Refactor: Implement Arara OARMP architecture and dynamic editors
This commit is contained in:
21
.gitignore
vendored
Normal file
21
.gitignore
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Python-generated files
|
||||||
|
__pycache__/
|
||||||
|
*.py[oc]
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
wheels/
|
||||||
|
*.egg-info
|
||||||
|
|
||||||
|
# Virtual environments
|
||||||
|
.venv
|
||||||
|
|
||||||
|
# Outputs and Databases
|
||||||
|
outputs/schedules/*.db
|
||||||
|
outputs/schedules/*.csv
|
||||||
|
outputs/schedules/*.txt
|
||||||
|
outputs/exports/
|
||||||
|
|
||||||
|
# Old local databases (just in case)
|
||||||
|
demands.db
|
||||||
|
optimized_cost.txt
|
||||||
|
resultado_otimizacao_alocacoes*.csv
|
||||||
1
.python-version
Normal file
1
.python-version
Normal file
@@ -0,0 +1 @@
|
|||||||
|
3.12
|
||||||
50
APP.md
Normal file
50
APP.md
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
Você é um especialista em UI/UX usando Streamlit.
|
||||||
|
|
||||||
|
[OBJETIVO]
|
||||||
|
|
||||||
|
- Construir uma interface gráfica para o arquivo main.py.
|
||||||
|
|
||||||
|
[REGRAS]
|
||||||
|
|
||||||
|
- A interface deve ser clean, moderna e intuitiva.
|
||||||
|
- Não crie gráficos que não sejam úteis.
|
||||||
|
|
||||||
|
[WORKSPACE]
|
||||||
|
|
||||||
|
- Você está em um ambiente Linux;
|
||||||
|
- O shell é fish;
|
||||||
|
- Coloque 'rtk' antes de todos os comandos;
|
||||||
|
- O ambiente venv foi criado usando 'uv';
|
||||||
|
- Rode scripts python com 'uv run ...';
|
||||||
|
- Adicione bibliotecas com 'uv add ...';
|
||||||
|
|
||||||
|
[PROJETO]
|
||||||
|
|
||||||
|
- Faça a interface toda em inglês;
|
||||||
|
- Crie uma aba chamada 'Data' com uma tabela do csv após filtragem e tratamento das variáveis;
|
||||||
|
- Crie uma aba chamada 'Fleet' com a tabela df_frota;
|
||||||
|
- Crie uma aba chamada 'Demand' com a tabela tabela_pax;
|
||||||
|
- Crie uma aba chamada 'Solver' com sliders para os parâmetros do problema:
|
||||||
|
- Frota de aeronaves;
|
||||||
|
- Período de operação;
|
||||||
|
- Local de origem;
|
||||||
|
- Local de destino;
|
||||||
|
- Número de aeronaves de cada tipo;
|
||||||
|
- Número de dias;
|
||||||
|
- Número de voos;
|
||||||
|
- Número de passageiros;
|
||||||
|
- Número de tripulantes;
|
||||||
|
- Número de bagagens;
|
||||||
|
- Número de aeronaves de cada tipo;
|
||||||
|
- Dentro da aba Solver coloque também, antes dos slides, o problema em 'matematiques' usando latex;
|
||||||
|
- No final da aba Solver, coloque um botão para resolver e uma caixa de texto com a saída do solver;
|
||||||
|
- Crie uma aba chamada 'Mapa' com um mapa da localização dos aeroportos na solução, com um slider por dia do ano;
|
||||||
|
- Crie uma aba chamada 'Resultados' com os resultados do solver, em tabelas. Coloque também o resultado não otimizado;
|
||||||
|
- Eu preciso saber também a quantiade de pernoites de uma aeronave em cada aeroporto.
|
||||||
|
- Desenhe a rota, ao selecionar a rota, um pop-up deve aparecer com informações sobre a rota (incluindo a aeronave e quantidade de pax e dias fora de sede);
|
||||||
|
- Mude a cor da rota caso seja uma rota de algum dia fora de sede.
|
||||||
|
- Crie um novo arquivo para este projeto, chamado main_app.py
|
||||||
|
- Utilize somente o Modelo VII
|
||||||
|
- Deixe o código bem documento usando doxygen
|
||||||
|
- Programe como um programado Senior usando Lean Code
|
||||||
|
- Antes de prosseguir, me mostre uma comparação para este projeto: Streamlit ou Shiny e eu decidirei qual o melhor.
|
||||||
BIN
Airline Operations and Scheduling.pdf
Executable file
BIN
Airline Operations and Scheduling.pdf
Executable file
Binary file not shown.
89
README.md
Normal file
89
README.md
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
# Fleet Assignment Optimization - Força Aérea Brasileira
|
||||||
|
|
||||||
|
## Integrantes do Grupo
|
||||||
|
- 1T Lago
|
||||||
|
- 1T Figueiredo
|
||||||
|
- 1T Fialho
|
||||||
|
|
||||||
|
## Sobre o Projeto
|
||||||
|
O presente trabalho aborda o problema clássico de **Fleet Assignment** (Alocação de Frota) aplicado ao contexto do transporte logístico aéreo militar.
|
||||||
|
|
||||||
|
O sistema foi desenvolvido como uma aplicação interativa (Dashboard Web) acoplada a um modelo matemático avançado. O objetivo é designar de forma ótima os diferentes modelos de aeronaves de transporte (C-97, C-95M, C-105, KC-390, KC-30, C-99A, C-98 e C-98A) de seus respectivos Esquadrões para atender à matriz de passageiros solicitada.
|
||||||
|
|
||||||
|
A arquitetura equilibra a maximização do atendimento de passageiros com a **minimização dos custos logísticos** (consumo de combustível em litros e penalidades de pernoite em bases externas), tudo isso balizado por limites de alcance, velocidades, tamanho físico das frotas disponíveis nas bases (Emissores) e capacidade de passageiros de cada aeronave.
|
||||||
|
|
||||||
|
### O Modelo Matemático
|
||||||
|
O núcleo de otimização foi construído utilizando Programação Linear Inteira Mista (MILP) processada pelo solver **SCIP** (implementado com *Google OR-Tools*). A modelagem contempla:
|
||||||
|
|
||||||
|
- **Função Objetivo:** $\min \sum_{t} \sum_{r} (c_{r} \cdot x_{r,t}) + \sum_{t} \sum_{d} (M \cdot s_{d,t})$
|
||||||
|
O algoritmo minimiza o custo total de combustível das missões ($c_r$), somado à grande penalidade ($M$) associada às variáveis de folga ($s_{d,t}$), forçando a malha a alocar missões para não deixar passageiros para trás, sempre que exequível.
|
||||||
|
- **Restrições Principais:**
|
||||||
|
- **Atendimento de Demanda:** $\sum (\text{cap}_{m} \cdot x) + s \ge \text{PAX}$
|
||||||
|
- **Bloqueio Temporal de Frota:** Se uma aeronave realizar uma missão que exige pernoite fora de sua base, o modelo garante o "bloqueio" desse ativo nos dias subsequentes da janela temporal ($T$), impossibilitando a clonagem da aeronave.
|
||||||
|
- **Limites de Estoque:** As decolagens originadas de uma localidade jamais podem exceder a propriedade física do $\text{MaxFleet}$ distribuída para o esquadrão emissor.
|
||||||
|
|
||||||
|
### Resultados Obtidos
|
||||||
|
A ferramenta é capaz de rodar a otimização global e extrair métricas gerenciais comparativas:
|
||||||
|
- **Baseline Fuel (Não-Otimizado):** O sistema isola qual seria o consumo nominal caso as demandas fossem atendidas de modo bruto.
|
||||||
|
- **Optimized Fuel Consumption:** Retorna o custo de combustível estrito gerado pelo motor SCIP.
|
||||||
|
- **Total Savings:** Revela à chefia o percentual quantitativo de economia gerada pela roteirização matemática contra o plano base.
|
||||||
|
- **Visão Tática:** A malha de voos diária pode ser "escrutinada" visualmente por meio de um Mapa Interativo renderizado sobre CartoDB / OpenStreetMap, evidenciando as decisões de despacho por código ICAO.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📂 Arquitetura do Projeto (Arara OARMP)
|
||||||
|
O projeto foi estruturado utilizando padrões modernos de software:
|
||||||
|
```text
|
||||||
|
/
|
||||||
|
├── app/
|
||||||
|
│ └── dashboard.py # Interface Streamlit Interativa
|
||||||
|
├── raw/ # Dados brutos fixos e mapas geo-referenciados
|
||||||
|
├── src/
|
||||||
|
│ └── fleet_assignment/ # Cérebro Matemático
|
||||||
|
│ ├── config.py # Constantes Globais
|
||||||
|
│ ├── ingest.py # Leitura, tratamento e merge
|
||||||
|
│ └── optimizer.py # Motor MILP (SCIP / OR-Tools)
|
||||||
|
├── outputs/ # Banco de dados temporário e CSVs finais
|
||||||
|
├── README.md
|
||||||
|
├── pyproject.toml
|
||||||
|
└── uv.lock
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠️ Guia de Instalação e Execução
|
||||||
|
|
||||||
|
### 1. Instalar o Python (3.12+)
|
||||||
|
Abra seu terminal/prompt e utilize o gerenciador de pacotes nativo do seu Sistema Operacional:
|
||||||
|
|
||||||
|
* **Windows (Winget):** `winget install Python.Python.3.12`
|
||||||
|
* **Ubuntu/Debian (APT):** `sudo apt update && sudo apt install python3 python3-pip python3-venv`
|
||||||
|
* **Fedora (DNF):** `sudo dnf install python3`
|
||||||
|
* **Arch Linux (Pacman):** `sudo pacman -S python`
|
||||||
|
* **macOS (Homebrew):** `brew install python`
|
||||||
|
|
||||||
|
### 2. Instalar o Gerenciador `uv`
|
||||||
|
O projeto adota o `uv` (gerenciador de ambiente e dependências ultrarrápido em Rust):
|
||||||
|
|
||||||
|
* **macOS / Linux:**
|
||||||
|
```bash
|
||||||
|
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||||
|
```
|
||||||
|
* **Windows (PowerShell):**
|
||||||
|
```powershell
|
||||||
|
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Configurar Ambiente e Executar
|
||||||
|
Abra o terminal na pasta raiz deste projeto (onde este `README.md` e o arquivo `pyproject.toml` se encontram) e siga os passos abaixo:
|
||||||
|
|
||||||
|
1. **Sincronizar Dependências (Instalar tudo e criar a VENV automaticamente):**
|
||||||
|
```bash
|
||||||
|
rtk uv sync
|
||||||
|
```
|
||||||
|
2. **Ligar o Servidor Web e a Interface:**
|
||||||
|
```bash
|
||||||
|
rtk uv run streamlit run app/dashboard.py
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Acesso:** Assim que o servidor subir, o Python acionará automaticamente a abertura de uma nova guia no seu **navegador web padrão** acessando o painel de operações (normalmente via `http://localhost:8501`).
|
||||||
382
app/dashboard.py
Normal file
382
app/dashboard.py
Normal file
@@ -0,0 +1,382 @@
|
|||||||
|
"""
|
||||||
|
Streamlit Dashboard for Brazilian Air Force Fleet Assignment.
|
||||||
|
Provides interactive mapping, scenario generation, and SCIP solver integration.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import sqlite3
|
||||||
|
import subprocess
|
||||||
|
import datetime
|
||||||
|
import pandas as pd
|
||||||
|
import pydeck as pdk
|
||||||
|
import streamlit as st
|
||||||
|
from vincenty import vincenty
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# PAGE CONFIGURATION
|
||||||
|
# ==========================================
|
||||||
|
st.set_page_config(
|
||||||
|
page_title="Fleet Assignment",
|
||||||
|
page_icon="✈️",
|
||||||
|
layout="wide",
|
||||||
|
initial_sidebar_state="expanded"
|
||||||
|
)
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# CONSTANTS & CONFIGURATION
|
||||||
|
# ==========================================
|
||||||
|
import sys
|
||||||
|
# Ensure we can import from src
|
||||||
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
|
|
||||||
|
from src.fleet_assignment.config import (
|
||||||
|
CSV_FILEPATH, JSON_AEROPORTOS, JSON_EMISSORES, DB_PATH,
|
||||||
|
RESULTS_FILE, COST_FILE, AIRCRAFT_CONFIG
|
||||||
|
)
|
||||||
|
|
||||||
|
from src.fleet_assignment.ingest import load_data
|
||||||
|
|
||||||
|
@st.cache_data
|
||||||
|
def get_cached_data():
|
||||||
|
return load_data()
|
||||||
|
|
||||||
|
demands_raw, df_fleet, valid_icaos, airports_geo = get_cached_data()
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# DATABASE MANAGEMENT
|
||||||
|
# ==========================================
|
||||||
|
def execute_sql(query, params=(), fetch=False):
|
||||||
|
"""Helper to execute SQL commands cleanly."""
|
||||||
|
with sqlite3.connect(DB_PATH) as conn:
|
||||||
|
if fetch:
|
||||||
|
return pd.read_sql_query(query, conn, params=params)
|
||||||
|
conn.execute(query, params)
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
def init_db(demands_df, frota_df, force_reset=False):
|
||||||
|
"""Initializes SQLite Database as the single source of truth."""
|
||||||
|
if force_reset and os.path.exists(DB_PATH):
|
||||||
|
os.remove(DB_PATH)
|
||||||
|
|
||||||
|
with sqlite3.connect(DB_PATH) as conn:
|
||||||
|
conn.execute('''
|
||||||
|
CREATE TABLE IF NOT EXISTS demandas (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
data_apenas TEXT,
|
||||||
|
local_dec TEXT,
|
||||||
|
local_pou TEXT,
|
||||||
|
pax INTEGER
|
||||||
|
)
|
||||||
|
''')
|
||||||
|
|
||||||
|
count = conn.execute("SELECT COUNT(*) FROM demandas").fetchone()[0]
|
||||||
|
if count == 0:
|
||||||
|
df_insert = demands_df[['Data Apenas', 'Localidade Decolagem', 'Localidade Pouso', 'PAX']].copy()
|
||||||
|
df_insert.columns = ['data_apenas', 'local_dec', 'local_pou', 'pax']
|
||||||
|
df_insert.to_sql('demandas', conn, if_exists='append', index=False)
|
||||||
|
frota_df.to_sql('frota', conn, if_exists='replace', index=False)
|
||||||
|
|
||||||
|
def load_demands():
|
||||||
|
return execute_sql("SELECT id as ID, data_apenas as 'Date', local_dec as 'Dep', local_pou as 'Arr', pax as 'PAX' FROM demandas", fetch=True)
|
||||||
|
|
||||||
|
init_db(demands_raw, df_fleet)
|
||||||
|
|
||||||
|
@st.cache_data
|
||||||
|
def load_results():
|
||||||
|
try:
|
||||||
|
return pd.read_csv(RESULTS_FILE, sep=';')
|
||||||
|
except FileNotFoundError:
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
df_results = load_results()
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# SOLVER INTEGRATION
|
||||||
|
# ==========================================
|
||||||
|
def run_solver_subprocess(time_limit_sec, output_placeholder):
|
||||||
|
"""Spawns the optimization worker and streams logs to the UI."""
|
||||||
|
process = subprocess.Popen(
|
||||||
|
["uv", "run", "python", "-u", "solver_worker.py", str(time_limit_sec)],
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.STDOUT,
|
||||||
|
text=True,
|
||||||
|
bufsize=1
|
||||||
|
)
|
||||||
|
|
||||||
|
full_log = ""
|
||||||
|
for line in iter(process.stdout.readline, ''):
|
||||||
|
full_log += line
|
||||||
|
output_placeholder.code(full_log, language='text')
|
||||||
|
|
||||||
|
process.wait()
|
||||||
|
return process.returncode == 0
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# UI RENDER
|
||||||
|
# ==========================================
|
||||||
|
st.title("✈️ Fleet Assignment")
|
||||||
|
st.markdown("Brazilian Air Force Fleet Routing and Scheduling (Global Time-Space Network Flow)")
|
||||||
|
|
||||||
|
tab1, tab2, tab3, tab4, tab5 = st.tabs(["Demand Data", "Fleet", "Solver", "Map", "Results"])
|
||||||
|
|
||||||
|
# --- TAB 1: DEMAND DATA ---
|
||||||
|
with tab1:
|
||||||
|
col_title, col_reset = st.columns([0.8, 0.2])
|
||||||
|
with col_title:
|
||||||
|
st.header("Passenger Demands")
|
||||||
|
with col_reset:
|
||||||
|
if st.button("🔄 Reset DB to Raw CSV", type="secondary", use_container_width=True):
|
||||||
|
init_db(demands_raw, df_fleet, force_reset=True)
|
||||||
|
st.success("Database Reset!")
|
||||||
|
st.rerun()
|
||||||
|
|
||||||
|
df_display_demand = load_demands()
|
||||||
|
|
||||||
|
st.info("💡 You can edit, add, or delete rows directly in the table below. Click 'Save Changes' when done.")
|
||||||
|
edited_demand = st.data_editor(
|
||||||
|
df_display_demand,
|
||||||
|
num_rows="dynamic",
|
||||||
|
use_container_width=True,
|
||||||
|
hide_index=True,
|
||||||
|
key="demand_editor"
|
||||||
|
)
|
||||||
|
|
||||||
|
if st.button("💾 Save Demand Changes", type="primary", use_container_width=True):
|
||||||
|
with sqlite3.connect(DB_PATH) as conn:
|
||||||
|
conn.execute("DROP TABLE IF EXISTS demandas")
|
||||||
|
conn.execute('''
|
||||||
|
CREATE TABLE demandas (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
data_apenas TEXT,
|
||||||
|
local_dec TEXT,
|
||||||
|
local_pou TEXT,
|
||||||
|
pax INTEGER
|
||||||
|
)
|
||||||
|
''')
|
||||||
|
df_to_save = edited_demand.drop(columns=['ID'], errors='ignore')
|
||||||
|
df_to_save.columns = ['data_apenas', 'local_dec', 'local_pou', 'pax']
|
||||||
|
df_to_save.to_sql('demandas', conn, if_exists='append', index=False)
|
||||||
|
st.success("Database synchronized successfully!")
|
||||||
|
st.rerun()
|
||||||
|
|
||||||
|
# --- TAB 2: FLEET ---
|
||||||
|
with tab2:
|
||||||
|
st.header("Fleet Specifications")
|
||||||
|
|
||||||
|
# Check if we have modified fleet in DB, otherwise use default
|
||||||
|
with sqlite3.connect(DB_PATH) as conn:
|
||||||
|
try:
|
||||||
|
current_fleet = pd.read_sql_query("SELECT * FROM frota", conn)
|
||||||
|
except Exception:
|
||||||
|
current_fleet = df_fleet.copy()
|
||||||
|
|
||||||
|
df_display_fleet = current_fleet[['Modelo', 'Emissor', 'Tamanho da Frota', 'Consumo (km/l)', 'Velocidade Média (km/h)', 'Capacidade', 'Alcance']].copy()
|
||||||
|
df_display_fleet.columns = ['Modelo', 'Squadron', 'Fleet Size', 'Fuel Usage (km/l)', 'Mean Speed (km/h)', 'PAX Capacity', 'Max Range (km)']
|
||||||
|
|
||||||
|
st.info("💡 Edit specs directly below to simulate larger fleets, different fuel burn, or cargo capacity.")
|
||||||
|
edited_fleet = st.data_editor(
|
||||||
|
df_display_fleet,
|
||||||
|
use_container_width=True,
|
||||||
|
hide_index=True,
|
||||||
|
key="fleet_editor"
|
||||||
|
)
|
||||||
|
|
||||||
|
if st.button("💾 Save Fleet Changes", type="primary", use_container_width=True):
|
||||||
|
rename_back = {
|
||||||
|
'Modelo': 'Modelo', 'Squadron': 'Emissor', 'Fleet Size': 'Tamanho da Frota',
|
||||||
|
'Fuel Usage (km/l)': 'Consumo (km/l)', 'Mean Speed (km/h)': 'Velocidade Média (km/h)',
|
||||||
|
'PAX Capacity': 'Capacidade', 'Max Range (km)': 'Alcance'
|
||||||
|
}
|
||||||
|
df_save_fleet = edited_fleet.rename(columns=rename_back)
|
||||||
|
|
||||||
|
with sqlite3.connect(DB_PATH) as conn:
|
||||||
|
old_frota = pd.read_sql_query("SELECT * FROM frota", conn)
|
||||||
|
for idx, row in df_save_fleet.iterrows():
|
||||||
|
mask = (old_frota['Modelo'] == row['Modelo']) & (old_frota['Emissor'] == row['Emissor'])
|
||||||
|
old_frota.loc[mask, 'Tamanho da Frota'] = row['Tamanho da Frota']
|
||||||
|
old_frota.loc[mask, 'Consumo (km/l)'] = row['Consumo (km/l)']
|
||||||
|
old_frota.loc[mask, 'Velocidade Média (km/h)'] = row['Velocidade Média (km/h)']
|
||||||
|
old_frota.loc[mask, 'Capacidade'] = row['Capacidade']
|
||||||
|
old_frota.loc[mask, 'Alcance'] = row['Alcance']
|
||||||
|
old_frota.to_sql('frota', conn, if_exists='replace', index=False)
|
||||||
|
|
||||||
|
st.success("Fleet changes saved successfully!")
|
||||||
|
st.rerun()
|
||||||
|
|
||||||
|
# --- TAB 3: SOLVER ---
|
||||||
|
with tab3:
|
||||||
|
st.header("Mathematical Formulation")
|
||||||
|
st.latex(r"\min \sum_{t} \sum_{r} (c_{r} \cdot x_{r,t}) + \sum_{t} \sum_{d} (M \cdot s_{d,t})")
|
||||||
|
st.latex(r"\text{s.t.} \quad \sum_{m,e} (\text{cap}_{m} \cdot x_{m,e,r,t}) + s_{r,t} \ge \text{PAX}_{r,t} \quad \forall r, t")
|
||||||
|
st.latex(r"\sum_{t_{start} \le T \le t_{start} + \text{pernoites}} x_{m,e,r,t_{start}} \le \text{MaxFleet}_{m,e} \quad \forall m, e, T")
|
||||||
|
|
||||||
|
st.markdown(r"""
|
||||||
|
**Dictionary of Variables:**
|
||||||
|
- $x_{m,e,r,t}$: Decision Variable (Integer). Number of aircraft of model $m$, from squadron $e$, allocated to route $r$ on day $t$.
|
||||||
|
- $c_r$: Estimated total fuel cost for the route $r$ mission, including overnight stay penalties if applicable.
|
||||||
|
- $s_{r,t}$: Slack Variable. Represents the passenger demand that could **not** be met on that day due to fleet limitations.
|
||||||
|
- $M$: High Penalty (Big M). Imposed on the system for each unit of slack activated, forcing the solver to meet demand whenever possible.
|
||||||
|
- $\text{cap}_m$: Maximum passenger capacity (seats) of aircraft $m$.
|
||||||
|
- $\text{PAX}_{r,t}$: Actual number of Air Force passengers needing to fly on route $r$ on day $t$.
|
||||||
|
- $\text{MaxFleet}_{m,e}$: Total physical aircraft available in squadron $e$ for model $m$.
|
||||||
|
- $T$: Temporal inspection window. Ensures aircraft blockade during overnight stays, preventing fleet duplication.
|
||||||
|
""")
|
||||||
|
|
||||||
|
if st.button("🚀 Run Global Optimization", type="primary"):
|
||||||
|
st.info("Starting Worker... Follow the real-time SCIP log below:")
|
||||||
|
log_placeholder = st.empty()
|
||||||
|
|
||||||
|
if run_solver_subprocess(300, log_placeholder):
|
||||||
|
st.success("Solver Finished! Results saved to CSV.")
|
||||||
|
st.session_state['new_results'] = True
|
||||||
|
else:
|
||||||
|
st.error("Solver Failed or was aborted.")
|
||||||
|
|
||||||
|
# --- TAB 4: MAP ---
|
||||||
|
with tab4:
|
||||||
|
st.header("Interactive Flight Map")
|
||||||
|
|
||||||
|
if st.session_state.get('new_results'):
|
||||||
|
df_results = load_results()
|
||||||
|
|
||||||
|
view_state = pdk.ViewState(latitude=-15.78, longitude=-47.92, zoom=3.5, pitch=45)
|
||||||
|
layers = []
|
||||||
|
|
||||||
|
if df_results.empty:
|
||||||
|
st.info("No optimization results yet. Run the Global Optimization to see routes.")
|
||||||
|
else:
|
||||||
|
df_results['Data'] = pd.to_datetime(df_results['Data'])
|
||||||
|
dias_disponiveis = sorted(df_results['Data'].dt.date.unique())
|
||||||
|
|
||||||
|
# Safe initialization of map date
|
||||||
|
if 'current_map_date' not in st.session_state or st.session_state.current_map_date not in dias_disponiveis:
|
||||||
|
st.session_state.current_map_date = dias_disponiveis[0]
|
||||||
|
|
||||||
|
current_idx = dias_disponiveis.index(st.session_state.current_map_date)
|
||||||
|
|
||||||
|
# Navigation Controls
|
||||||
|
col_prev, col_drop, col_next = st.columns([1, 8, 1])
|
||||||
|
with col_prev:
|
||||||
|
st.markdown("<br/>", unsafe_allow_html=True)
|
||||||
|
if st.button("⬅️", disabled=current_idx==0, use_container_width=True):
|
||||||
|
st.session_state.current_map_date = dias_disponiveis[current_idx - 1]
|
||||||
|
st.rerun()
|
||||||
|
with col_drop:
|
||||||
|
selected_date = st.date_input("Select via Calendar", value=st.session_state.current_map_date)
|
||||||
|
if selected_date != st.session_state.current_map_date:
|
||||||
|
st.session_state.current_map_date = selected_date
|
||||||
|
st.rerun()
|
||||||
|
with col_next:
|
||||||
|
st.markdown("<br/>", unsafe_allow_html=True)
|
||||||
|
if st.button("➡️", disabled=current_idx>=len(dias_disponiveis)-1, use_container_width=True):
|
||||||
|
st.session_state.current_map_date = dias_disponiveis[current_idx + 1]
|
||||||
|
st.rerun()
|
||||||
|
|
||||||
|
slider_date = st.select_slider("Or scrub through scheduled flight days", options=dias_disponiveis, value=st.session_state.current_map_date)
|
||||||
|
if slider_date != st.session_state.current_map_date:
|
||||||
|
st.session_state.current_map_date = slider_date
|
||||||
|
st.rerun()
|
||||||
|
|
||||||
|
df_day = df_results[df_results['Data'].dt.date == st.session_state.current_map_date]
|
||||||
|
df_demands_map = load_demands()
|
||||||
|
|
||||||
|
# Map Data Parsing
|
||||||
|
map_data = []
|
||||||
|
for _, row in df_day.iterrows():
|
||||||
|
orig, dest = row['Local Decolagem'], row['Local Pouso']
|
||||||
|
|
||||||
|
if orig in airports_geo and dest in airports_geo:
|
||||||
|
lon1, lat1 = float(airports_geo[orig]['lon']), float(airports_geo[orig]['lat'])
|
||||||
|
lon2, lat2 = float(airports_geo[dest]['lon']), float(airports_geo[dest]['lat'])
|
||||||
|
|
||||||
|
pernoites = row.get('Pernoites', 0)
|
||||||
|
color = [255, 65, 54, 200] if pernoites > 0 else [0, 116, 217, 200]
|
||||||
|
|
||||||
|
# Calculate PAX sum for this route on this day
|
||||||
|
pax_mask = (df_demands_map['Dep'] == orig) & (df_demands_map['Arr'] == dest) & (df_demands_map['Date'] == str(st.session_state.current_map_date))
|
||||||
|
pax_count = df_demands_map[pax_mask]['PAX'].sum()
|
||||||
|
|
||||||
|
map_data.append({
|
||||||
|
"start": [lon1, lat1], "end": [lon2, lat2], "color": color,
|
||||||
|
"modelo": row['Modelo'], "orig": orig, "dest": dest,
|
||||||
|
"pax": int(pax_count), "pernoites": pernoites
|
||||||
|
})
|
||||||
|
|
||||||
|
df_map = pd.DataFrame(map_data)
|
||||||
|
if df_map.empty:
|
||||||
|
st.info("No flights scheduled for this day.")
|
||||||
|
else:
|
||||||
|
layers.append(pdk.Layer(
|
||||||
|
"ArcLayer", data=df_map,
|
||||||
|
get_source_position="start", get_target_position="end",
|
||||||
|
get_source_color="color", get_target_color="color",
|
||||||
|
get_width=3, pickable=True
|
||||||
|
))
|
||||||
|
|
||||||
|
st.pydeck_chart(pdk.Deck(
|
||||||
|
layers=layers,
|
||||||
|
initial_view_state=view_state,
|
||||||
|
tooltip={
|
||||||
|
"html": "<b>✈️ Aircraft:</b> {modelo}<br/><b>📍 Route:</b> {orig} ➔ {dest}<br/><b>👥 PAX:</b> {pax}<br/><b>🌙 Out of Base:</b> {pernoites} days",
|
||||||
|
"style": {"backgroundColor": "steelblue", "color": "white"}
|
||||||
|
} if layers else None,
|
||||||
|
map_style='road'
|
||||||
|
))
|
||||||
|
|
||||||
|
# Selected Day Results Table
|
||||||
|
if not df_results.empty:
|
||||||
|
df_day_display = df_day.copy()
|
||||||
|
|
||||||
|
# Bind PAX back into the table
|
||||||
|
df_day_display['PAX'] = df_day_display.apply(lambda r: df_demands_map[
|
||||||
|
(df_demands_map['Dep'] == r['Local Decolagem']) &
|
||||||
|
(df_demands_map['Arr'] == r['Local Pouso']) &
|
||||||
|
(df_demands_map['Date'] == str(st.session_state.current_map_date))
|
||||||
|
]['PAX'].sum(), axis=1)
|
||||||
|
|
||||||
|
df_day_display.rename(columns={
|
||||||
|
'Data': 'Date', 'Modelo': 'Model', 'Emissor': 'Squadron',
|
||||||
|
'Local Decolagem': 'Departure', 'Local Pouso': 'Arrival',
|
||||||
|
'Qtd Aeronaves': 'Allocated Fleet', 'Pernoites': 'Days Out of Base'
|
||||||
|
}, inplace=True)
|
||||||
|
|
||||||
|
st.subheader(f"Flight Schedule for {st.session_state.current_map_date}")
|
||||||
|
st.dataframe(df_day_display, use_container_width=True)
|
||||||
|
|
||||||
|
# --- TAB 5: RESULTS ---
|
||||||
|
with tab5:
|
||||||
|
st.header("Optimization Results")
|
||||||
|
|
||||||
|
try:
|
||||||
|
raw_fuel_df = execute_sql("SELECT SUM(\"Combustível\") as total FROM frota", fetch=True)
|
||||||
|
raw_fuel = raw_fuel_df['total'].iloc[0] if not raw_fuel_df.empty else 0
|
||||||
|
if pd.isna(raw_fuel): raw_fuel = 0
|
||||||
|
|
||||||
|
opt_fuel = None
|
||||||
|
if os.path.exists(COST_FILE):
|
||||||
|
with open(COST_FILE, "r") as f:
|
||||||
|
opt_fuel = float(f.read().strip())
|
||||||
|
|
||||||
|
colA, colB, colC = st.columns(3)
|
||||||
|
with colA:
|
||||||
|
st.metric(label="Baseline Fuel (Non-Optimized)", value=f"{raw_fuel:,.2f} L")
|
||||||
|
with colB:
|
||||||
|
if opt_fuel is not None:
|
||||||
|
st.metric(label="Optimized Fuel Consumption", value=f"{opt_fuel:,.2f} L", delta=f"{opt_fuel - raw_fuel:,.2f} L", delta_color="inverse")
|
||||||
|
with colC:
|
||||||
|
if opt_fuel is not None and raw_fuel > 0:
|
||||||
|
savings = (1 - (opt_fuel / raw_fuel)) * 100
|
||||||
|
st.metric(label="Total Fuel Savings", value=f"{savings:.2f}%")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if not df_results.empty:
|
||||||
|
st.dataframe(df_results, use_container_width=True)
|
||||||
|
|
||||||
|
if 'Pernoites' in df_results.columns:
|
||||||
|
st.subheader("Days Out of Base (Pernoites) Breakdown")
|
||||||
|
df_pernoites = df_results[df_results['Pernoites'] > 0]
|
||||||
|
st.dataframe(df_pernoites[['Modelo', 'Local Decolagem', 'Local Pouso', 'Pernoites']].sort_values(by='Pernoites', ascending=False))
|
||||||
|
else:
|
||||||
|
st.warning("No results available.")
|
||||||
1120
create_nb.py
1120
create_nb.py
File diff suppressed because it is too large
Load Diff
2450
modelos.ipynb
2450
modelos.ipynb
File diff suppressed because one or more lines are too long
@@ -13,6 +13,7 @@ dependencies = [
|
|||||||
"pulp>=3.3.2",
|
"pulp>=3.3.2",
|
||||||
"pymap3d>=3.2.0",
|
"pymap3d>=3.2.0",
|
||||||
"seaborn>=0.13.2",
|
"seaborn>=0.13.2",
|
||||||
|
"streamlit>=1.58.0",
|
||||||
"tabulate>=0.10.0",
|
"tabulate>=0.10.0",
|
||||||
"vincenty>=0.1.4",
|
"vincenty>=0.1.4",
|
||||||
]
|
]
|
||||||
|
|||||||
12568
raw/SISCO_AEREA_01-01-2025_A_31-12-2025_1911251714Z.csv
Normal file
12568
raw/SISCO_AEREA_01-01-2025_A_31-12-2025_1911251714Z.csv
Normal file
File diff suppressed because it is too large
Load Diff
351662
raw/airports.json
Normal file
351662
raw/airports.json
Normal file
File diff suppressed because it is too large
Load Diff
46
raw/emissores.json
Normal file
46
raw/emissores.json
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"1GAV8": "SBNT",
|
||||||
|
"2/2 GT": "SBGL",
|
||||||
|
"BABV": "SBBV",
|
||||||
|
"CINDACTA I": "SBBS",
|
||||||
|
"ETA7": "SBMN",
|
||||||
|
"1 GTT": "BAAN",
|
||||||
|
"3GAV8": "SBSC",
|
||||||
|
"1GAV3": "SBBV",
|
||||||
|
"1GAV12": "SBSM",
|
||||||
|
"PAMA LS": "SBLS",
|
||||||
|
"ETA3": "SBGL",
|
||||||
|
"ETA1": "SBBE",
|
||||||
|
"2GAV3": "SBPV",
|
||||||
|
"1 GAVCA": "SBSC",
|
||||||
|
"1GAV9": "SBMN",
|
||||||
|
"ETA5": "SBCO",
|
||||||
|
"1/1 GT": "SBGL",
|
||||||
|
"2GAV6": "SBAN",
|
||||||
|
"CINDACTA IV": "SBMN",
|
||||||
|
"1 GDA": "SBAN",
|
||||||
|
"EPCAR": "SBBQ",
|
||||||
|
"1GAV14": "SBCO",
|
||||||
|
"1GAV15": "SBCG",
|
||||||
|
"BASM": "SBSM",
|
||||||
|
"BACG": "SBCG",
|
||||||
|
"EEAR": "SBGW",
|
||||||
|
"3GAV7": "SBBE",
|
||||||
|
"PAMA SP": "SBMT",
|
||||||
|
"ETA2": "SBNT",
|
||||||
|
"1/2 GT": "SBGL",
|
||||||
|
"3GAV3": "SBCG",
|
||||||
|
"5GAV8": "SBSM",
|
||||||
|
"ETA6": "SBBR",
|
||||||
|
"1GAV7": "SBSC",
|
||||||
|
"CINDACTA II": "SBBI",
|
||||||
|
"BAPV": "SBPV",
|
||||||
|
"7GAV8": "SBMN",
|
||||||
|
"1GAV10": "SBSM",
|
||||||
|
"2GAV5": "SBNT",
|
||||||
|
"2GAV10": "SBCG",
|
||||||
|
"2GAV7": "SBCO",
|
||||||
|
"CINDACTA III": "SBRF"
|
||||||
|
}
|
||||||
|
]
|
||||||
26
src/fleet_assignment/config.py
Normal file
26
src/fleet_assignment/config.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
# Project Roots
|
||||||
|
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
|
RAW_DIR = os.path.join(ROOT_DIR, 'raw')
|
||||||
|
OUTPUTS_DIR = os.path.join(ROOT_DIR, 'outputs')
|
||||||
|
SCHEDULES_DIR = os.path.join(OUTPUTS_DIR, 'schedules')
|
||||||
|
|
||||||
|
# File Paths
|
||||||
|
CSV_FILEPATH = os.path.join(RAW_DIR, "SISCO_AEREA_01-01-2025_A_31-12-2025_1911251714Z.csv")
|
||||||
|
JSON_AEROPORTOS = os.path.join(RAW_DIR, "airports.json")
|
||||||
|
JSON_EMISSORES = os.path.join(RAW_DIR, "emissores.json")
|
||||||
|
DB_PATH = os.path.join(SCHEDULES_DIR, "demands.db")
|
||||||
|
RESULTS_FILE = os.path.join(SCHEDULES_DIR, "resultado_otimizacao_alocacoes.csv")
|
||||||
|
COST_FILE = os.path.join(SCHEDULES_DIR, "optimized_cost.txt")
|
||||||
|
|
||||||
|
AIRCRAFT_CONFIG = {
|
||||||
|
'C-97': {'cap': 30, 'range': 1600, 'daily_fuel': 240},
|
||||||
|
'C-95M': {'cap': 12, 'range': 1900, 'daily_fuel': 180},
|
||||||
|
'C-105': {'cap': 73, 'range': 5000, 'daily_fuel': 180},
|
||||||
|
'KC-390':{'cap': 80, 'range': 6000, 'daily_fuel': 180},
|
||||||
|
'KC-30': {'cap': 238, 'range': 14500, 'daily_fuel': 600},
|
||||||
|
'C-99A': {'cap': 50, 'range': 2200, 'daily_fuel': 180},
|
||||||
|
'C-98': {'cap': 10, 'range': 2400, 'daily_fuel': 180},
|
||||||
|
'C-98A': {'cap': 14, 'range': 2400, 'daily_fuel': 180}
|
||||||
|
}
|
||||||
77
src/fleet_assignment/ingest.py
Normal file
77
src/fleet_assignment/ingest.py
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import json
|
||||||
|
import pandas as pd
|
||||||
|
from vincenty import vincenty
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Ensure src module is visible if run standalone
|
||||||
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
|
||||||
|
|
||||||
|
from src.fleet_assignment.config import (
|
||||||
|
CSV_FILEPATH, JSON_AEROPORTOS, JSON_EMISSORES, AIRCRAFT_CONFIG
|
||||||
|
)
|
||||||
|
|
||||||
|
def load_data():
|
||||||
|
"""Reads raw CSV and JSON to build the baseline demand and fleet dataframes."""
|
||||||
|
df = pd.read_csv(CSV_FILEPATH, low_memory=False)
|
||||||
|
df_airports = pd.read_json(JSON_AEROPORTOS, orient='index')
|
||||||
|
|
||||||
|
# Basic Cleaning
|
||||||
|
df.replace('NIL', 0, inplace=True)
|
||||||
|
df = df[(df['Localidade Decolagem'] != 0) & (df['Localidade Pouso'] != 0)]
|
||||||
|
df = df[df['Modelo'].isin(AIRCRAFT_CONFIG.keys())]
|
||||||
|
|
||||||
|
df['PAX'] = pd.to_numeric(df['PAX']).fillna(0)
|
||||||
|
df['Dep TimeStamp'] = pd.to_datetime(df['Data de Decolagem'].astype(str) + ' ' + df['Hora de Decolagem'].astype(str), format='mixed', dayfirst=True, errors='coerce')
|
||||||
|
df['Data Apenas'] = df['Dep TimeStamp'].dt.date
|
||||||
|
df['Combustível'] = pd.to_numeric(df['Combustível'], errors='coerce').fillna(0)
|
||||||
|
|
||||||
|
# Merge Coordinates
|
||||||
|
df = df.merge(df_airports[['lat', 'lon']], left_on='Localidade Decolagem', right_index=True, how='left')
|
||||||
|
df.rename(columns={'lat': 'lat_dep', 'lon': 'lon_dep'}, inplace=True)
|
||||||
|
df = df.merge(df_airports[['lat', 'lon']], left_on='Localidade Pouso', right_index=True, how='left')
|
||||||
|
df.rename(columns={'lat': 'lat_arr', 'lon': 'lon_arr'}, inplace=True)
|
||||||
|
|
||||||
|
# Distance & Time Computations
|
||||||
|
def calc_dist(row):
|
||||||
|
if pd.isna(row['lat_dep']) or pd.isna(row['lat_arr']): return 0.0
|
||||||
|
return vincenty((row['lat_dep'], row['lon_dep']), (row['lat_arr'], row['lon_arr']))
|
||||||
|
|
||||||
|
df['Distancia'] = df.apply(calc_dist, axis=1)
|
||||||
|
df['Tempo de Voo'] = pd.to_timedelta(df['Tempo de Voo'].astype(str), errors='coerce')
|
||||||
|
df['Tempo de Voo (h)'] = df['Tempo de Voo'].dt.total_seconds() / 3600.0
|
||||||
|
|
||||||
|
# Build Fleet Specifications
|
||||||
|
df_fleet = df.groupby(['Modelo', 'Emissor']).agg({
|
||||||
|
'Combustível': 'sum',
|
||||||
|
'Distancia': 'sum',
|
||||||
|
'Tempo de Voo (h)': 'sum',
|
||||||
|
'Matrícula': 'nunique'
|
||||||
|
})
|
||||||
|
df_fleet.rename(columns={'Matrícula': 'Tamanho da Frota'}, inplace=True)
|
||||||
|
|
||||||
|
df_fleet['Consumo (km/l)'] = (df_fleet['Distancia'] / df_fleet['Combustível']).replace([float('inf'), -float('inf')], 0).fillna(0)
|
||||||
|
df_fleet['Velocidade Média (km/h)'] = (df_fleet['Distancia'] / df_fleet['Tempo de Voo (h)']).replace([float('inf'), -float('inf')], 0).fillna(0)
|
||||||
|
|
||||||
|
models = df_fleet.index.get_level_values('Modelo')
|
||||||
|
df_fleet['Capacidade'] = models.map(lambda m: AIRCRAFT_CONFIG[m]['cap'])
|
||||||
|
df_fleet['Alcance'] = models.map(lambda m: AIRCRAFT_CONFIG[m]['range'])
|
||||||
|
df_fleet['Diaria_Litros'] = models.map(lambda m: AIRCRAFT_CONFIG[m]['daily_fuel'])
|
||||||
|
|
||||||
|
# Build Demands
|
||||||
|
df_valid = df.dropna(subset=['Data Apenas']).copy()
|
||||||
|
df_valid = df_valid[(df_valid['Localidade Decolagem'] != '0') & (df_valid['Localidade Pouso'] != '0')]
|
||||||
|
demands_grouped = df_valid.groupby(['Data Apenas', 'Localidade Decolagem', 'Localidade Pouso'])['PAX'].sum().reset_index()
|
||||||
|
demands = demands_grouped[demands_grouped['PAX'] > 0].copy()
|
||||||
|
|
||||||
|
# Load External Lookups
|
||||||
|
with open(JSON_EMISSORES, 'r') as f:
|
||||||
|
emissores_data = json.load(f)[0]
|
||||||
|
|
||||||
|
with open(JSON_AEROPORTOS, 'r') as f:
|
||||||
|
airports_geo = json.load(f)
|
||||||
|
|
||||||
|
# Validation Lists
|
||||||
|
valid_icaos = df_airports.index.intersection(list(set(demands['Localidade Decolagem'].unique().tolist() + demands['Localidade Pouso'].unique().tolist() + list(emissores_data.values())))).tolist()
|
||||||
|
|
||||||
|
return demands, df_fleet.reset_index(), valid_icaos, airports_geo
|
||||||
192
src/fleet_assignment/optimizer.py
Normal file
192
src/fleet_assignment/optimizer.py
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
"""
|
||||||
|
Worker script to run the SCIP solver in a separate process.
|
||||||
|
This allows capturing the C++ stdout (EnableOutput) and streaming it back to Streamlit.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import pandas as pd
|
||||||
|
import math
|
||||||
|
import datetime
|
||||||
|
from ortools.linear_solver import pywraplp
|
||||||
|
import json
|
||||||
|
from vincenty import vincenty
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
|
# Ensure src module is visible if run standalone
|
||||||
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
|
||||||
|
|
||||||
|
from src.fleet_assignment.config import DB_PATH, RESULTS_FILE, COST_FILE
|
||||||
|
|
||||||
|
def run_solver(time_limit_sec=300):
|
||||||
|
print(f"--- Starting Global Solver Worker (Limit: {time_limit_sec}s) ---")
|
||||||
|
JSON_AEROPORTOS = "airports.json"
|
||||||
|
|
||||||
|
conn = sqlite3.connect(DB_PATH)
|
||||||
|
df_frota_db = pd.read_sql_query("SELECT * FROM frota", conn)
|
||||||
|
demands_db = pd.read_sql_query("SELECT data_apenas as 'Data Apenas', local_dec as 'Localidade Decolagem', local_pou as 'Localidade Pouso', pax as 'PAX' FROM demandas", conn)
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
df_aeroportos = pd.read_json(JSON_AEROPORTOS, orient='index')
|
||||||
|
|
||||||
|
# Format demands as required by downstream logic
|
||||||
|
pax_demanda_completa = demands_db.groupby(['Data Apenas', 'Localidade Decolagem', 'Localidade Pouso'])['PAX'].sum().reset_index()
|
||||||
|
demands = pax_demanda_completa[pax_demanda_completa['PAX'] > 0].copy()
|
||||||
|
|
||||||
|
with open('emissores.json', 'r') as f:
|
||||||
|
emissores_data = json.load(f)[0]
|
||||||
|
icaos_emissores = list(emissores_data.values())
|
||||||
|
|
||||||
|
icaos_dec = demands['Localidade Decolagem'].unique().tolist()
|
||||||
|
icaos_pou = demands['Localidade Pouso'].unique().tolist()
|
||||||
|
all_icaos = [icao for icao in list(set(icaos_dec + icaos_pou + icaos_emissores)) if str(icao).strip() not in ['0', '']]
|
||||||
|
|
||||||
|
coords = df_aeroportos.loc[df_aeroportos.index.intersection(all_icaos), ['lat', 'lon']]
|
||||||
|
valid_icaos = coords.index.tolist()
|
||||||
|
|
||||||
|
dist_matrix = pd.DataFrame(index=valid_icaos, columns=valid_icaos)
|
||||||
|
for i in valid_icaos:
|
||||||
|
for j in valid_icaos:
|
||||||
|
if i == j: dist_matrix.loc[i, j] = 0.0
|
||||||
|
else:
|
||||||
|
lat1, lon1 = coords.loc[i, 'lat'], coords.loc[i, 'lon']
|
||||||
|
lat2, lon2 = coords.loc[j, 'lat'], coords.loc[j, 'lon']
|
||||||
|
dist_matrix.loc[i, j] = round(vincenty((lat1, lon1), (lat2, lon2)), 2)
|
||||||
|
|
||||||
|
AERONAVES_INTERESSE = ['C-97', 'C-95M', 'C-105', 'KC-390', 'KC-30', 'C-99A', 'C-98', 'C-98A']
|
||||||
|
CAPACIDADES_AERONAVES_INTERESSE = [30, 12, 73, 80, 238, 50, 10, 14]
|
||||||
|
ALCANCE_AERONAVES_INTERESSE = [1600, 1900, 5000, 6000, 14500, 2200, 2400, 2400]
|
||||||
|
DIARIAS_AERONAVES_INTERESSE = [x * 60 for x in [4, 3, 3, 3, 10, 3, 3, 3]]
|
||||||
|
|
||||||
|
frotas = []
|
||||||
|
for idx, row in df_frota_db.iterrows():
|
||||||
|
modelo, emissor = row['Modelo'], row['Emissor']
|
||||||
|
consumo = row['Consumo (km/l)']
|
||||||
|
if consumo > 0 and modelo in AERONAVES_INTERESSE:
|
||||||
|
a_idx = AERONAVES_INTERESSE.index(modelo)
|
||||||
|
frotas.append({
|
||||||
|
'modelo': str(modelo),
|
||||||
|
'emissor': str(emissor),
|
||||||
|
'base': emissores_data.get(str(emissor), None),
|
||||||
|
'frota_max': int(row['Tamanho da Frota']),
|
||||||
|
'consumo_kml': float(consumo),
|
||||||
|
'capacidade': int(CAPACIDADES_AERONAVES_INTERESSE[a_idx]),
|
||||||
|
'alcance': float(ALCANCE_AERONAVES_INTERESSE[a_idx]),
|
||||||
|
'velocidade_media': float(row['Velocidade Média (km/h)']),
|
||||||
|
'diaria_litros': float(DIARIAS_AERONAVES_INTERESSE[a_idx])
|
||||||
|
})
|
||||||
|
frotas = [f for f in frotas if f['base'] is not None and f['base'] in valid_icaos]
|
||||||
|
|
||||||
|
df_dias = pd.to_datetime(demands['Data Apenas']).dt.date
|
||||||
|
dias_unicos_list = sorted(df_dias.dropna().unique())
|
||||||
|
if not dias_unicos_list:
|
||||||
|
print("NO DEMAND DATA.")
|
||||||
|
return
|
||||||
|
|
||||||
|
min_date = min(dias_unicos_list)
|
||||||
|
max_date = max(dias_unicos_list)
|
||||||
|
todas_as_datas = [min_date + datetime.timedelta(days=i) for i in range((max_date - min_date).days + 1)]
|
||||||
|
|
||||||
|
print("Pre-computing distances and overnight stays...")
|
||||||
|
unique_routes = demands[['Localidade Decolagem', 'Localidade Pouso']].drop_duplicates()
|
||||||
|
route_info = {}
|
||||||
|
for idx, row in unique_routes.iterrows():
|
||||||
|
l_dec = str(row['Localidade Decolagem'])
|
||||||
|
l_pou = str(row['Localidade Pouso'])
|
||||||
|
if l_dec not in valid_icaos or l_pou not in valid_icaos:
|
||||||
|
continue
|
||||||
|
for f in frotas:
|
||||||
|
m, e, base = f['modelo'], f['emissor'], f['base']
|
||||||
|
dist_total = dist_matrix.loc[base, l_dec] + dist_matrix.loc[l_dec, l_pou] + dist_matrix.loc[l_pou, base]
|
||||||
|
tempo_missao = dist_total / f['velocidade_media'] if f['velocidade_media'] > 0 else float('inf')
|
||||||
|
|
||||||
|
if tempo_missao <= 96.0:
|
||||||
|
num_pernoites = max(0, math.ceil(tempo_missao / 12.0) - 1)
|
||||||
|
fator1 = 1.25 if dist_matrix.loc[base, l_dec] > f['alcance'] else 1.0
|
||||||
|
fator2 = 1.25 if dist_matrix.loc[l_dec, l_pou] > f['alcance'] else 1.0
|
||||||
|
fator3 = 1.25 if dist_matrix.loc[l_pou, base] > f['alcance'] else 1.0
|
||||||
|
comb_missao = ((dist_matrix.loc[base, l_dec]*fator1 + dist_matrix.loc[l_dec, l_pou]*fator2 + dist_matrix.loc[l_pou, base]*fator3) / f['consumo_kml']) + (num_pernoites * f['diaria_litros'])
|
||||||
|
route_info[(m, e, l_dec, l_pou)] = {'num_pernoites': num_pernoites, 'combustivel_missao': comb_missao}
|
||||||
|
|
||||||
|
solver = pywraplp.Solver.CreateSolver('SCIP')
|
||||||
|
solver.SetTimeLimit(time_limit_sec * 1000)
|
||||||
|
solver.EnableOutput() # O MAIS IMPORTANTE: Isso escreve no stdout para o subprocess ler!
|
||||||
|
|
||||||
|
print("Building Demand Matrix...")
|
||||||
|
x, s = {}, {}
|
||||||
|
for t in dias_unicos_list:
|
||||||
|
demandas_dia = demands[df_dias == t]
|
||||||
|
for idx, d_row in demandas_dia.iterrows():
|
||||||
|
l_dec, l_pou = str(d_row['Localidade Decolagem']), str(d_row['Localidade Pouso'])
|
||||||
|
if l_dec not in valid_icaos or l_pou not in valid_icaos: continue
|
||||||
|
|
||||||
|
s[(l_dec, l_pou, t)] = solver.NumVar(0, solver.infinity(), f"s_{l_dec}_{l_pou}_{t}")
|
||||||
|
restricao_pax = solver.Constraint(float(d_row['PAX']), solver.infinity(), "")
|
||||||
|
restricao_pax.SetCoefficient(s[(l_dec, l_pou, t)], 1)
|
||||||
|
|
||||||
|
for f in frotas:
|
||||||
|
m, e = f['modelo'], f['emissor']
|
||||||
|
if (m, e, l_dec, l_pou) in route_info:
|
||||||
|
x[(m, e, l_dec, l_pou, t)] = solver.IntVar(0, solver.infinity(), f"x_{m}_{e}_{l_dec}_{l_pou}_{t}")
|
||||||
|
restricao_pax.SetCoefficient(x[(m, e, l_dec, l_pou, t)], f['capacidade'])
|
||||||
|
|
||||||
|
print("Building Fleet Temporal Matrix...")
|
||||||
|
for f in frotas:
|
||||||
|
m, e, frota_max = f['modelo'], f['emissor'], f['frota_max']
|
||||||
|
for t_atual in todas_as_datas:
|
||||||
|
restricao_frota = solver.Constraint(0, frota_max, "")
|
||||||
|
for t_start in dias_unicos_list:
|
||||||
|
diff_days = (t_atual - t_start).days
|
||||||
|
if 0 <= diff_days <= 7:
|
||||||
|
for idx, d_row in demands[df_dias == t_start].iterrows():
|
||||||
|
l_dec, l_pou = str(d_row['Localidade Decolagem']), str(d_row['Localidade Pouso'])
|
||||||
|
if (m, e, l_dec, l_pou, t_start) in x:
|
||||||
|
if diff_days <= route_info[(m, e, l_dec, l_pou)]['num_pernoites']:
|
||||||
|
restricao_frota.SetCoefficient(x[(m, e, l_dec, l_pou, t_start)], 1)
|
||||||
|
|
||||||
|
print("\n--- STARTING SCIP OPTIMIZATION ---\n")
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
objetivo = solver.Objective()
|
||||||
|
objetivo.SetMinimization()
|
||||||
|
for var in s.values(): objetivo.SetCoefficient(var, 1e8)
|
||||||
|
for (m, e, l_dec, l_pou, t), var in x.items():
|
||||||
|
objetivo.SetCoefficient(var, route_info[(m, e, l_dec, l_pou)]['combustivel_missao'])
|
||||||
|
|
||||||
|
status = solver.Solve()
|
||||||
|
|
||||||
|
print(f"\n--- SCIP FINISHED ---")
|
||||||
|
if status in [pywraplp.Solver.OPTIMAL, pywraplp.Solver.FEASIBLE]:
|
||||||
|
obj_val = solver.Objective().Value()
|
||||||
|
try:
|
||||||
|
best_bound = solver.Objective().BestBound()
|
||||||
|
except:
|
||||||
|
best_bound = obj_val
|
||||||
|
gap = abs((obj_val - best_bound) / obj_val) * 100 if obj_val > 0 else 0
|
||||||
|
|
||||||
|
print(f"Final Status: {'OPTIMAL' if status == pywraplp.Solver.OPTIMAL else 'FEASIBLE (Time Limit)'}")
|
||||||
|
print(f"Optimized Cost: {obj_val:,.2f} L")
|
||||||
|
with open(COST_FILE, "w") as f:
|
||||||
|
f.write(str(obj_val))
|
||||||
|
print(f"Dual Bound: {best_bound:,.2f} L")
|
||||||
|
print(f"Gap: {gap:.4f}%")
|
||||||
|
|
||||||
|
results = []
|
||||||
|
for (m, e, l_dec, l_pou, t), var in x.items():
|
||||||
|
if var.solution_value() > 0:
|
||||||
|
results.append({
|
||||||
|
'Data': t, 'Modelo': m, 'Emissor': e,
|
||||||
|
'Local Decolagem': l_dec, 'Local Pouso': l_pou,
|
||||||
|
'Qtd Aeronaves': int(var.solution_value()),
|
||||||
|
'Pernoites': route_info[(m, e, l_dec, l_pou)]['num_pernoites']
|
||||||
|
})
|
||||||
|
df_results = pd.DataFrame(results)
|
||||||
|
df_results.to_csv(RESULTS_FILE, sep=';', index=False)
|
||||||
|
print(f"Results successfully saved to {RESULTS_FILE}")
|
||||||
|
else:
|
||||||
|
print("\n[ERROR] Solver failed to find a solution.")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
time_limit = int(sys.argv[1]) if len(sys.argv) > 1 else 300
|
||||||
|
run_solver(time_limit)
|
||||||
342
uv.lock
generated
342
uv.lock
generated
@@ -19,6 +19,22 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/18/a6/907a406bb7d359e6a63f99c313846d9eec4f7e6f7437809e03aa00fa3074/absl_py-2.4.0-py3-none-any.whl", hash = "sha256:88476fd881ca8aab94ffa78b7b6c632a782ab3ba1cd19c9bd423abc4fb4cd28d", size = 135750, upload-time = "2026-01-28T10:17:04.19Z" },
|
{ url = "https://files.pythonhosted.org/packages/18/a6/907a406bb7d359e6a63f99c313846d9eec4f7e6f7437809e03aa00fa3074/absl_py-2.4.0-py3-none-any.whl", hash = "sha256:88476fd881ca8aab94ffa78b7b6c632a782ab3ba1cd19c9bd423abc4fb4cd28d", size = 135750, upload-time = "2026-01-28T10:17:04.19Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "altair"
|
||||||
|
version = "6.2.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "jinja2" },
|
||||||
|
{ name = "jsonschema" },
|
||||||
|
{ name = "narwhals" },
|
||||||
|
{ name = "packaging" },
|
||||||
|
{ name = "typing-extensions", marker = "python_full_version < '3.15'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/86/97/9a0dc61efd4f2dee29cb6d8edbbacdb789ce48cbffd98efa2b3ab145b297/altair-6.2.1.tar.gz", hash = "sha256:ca0298fa20b1a4fae22eff8847b95f74912bd90544013ad36af192119883ea64", size = 766468, upload-time = "2026-06-05T16:23:36.57Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/dc/78/b556548d92b9e29ae68a86e7b416888820900809e189e39caf308c7d44a3/altair-6.2.1-py3-none-any.whl", hash = "sha256:bf2fee3733c3a31a588e45b857a2495a88d506970deb87f74e1613f0247446b1", size = 797498, upload-time = "2026-06-05T16:23:34.799Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyio"
|
name = "anyio"
|
||||||
version = "4.13.0"
|
version = "4.13.0"
|
||||||
@@ -163,6 +179,24 @@ css = [
|
|||||||
{ name = "tinycss2" },
|
{ name = "tinycss2" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "blinker"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460, upload-time = "2024-11-08T17:25:47.436Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458, upload-time = "2024-11-08T17:25:46.184Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cachetools"
|
||||||
|
version = "7.1.4"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/f4/8b/0d3945a13955303b81272f759a0331e54c5c793da455e6f5706b89d2639c/cachetools-7.1.4.tar.gz", hash = "sha256:437f55a4e0c1b01a4f3077cc470e6991d47430970e36fbcb77e2be0df4fc1cd6", size = 40085, upload-time = "2026-05-21T22:40:43.376Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8c/7b/1fc1c09cc0756cf25861a3be10565915953876da48bb228fb9a672b20a42/cachetools-7.1.4-py3-none-any.whl", hash = "sha256:323dc4127934744db5b54eb4924482d7edafbf9554e820d1531c2e08c0e4ef54", size = 16761, upload-time = "2026-05-21T22:40:41.845Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ceao-809"
|
name = "ceao-809"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -176,6 +210,7 @@ dependencies = [
|
|||||||
{ name = "pulp" },
|
{ name = "pulp" },
|
||||||
{ name = "pymap3d" },
|
{ name = "pymap3d" },
|
||||||
{ name = "seaborn" },
|
{ name = "seaborn" },
|
||||||
|
{ name = "streamlit" },
|
||||||
{ name = "tabulate" },
|
{ name = "tabulate" },
|
||||||
{ name = "vincenty" },
|
{ name = "vincenty" },
|
||||||
]
|
]
|
||||||
@@ -190,6 +225,7 @@ requires-dist = [
|
|||||||
{ name = "pulp", specifier = ">=3.3.2" },
|
{ name = "pulp", specifier = ">=3.3.2" },
|
||||||
{ name = "pymap3d", specifier = ">=3.2.0" },
|
{ name = "pymap3d", specifier = ">=3.2.0" },
|
||||||
{ name = "seaborn", specifier = ">=0.13.2" },
|
{ name = "seaborn", specifier = ">=0.13.2" },
|
||||||
|
{ name = "streamlit", specifier = ">=1.58.0" },
|
||||||
{ name = "tabulate", specifier = ">=0.10.0" },
|
{ name = "tabulate", specifier = ">=0.10.0" },
|
||||||
{ name = "vincenty", specifier = ">=0.1.4" },
|
{ name = "vincenty", specifier = ">=0.1.4" },
|
||||||
]
|
]
|
||||||
@@ -333,6 +369,18 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" },
|
{ url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "click"
|
||||||
|
version = "8.4.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/9b/98/518d8e5081007684232226f475082b30087d0f585e8457db087298259f49/click-8.4.1.tar.gz", hash = "sha256:918b5633eddf6b41c32d4f454bf0de810065c74e3f7dbf8ee5452f8be88d3e96", size = 353007, upload-time = "2026-05-22T04:08:37.769Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c7/0d/67e5b4109ea4a837e80daa87c2c696711955e40449a97e8926672534def2/click-8.4.1-py3-none-any.whl", hash = "sha256:482be17c6991b8c19c5429a1e995d9b0efdbb63172824c41f99965dc0ade8ec2", size = 116639, upload-time = "2026-05-22T04:08:35.26Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colorama"
|
name = "colorama"
|
||||||
version = "0.4.6"
|
version = "0.4.6"
|
||||||
@@ -533,6 +581,30 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014", size = 9121, upload-time = "2021-03-11T07:16:28.351Z" },
|
{ url = "https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014", size = 9121, upload-time = "2021-03-11T07:16:28.351Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gitdb"
|
||||||
|
version = "4.0.12"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "smmap" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", size = 394684, upload-time = "2025-01-02T07:20:46.413Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf", size = 62794, upload-time = "2025-01-02T07:20:43.624Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gitpython"
|
||||||
|
version = "3.1.50"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "gitdb" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/33/f6/354ae6491228b5eb40e10d89c4d13c651fe1cf7556e35ebdded50cff57ce/gitpython-3.1.50.tar.gz", hash = "sha256:80da2d12504d52e1f998772dc5baf6e553f8d2fcfe1fcc226c9d9a2ee3372dcc", size = 219798, upload-time = "2026-05-06T04:01:26.571Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/20/7a/1c6e3562dfd8950adbb11ffbc65d21e7c89d01a6e4f137fa981056de25c5/gitpython-3.1.50-py3-none-any.whl", hash = "sha256:d352abe2908d07355014abdd21ddf798c2a961469239afec4962e9da884858f9", size = 212507, upload-time = "2026-05-06T04:01:23.799Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "h11"
|
name = "h11"
|
||||||
version = "0.16.0"
|
version = "0.16.0"
|
||||||
@@ -555,6 +627,42 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
|
{ url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httptools"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/43/e5/d471fcb0e14523fe1c3f4ba58ca52480e7bd70ad7109a3846bc75892f7fb/httptools-0.8.0.tar.gz", hash = "sha256:6b2a32f18d97e16e90827d7a819ffa8dbd8cc245fc4e1fa9d1095b54ef4bd999", size = 271342, upload-time = "2026-05-25T22:17:48.841Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/14/88/1d21a36da8f5cb0fa49eafd4b169eba5608d57e75bbcf61845cbc6243216/httptools-0.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:880490234c10f70a9830743097e8958d6e4b9f5a0ffc24515023afeef984054d", size = 208247, upload-time = "2026-05-25T22:17:07.843Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a5/42/cc4feea2945cb3051038f090c9b36bd5b8a9d7f5a894a506a8983e33fd1c/httptools-0.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5931891fb7b441b8a3853cf1b85c82c903defce084dd5f6771ca46e31bf862c5", size = 113064, upload-time = "2026-05-25T22:17:09.136Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e3/a6/febbb8b8db0f58b38e44ad6cb946e6a255ae49b55f2e8543408fb7501ccd/httptools-0.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b15fc622b0f869d19207c4089a501d9bcc63ca5e071ffdd2f03f922df882dcb2", size = 523851, upload-time = "2026-05-25T22:17:10.106Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b7/e4/f90a0df0b83beff265b7e3b65f2a4cefd95792d4be0ac3e16049f2acd3c2/httptools-0.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:425f83884fd6343828d8c565f046cb72b6d19063f6924093e11bcd8e1548cd09", size = 518842, upload-time = "2026-05-25T22:17:11.218Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9e/2d/0c9ac76dd2c893841fbf6498d6acec4f2442e1b7067f6e3e316a80e494e8/httptools-0.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ef7c3c97f4311c7be57e2986629df89d49cb434dbff78eafcd48c2bff986b15a", size = 501238, upload-time = "2026-05-25T22:17:12.728Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ca/42/906adc91ae3a5fa9c59c0a2f21c139725bd7e5b41ae6acd485cd14123ebf/httptools-0.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a1afd7c9fbff0d9f5d489c4ce2768bd09c84a46ddefc7161e6aa82ae35c85745", size = 509567, upload-time = "2026-05-25T22:17:13.842Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/05/0b/4240efeb672751ee5b9b380cb0e3fdc050bc05f68adc7a8aefc4fcd9a69a/httptools-0.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:cd96f29b4bab1d42fa6e3d008711c75e0f79e94e06827330160e3a304227f150", size = 90918, upload-time = "2026-05-25T22:17:15.155Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5e/e5/8cfcabc5546e8022f168be28bcdaa128a240a0befdd03b59d558b4f18bd6/httptools-0.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:614ceea8ea606848bece2338ac03b3ce5324bcb4be8dc7d377ed708012fa4db8", size = 205148, upload-time = "2026-05-25T22:17:16.333Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2a/0e/0fb14848c19a686c8062ff9067c1a48793e3224b47bc5b201535b6036fce/httptools-0.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2d689918c15a013c65ef52d9fd495d766893ab831a2c8d89f2ac5940a5df847c", size = 111368, upload-time = "2026-05-25T22:17:17.586Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2e/1b/46f1cecf06b9bbde8e4b8c88034ac7908989e5ff7a3a388ef38392949c1f/httptools-0.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:eb3028cca2fc0a6d720e52ef61d8ebb62fcbfeb1de56874546d858d3f25a26b7", size = 486447, upload-time = "2026-05-25T22:17:18.564Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/77/00/258bfc0837221f81d9725c45f9b948a6a6b2994a147a4fb66e85100c668f/httptools-0.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:88bdd940f2b5d487b4d032c6afa5489a7dc4694410d43de3c38c4fb3af0dc45d", size = 482448, upload-time = "2026-05-25T22:17:19.912Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/04/ab/d1cef3b5523f4d272a70f42a776c3169a2dddfe3a54de4b2ce4a36341528/httptools-0.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6a43c9dd399758ccc0531acb0a3c4a6c299ee893ee9400e9c893b7bdcfae0681", size = 464460, upload-time = "2026-05-25T22:17:20.882Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ce/48/5d1d072442277bb2b3434e0e60690b8e8c23840ef7de8b6ea54040a536d3/httptools-0.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0770728beb05094c809b98e814edff5fef69d26ad7d21185f2f6d5884a0ba683", size = 471312, upload-time = "2026-05-25T22:17:22.085Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0d/66/b96623b27e51a68199ef4efdda0613cced9233fe3062ac74e50749c5ad37/httptools-0.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:7685df791fad561384bfb139e77fde27a1ffd93134e016f95a0db424ffbf77b1", size = 90117, upload-time = "2026-05-25T22:17:23.074Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1a/12/fa3fbf5f9517b273edea2dc982aa82a8c634091e67c590792b729017bc6f/httptools-0.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:de242a49b5d18e0a8776e654e9f6bf6d89f3875a5c35b425a0e7ce940feb3fd6", size = 206183, upload-time = "2026-05-25T22:17:24.004Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/30/fc/5e7c4cb443370f2090a3aba0453a07384d29ff66b7435bb90e77e1037599/httptools-0.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:159e9ab5f701ccd42e555a12f1ad8ff69702910fc1c996cf2bb66e5fcb7a231b", size = 112079, upload-time = "2026-05-25T22:17:25.216Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ba/53/771bd891eb0f236f32145d6a1775777ec85745f3cc983a1f23d1a3b8ddfe/httptools-0.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c4a9f1707e4823d54dfec6c33fa3697d302aed536ed352a7ebb5a061ddb869d0", size = 481596, upload-time = "2026-05-25T22:17:26.186Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/62/42/94e15bc68ce3d423243c45d7f1b0c7561f13844f97dc52ae23182fb65628/httptools-0.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d76ad7b951387e3632c8716a9bb03ac5b45c5f16119aa409db0459520887944e", size = 480865, upload-time = "2026-05-25T22:17:27.542Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1c/7c/fe2980fc03723272e30f135b62360b075f513dfe7cc73aef36c7f04012bd/httptools-0.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a3b7387147361c3fd47a0bde763c5c91b5b4cd4dc9989b8ece84ff436c99843b", size = 463189, upload-time = "2026-05-25T22:17:28.546Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/15/1b/47fc5fff68acd1bfa20b4734059c9a06cadb88119dcd5258b5b0d21d91c8/httptools-0.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f256d6ce930c52ca1cb2a960b7da03548c454e7d28b06059ad41bfe789036ce0", size = 466610, upload-time = "2026-05-25T22:17:29.816Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/60/bd/07b13c93ffd9bec9546e0d43f8e19378dd696dbd278511406bc07371ef1f/httptools-0.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:19d1ee275bb59ba2643ba9a3a1e51cc0c788caf2b8df506368e03f56fdd08527", size = 92705, upload-time = "2026-05-25T22:17:31.133Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fd/c4/121648f68ce066d7bd762d6b6d97e620847642d38d54f3d90ff11d947629/httptools-0.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:de1ed58a974e75d56560acc7e7fed01a454994429456f65209789992e41f2568", size = 215023, upload-time = "2026-05-25T22:17:32.401Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b9/b0/312a062ae741ae3e8baa8c8bf20be81b2e67337b259ab4349bebc7b6142e/httptools-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e93c227b595c6926c1acee96891dd9da4be338cfbe82e5cd3bb9d8dd7dc4ac0b", size = 117405, upload-time = "2026-05-25T22:17:33.742Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fc/37/fccd705f795386bb05bf413012fecff2a33e5aa8c2f069096de3e9fd8702/httptools-0.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2a021c3a8e65cc125390d72f59b968afca3bdcaff25bd67965e0a055a14946ca", size = 558497, upload-time = "2026-05-25T22:17:34.732Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bd/39/f172e8003576de35f5ba77ff417cf0e34429d35dc014deef15afa337a72c/httptools-0.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48774d39cbb70e2b1f71f88852a3087ae1d3a1eb80482bb48c13067ab080c14f", size = 571585, upload-time = "2026-05-25T22:17:35.813Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3e/b9/f5564760af99f3dbbf3f9104dc00e5da27e96cf433c6bdcf77617f70bf3f/httptools-0.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:88eead8ec8680a9f146c655bc88445a325bd7921cfd8194c7337e9467282427d", size = 543297, upload-time = "2026-05-25T22:17:37.08Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/99/67/8d9f2c313618e161b82f3873188e7196126da1d6e29688df40eb3997c77a/httptools-0.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2c032fa028f46871ec7e1fc59fc15e8023eab3e6bbe6ece786a1611719a5d081", size = 539535, upload-time = "2026-05-25T22:17:38.032Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/48/63/b906c01e53f50d432c0defe43ce52764a111dc1bdd028bafbeb54dcfd008/httptools-0.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:384c17174464c8e873398b7af24f0b1f44d992c820328413951a625323155d77", size = 108209, upload-time = "2026-05-25T22:17:39.473Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "httpx"
|
name = "httpx"
|
||||||
version = "0.28.1"
|
version = "0.28.1"
|
||||||
@@ -658,6 +766,15 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042", size = 11321, upload-time = "2020-11-01T10:59:58.02Z" },
|
{ url = "https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042", size = 11321, upload-time = "2020-11-01T10:59:58.02Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itsdangerous"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410, upload-time = "2024-04-16T21:28:15.614Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234, upload-time = "2024-04-16T21:28:14.499Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jedi"
|
name = "jedi"
|
||||||
version = "0.20.0"
|
version = "0.20.0"
|
||||||
@@ -1127,6 +1244,15 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/2a/7f/a946aa4f8752b37102b41e64dca18a1976ac705c3a0d1dfe74d820a02552/mistune-3.2.1-py3-none-any.whl", hash = "sha256:78cdb0ba5e938053ccf63651b352508d2efa9411dc8810bfb05f2dc5140c0048", size = 53749, upload-time = "2026-05-03T14:33:20.551Z" },
|
{ url = "https://files.pythonhosted.org/packages/2a/7f/a946aa4f8752b37102b41e64dca18a1976ac705c3a0d1dfe74d820a02552/mistune-3.2.1-py3-none-any.whl", hash = "sha256:78cdb0ba5e938053ccf63651b352508d2efa9411dc8810bfb05f2dc5140c0048", size = 53749, upload-time = "2026-05-03T14:33:20.551Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "narwhals"
|
||||||
|
version = "2.22.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/62/3c/c4ef2164a71c1a63d7f1ae411c4082c5fa872405106db60a4b7114989ad7/narwhals-2.22.1.tar.gz", hash = "sha256:d62920805a0a43b7ff8b54b0c0d3142d796f8a9301836ada37e573d6a33cbcd9", size = 647493, upload-time = "2026-06-05T12:34:34.051Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/48/ca/36339329c4604adbcc99c899b7eb1ce1a555c499b6a6860757dc9bfed36d/narwhals-2.22.1-py3-none-any.whl", hash = "sha256:60567d774edf77db53906f89d9fbd164e66e56d66d388e1e6990f17ac33cfb53", size = 454815, upload-time = "2026-06-05T12:34:32.289Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nbclient"
|
name = "nbclient"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
@@ -1567,6 +1693,49 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" },
|
{ url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyarrow"
|
||||||
|
version = "24.0.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/91/13/13e1069b351bdc3881266e11147ffccf687505dbb0ea74036237f5d454a5/pyarrow-24.0.0.tar.gz", hash = "sha256:85fe721a14dd823aca09127acbb06c3ca723efbd436c004f16bca601b04dcc83", size = 1180261, upload-time = "2026-04-21T10:51:25.837Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b4/a9/9686d9f07837f91f775e8932659192e02c74f9d8920524b480b85212cc68/pyarrow-24.0.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:6233c9ed9ab9d1db47de57d9753256d9dcffbf42db341576099f0fd9f6bf4810", size = 34981559, upload-time = "2026-04-21T10:47:22.17Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/80/b6/0ddf0e9b6ead3474ab087ae598c76b031fc45532bf6a63f3a553440fb258/pyarrow-24.0.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:f7616236ec1bc2b15bfdec22a71ab38851c86f8f05ff64f379e1278cf20c634a", size = 36663654, upload-time = "2026-04-21T10:47:28.315Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7c/3b/926382efe8ce27ba729071d3566ade6dfb86bdf112f366000196b2f5780a/pyarrow-24.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:1617043b99bd33e5318ae18eb2919af09c71322ef1ca46566cdafc6e6712fb66", size = 45679394, upload-time = "2026-04-21T10:47:34.821Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b3/7a/829f7d9dfd37c207206081d6dad474d81dde29952401f07f2ba507814818/pyarrow-24.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:6165461f55ef6314f026de6638d661188e3455d3ec49834556a0ebbdbace18bb", size = 48863122, upload-time = "2026-04-21T10:47:42.056Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5f/e8/f88ce625fe8babaae64e8db2d417c7653adb3019b08aae85c5ed787dc816/pyarrow-24.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3b13dedfe76a0ad2d1d859b0811b53827a4e9d93a0bcb05cf59333ab4980cc7e", size = 49376032, upload-time = "2026-04-21T10:47:48.967Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/36/7a/82c363caa145fff88fb475da50d3bf52bb024f61917be5424c3392eaf878/pyarrow-24.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:25ea65d868eb04015cd18e6df2fbe98f07e5bda2abefabcb88fce39a947716f6", size = 51929490, upload-time = "2026-04-21T10:47:55.981Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/66/1c/e3e72c8014ad2743ca64a701652c733cc5cbcee15c0463a32a8c55518d9e/pyarrow-24.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:295f0a7f2e242dabd513737cf076007dc5b2d59237e3eca37b05c0c6446f3826", size = 27355660, upload-time = "2026-04-21T10:48:01.718Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6f/d3/a1abf004482026ddc17f4503db227787fa3cfe41ec5091ff20e4fea55e57/pyarrow-24.0.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:02b001b3ed4723caa44f6cd1af2d5c86aa2cf9971dacc2ffa55b21237713dfba", size = 34976759, upload-time = "2026-04-21T10:48:07.258Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4f/4a/34f0a36d28a2dd32225301b79daad44e243dc1a2bb77d43b60749be255c4/pyarrow-24.0.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:04920d6a71aabd08a0417709efce97d45ea8e6fb733d9ca9ecffb13c67839f68", size = 36658471, upload-time = "2026-04-21T10:48:13.347Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1f/78/543b94712ae8bb1a6023bcc1acf1a740fbff8286747c289cd9468fced2a5/pyarrow-24.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:a964266397740257f16f7bb2e4f08a0c81454004beab8ff59dd531b73610e9f2", size = 45675981, upload-time = "2026-04-21T10:48:20.201Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/84/9f/8fb7c222b100d314137fa40ec050de56cd8c6d957d1cfff685ce72f15b17/pyarrow-24.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:6f066b179d68c413374294bc1735f68475457c933258df594443bb9d88ddc2a0", size = 48859172, upload-time = "2026-04-21T10:48:27.541Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a7/d3/1ea72538e6c8b3b475ed78d1049a2c518e655761ea50fe1171fc855fcab7/pyarrow-24.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1183baeb14c5f587b1ec52831e665718ce632caab84b7cd6b85fd44f96114495", size = 49385733, upload-time = "2026-04-21T10:48:34.7Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c3/be/c3d8b06a1ba35f2260f8e1f771abbee7d5e345c0937aab90675706b1690a/pyarrow-24.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:806f24b4085453c197a5078218d1ee08783ebbba271badd153d1ae22a3ee804f", size = 51934335, upload-time = "2026-04-21T10:48:42.099Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9c/62/89e07a1e7329d2cde3e3c6994ba0839a24977a2beda8be6005ea3d860b99/pyarrow-24.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:e4505fc6583f7b05ab854934896bcac8253b04ac1171a77dfb73efef92076d91", size = 27271748, upload-time = "2026-04-21T10:49:42.532Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/17/1a/cff3a59f80b5b1658549d46611b67163f65e0664431c076ad728bf9d5af4/pyarrow-24.0.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:1a4e45017efbf115032e4475ee876d525e0e36c742214fbe405332480ecd6275", size = 35238554, upload-time = "2026-04-21T10:48:48.526Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a8/99/cce0f42a327bfef2c420fb6078a3eb834826e5d6697bf3009fe11d2ad051/pyarrow-24.0.0-cp313-cp313t-macosx_12_0_x86_64.whl", hash = "sha256:7986f1fa71cee060ad00758bcc79d3a93bab8559bf978fab9e53472a2e25a17b", size = 36782301, upload-time = "2026-04-21T10:48:55.181Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2a/66/8e560d5ff6793ca29aca213c53eec0dd482dd46cb93b2819e5aab52e4252/pyarrow-24.0.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:d3e0b61e8efb24ed38898e5cdc5fffa9124be480008d401a1f8071500494ae42", size = 45721929, upload-time = "2026-04-21T10:49:03.676Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/27/0c/a26e25505d030716e078d9f16eb74973cbf0b33b672884e9f9da1c83b871/pyarrow-24.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:55a3bc1e3df3b5567b7d27ef551b2283f0c68a5e86f1cd56abc569da4f31335b", size = 48825365, upload-time = "2026-04-21T10:49:11.714Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5f/eb/771f9ecb0c65e73fe9dccdd1717901b9594f08c4515d000c7c62df573811/pyarrow-24.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:641f795b361874ac9da5294f8f443dfdbee355cf2bd9e3b8d97aaac2306b9b37", size = 49451819, upload-time = "2026-04-21T10:49:21.474Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/48/da/61ae89a88732f5a785646f3ec6125dbb640fa98a540eb2b9889caa561403/pyarrow-24.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8adc8e6ce5fccf5dc707046ae4914fd537def529709cc0d285d37a7f9cd442ca", size = 51909252, upload-time = "2026-04-21T10:49:31.164Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cb/1a/8dd5cafab7b66573fa91c03d06d213356ad4edd71813aa75e08ce2b3a844/pyarrow-24.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:9b18371ad2f44044b81a8d23bc2d8a9b6a6226dca775e8e16cfee640473d6c5d", size = 27388127, upload-time = "2026-04-21T10:49:37.334Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ad/80/d022a34ff05d2cbedd8ccf841fc1f532ecfa9eb5ed1711b56d0e0ea71fc9/pyarrow-24.0.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:1cc9057f0319e26333b357e17f3c2c022f1a83739b48a88b25bfd5fa2dc18838", size = 35007997, upload-time = "2026-04-21T10:49:48.796Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1a/ff/f01485fda6f4e5d441afb8dd5e7681e4db18826c1e271852f5d3957d6a80/pyarrow-24.0.0-cp314-cp314-macosx_12_0_x86_64.whl", hash = "sha256:e6f1278ee4785b6db21229374a1c9e54ec7c549de5d1efc9630b6207de7e170b", size = 36678720, upload-time = "2026-04-21T10:49:55.858Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9e/c2/2d2d5fea814237923f71b36495211f20b43a1576f9a4d6da7e751a64ec6f/pyarrow-24.0.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:adbbedc55506cbdabb830890444fb856bfb0060c46c6f8026c6c2f2cf86ae795", size = 45741852, upload-time = "2026-04-21T10:50:04.624Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8e/3a/28ba9c1c1ebdbb5f1b94dfebb46f207e52e6a554b7fe4132540fde29a3a0/pyarrow-24.0.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:ae8a1145af31d903fa9bb166824d7abe9b4681a000b0159c9fb99c11bc11ad26", size = 48889852, upload-time = "2026-04-21T10:50:12.293Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/df/51/4a389acfd31dca009f8fb82d7f510bb4130f2b3a8e18cf00194d0687d8ac/pyarrow-24.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d7027eba1df3b2069e2e8d80f644fa0918b68c46432af3d088ddd390d063ecde", size = 49445207, upload-time = "2026-04-21T10:50:20.677Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/19/4b/0bab2b23d2ae901b1b9a03c0efd4b2d070256f8ce3fc43f6e58c167b2081/pyarrow-24.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e56a1ffe9bf7b727432b89104cc0849c21582949dd7bdcb34f17b2001a351a76", size = 51954117, upload-time = "2026-04-21T10:50:29.14Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/29/88/f4e9145da0417b3d2c12035a8492b35ff4a3dbc653e614fcfb51d9dedb38/pyarrow-24.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:38be1808cdd068605b787e6ca9119b27eb275a0234e50212c3492331680c3b1e", size = 28001155, upload-time = "2026-04-21T10:51:22.337Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/79/4f/46a49a63f43526da895b1a45bbb51d5baf8e4d77159f8528fc3e5490007f/pyarrow-24.0.0-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:418e48ce50a45a6a6c73c454677203a9c75c966cb1e92ca3370959185f197a05", size = 35250387, upload-time = "2026-04-21T10:50:35.552Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a0/da/d5e0cd5ef00796922404806d5f00325cdadc3441ce2c13fe7115f2df9a64/pyarrow-24.0.0-cp314-cp314t-macosx_12_0_x86_64.whl", hash = "sha256:2f16197705a230a78270cdd4ea8a1d57e86b2fdcbc34a1f6aebc72e65c986f9a", size = 36797102, upload-time = "2026-04-21T10:50:42.417Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/34/c7/5904145b0a593a05236c882933d439b5720f0a145381179063722fbfc123/pyarrow-24.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:fb24ac194bfc5e86839d7dcd52092ee31e5fe6733fe11f5e3b06ef0812b20072", size = 45745118, upload-time = "2026-04-21T10:50:49.324Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/13/d3/cca42fe166d1c6e4d5b80e530b7949104d10e17508a90ae202dac205ce2a/pyarrow-24.0.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:9700ebd9a51f5895ce75ff4ac4b3c47a7d4b42bc618be8e713e5d56bacf5f931", size = 48844765, upload-time = "2026-04-21T10:50:55.579Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b0/49/942c3b79878ba928324d1e17c274ed84581db8c0a749b24bcf4cbdf15bd3/pyarrow-24.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d8ddd2768da81d3ee08cfea9b597f4abb4e8e1dc8ae7e204b608d23a0d3ab699", size = 49471890, upload-time = "2026-04-21T10:51:02.439Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/76/97/ff71431000a75d84135a1ace5ca4ba11726a231a8007bbb320a4c54075d5/pyarrow-24.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:61a3d7eaa97a14768b542f3d284dc6400dd2470d9f080708b13cd46b6ae18136", size = 51932250, upload-time = "2026-04-21T10:51:10.576Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/51/be/6f79d55816d5c22557cf27533543d5d70dfe692adfbee4b99f2760674f38/pyarrow-24.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:c91d00057f23b8d353039520dc3a6c09d8608164c692e9f59a175a42b2ae0c19", size = 28131282, upload-time = "2026-04-21T10:51:16.815Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pycparser"
|
name = "pycparser"
|
||||||
version = "3.0"
|
version = "3.0"
|
||||||
@@ -1576,6 +1745,19 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" },
|
{ url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pydeck"
|
||||||
|
version = "0.9.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "jinja2" },
|
||||||
|
{ name = "numpy" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/eb/df/4e9e7f20f8034a37c6571c93809f6d22388c39978c98d174d656c1a18fd2/pydeck-0.9.2.tar.gz", hash = "sha256:c10d9035e81ead6385264cac8d19402471f6866a15ca1f7df1400f52142bcf87", size = 5849672, upload-time = "2026-04-16T18:30:30.089Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/88/24/b30ee7d723100fd822de1bb4c0adea62f3419884a75a536f35f355d1e7c0/pydeck-0.9.2-py2.py3-none-any.whl", hash = "sha256:8213dfeacc5f6bfe6825f61c8ee34e3850e8a31fc43924379ec98edb34a75b25", size = 11305615, upload-time = "2026-04-16T18:30:28.133Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pygments"
|
name = "pygments"
|
||||||
version = "2.20.0"
|
version = "2.20.0"
|
||||||
@@ -1624,6 +1806,15 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/27/be/0631a861af4d1c875f096c07d34e9a63639560a717130e7a87cbc82b7e3f/python_json_logger-4.1.0-py3-none-any.whl", hash = "sha256:132994765cf75bf44554be9aa49b06ef2345d23661a96720262716438141b6b2", size = 15021, upload-time = "2026-03-29T04:39:55.266Z" },
|
{ url = "https://files.pythonhosted.org/packages/27/be/0631a861af4d1c875f096c07d34e9a63639560a717130e7a87cbc82b7e3f/python_json_logger-4.1.0-py3-none-any.whl", hash = "sha256:132994765cf75bf44554be9aa49b06ef2345d23661a96720262716438141b6b2", size = 15021, upload-time = "2026-03-29T04:39:55.266Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "python-multipart"
|
||||||
|
version = "0.0.32"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/5b/42/55c32bb9b12693c092ad250a0e82edb5b31ddeda6eb772de5f308b3804ad/python_multipart-0.0.32.tar.gz", hash = "sha256:be54b7f3fa167bb83e4fcd936b887b708f4e57fe75911c02aebf53efaf8d938e", size = 46881, upload-time = "2026-06-04T16:18:58.647Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl", hash = "sha256:ff6d3f776f16878c894e52e107296ffc890e913c611b1a4ec6c44e2821fe2e23", size = 30042, upload-time = "2026-06-04T16:18:57.319Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pywinpty"
|
name = "pywinpty"
|
||||||
version = "3.0.3"
|
version = "3.0.3"
|
||||||
@@ -1944,6 +2135,15 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
|
{ url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smmap"
|
||||||
|
version = "5.0.3"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/1f/ea/49c993d6dfdd7338c9b1000a0f36817ed7ec84577ae2e52f890d1a4ff909/smmap-5.0.3.tar.gz", hash = "sha256:4d9debb8b99007ae47165abc08670bd74cb74b5227dda7f643eccc4e9eb5642c", size = 22506, upload-time = "2026-03-09T03:43:26.1Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c1/d4/59e74daffcb57a07668852eeeb6035af9f32cbfd7a1d2511f17d2fe6a738/smmap-5.0.3-py3-none-any.whl", hash = "sha256:c106e05d5a61449cf6ba9a1e650227ecfb141590d2a98412103ff35d89fc7b2f", size = 24390, upload-time = "2026-03-09T03:43:24.361Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "soupsieve"
|
name = "soupsieve"
|
||||||
version = "2.8.4"
|
version = "2.8.4"
|
||||||
@@ -1967,6 +2167,54 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" },
|
{ url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "starlette"
|
||||||
|
version = "1.3.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "anyio" },
|
||||||
|
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/eb/e3/7c1dc7381d9f8ab7d854328ebfa884e62cb3f3d8549ddfd37c7814f42afa/starlette-1.3.1.tar.gz", hash = "sha256:05d0213193f2fbaae60e2ecb593b4add4262ad4e46536b54abe36f11a71724e0", size = 2703240, upload-time = "2026-06-12T09:23:11.602Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl", hash = "sha256:c7372aae11c3c3f26a42df7bd626cec2f47d03483d261d369516a615a53714c6", size = 73632, upload-time = "2026-06-12T09:23:10.017Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "streamlit"
|
||||||
|
version = "1.58.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "altair" },
|
||||||
|
{ name = "anyio" },
|
||||||
|
{ name = "blinker" },
|
||||||
|
{ name = "cachetools" },
|
||||||
|
{ name = "click" },
|
||||||
|
{ name = "gitpython" },
|
||||||
|
{ name = "httptools" },
|
||||||
|
{ name = "itsdangerous" },
|
||||||
|
{ name = "numpy" },
|
||||||
|
{ name = "packaging" },
|
||||||
|
{ name = "pandas" },
|
||||||
|
{ name = "pillow" },
|
||||||
|
{ name = "protobuf" },
|
||||||
|
{ name = "pyarrow" },
|
||||||
|
{ name = "pydeck" },
|
||||||
|
{ name = "python-multipart" },
|
||||||
|
{ name = "requests" },
|
||||||
|
{ name = "starlette" },
|
||||||
|
{ name = "tenacity" },
|
||||||
|
{ name = "toml" },
|
||||||
|
{ name = "typing-extensions" },
|
||||||
|
{ name = "uvicorn" },
|
||||||
|
{ name = "watchdog", marker = "sys_platform != 'darwin'" },
|
||||||
|
{ name = "websockets" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/91/74/20dac6d6200d6ec0e1c230fb8eeb6a1a423645eacb76e8d802adfc246456/streamlit-1.58.0.tar.gz", hash = "sha256:78a22e7085b053af7ce544442bf4b670771e68c509ba1bdaa056ba0708f49c3d", size = 8721149, upload-time = "2026-05-28T18:02:44.606Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/df/84/14c36a92fb24f8e1cea452f53b0744b5da69d52cdd2fe22e71e6fbf765d5/streamlit-1.58.0-py3-none-any.whl", hash = "sha256:4ca8a7afc5bd16a5f176ccf4be1e34e8121cad0240becd127fb58a103ea3178d", size = 9219185, upload-time = "2026-05-28T18:02:41.993Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tabulate"
|
name = "tabulate"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
@@ -1976,6 +2224,15 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/99/55/db07de81b5c630da5cbf5c7df646580ca26dfaefa593667fc6f2fe016d2e/tabulate-0.10.0-py3-none-any.whl", hash = "sha256:f0b0622e567335c8fabaaa659f1b33bcb6ddfe2e496071b743aa113f8774f2d3", size = 39814, upload-time = "2026-03-04T18:55:31.284Z" },
|
{ url = "https://files.pythonhosted.org/packages/99/55/db07de81b5c630da5cbf5c7df646580ca26dfaefa593667fc6f2fe016d2e/tabulate-0.10.0-py3-none-any.whl", hash = "sha256:f0b0622e567335c8fabaaa659f1b33bcb6ddfe2e496071b743aa113f8774f2d3", size = 39814, upload-time = "2026-03-04T18:55:31.284Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tenacity"
|
||||||
|
version = "9.1.4"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/47/c6/ee486fd809e357697ee8a44d3d69222b344920433d3b6666ccd9b374630c/tenacity-9.1.4.tar.gz", hash = "sha256:adb31d4c263f2bd041081ab33b498309a57c77f9acf2db65aadf0898179cf93a", size = 49413, upload-time = "2026-02-07T10:45:33.841Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl", hash = "sha256:6095a360c919085f28c6527de529e76a06ad89b23659fa881ae0649b867a9d55", size = 28926, upload-time = "2026-02-07T10:45:32.24Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "terminado"
|
name = "terminado"
|
||||||
version = "0.18.1"
|
version = "0.18.1"
|
||||||
@@ -2002,6 +2259,15 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/60/45/c7b5c3168458db837e8ceab06dc77824e18202679d0463f0e8f002143a97/tinycss2-1.5.1-py3-none-any.whl", hash = "sha256:3415ba0f5839c062696996998176c4a3751d18b7edaaeeb658c9ce21ec150661", size = 28404, upload-time = "2025-11-23T10:29:08.676Z" },
|
{ url = "https://files.pythonhosted.org/packages/60/45/c7b5c3168458db837e8ceab06dc77824e18202679d0463f0e8f002143a97/tinycss2-1.5.1-py3-none-any.whl", hash = "sha256:3415ba0f5839c062696996998176c4a3751d18b7edaaeeb658c9ce21ec150661", size = 28404, upload-time = "2025-11-23T10:29:08.676Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.10.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253, upload-time = "2020-11-01T01:40:22.204Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588, upload-time = "2020-11-01T01:40:20.672Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tornado"
|
name = "tornado"
|
||||||
version = "6.5.6"
|
version = "6.5.6"
|
||||||
@@ -2064,12 +2330,43 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" },
|
{ url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uvicorn"
|
||||||
|
version = "0.49.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "click" },
|
||||||
|
{ name = "h11" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/c4/1f/fa18009dea8469069cca78a4e877a008ab78f08b064bfc9ab891579077ff/uvicorn-0.49.0.tar.gz", hash = "sha256:ebf4271aa580d9de97f93192d4595176df6e91f9aae919ca73e4fc07df1e66a3", size = 91284, upload-time = "2026-06-03T22:01:30.448Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/88/fa/e1388bbcf24ef3274f45c0c1c7b501fd14971037c1b6ee23610553307497/uvicorn-0.49.0-py3-none-any.whl", hash = "sha256:ba3d14c3ee7e41c6c654c46c9eb489d33213cdd30aa1696eab1374337c13f68f", size = 71376, upload-time = "2026-06-03T22:01:29.037Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vincenty"
|
name = "vincenty"
|
||||||
version = "0.1.4"
|
version = "0.1.4"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/c4/de/296372fde237fdda627fb6127a34689a3c1b25b6531a180060bf8e11457f/vincenty-0.1.4.tar.gz", hash = "sha256:eaa2f2de835f369cbd71c1a01ccd4e0d412da0f4aeef7c9692242b9ce182785a", size = 2757, upload-time = "2016-01-24T08:49:26.739Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/c4/de/296372fde237fdda627fb6127a34689a3c1b25b6531a180060bf8e11457f/vincenty-0.1.4.tar.gz", hash = "sha256:eaa2f2de835f369cbd71c1a01ccd4e0d412da0f4aeef7c9692242b9ce182785a", size = 2757, upload-time = "2016-01-24T08:49:26.739Z" }
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "watchdog"
|
||||||
|
version = "6.0.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wcwidth"
|
name = "wcwidth"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
@@ -2105,3 +2402,48 @@ sdist = { url = "https://files.pythonhosted.org/packages/2c/41/aa4bf9664e4cda14c
|
|||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef", size = 82616, upload-time = "2025-10-07T21:16:34.951Z" },
|
{ url = "https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef", size = 82616, upload-time = "2025-10-07T21:16:34.951Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "websockets"
|
||||||
|
version = "16.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/04/24/4b2031d72e840ce4c1ccb255f693b15c334757fc50023e4db9537080b8c4/websockets-16.0.tar.gz", hash = "sha256:5f6261a5e56e8d5c42a4497b364ea24d94d9563e8fbd44e78ac40879c60179b5", size = 179346, upload-time = "2026-01-10T09:23:47.181Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/84/7b/bac442e6b96c9d25092695578dda82403c77936104b5682307bd4deb1ad4/websockets-16.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:71c989cbf3254fbd5e84d3bff31e4da39c43f884e64f2551d14bb3c186230f00", size = 177365, upload-time = "2026-01-10T09:22:46.787Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b0/fe/136ccece61bd690d9c1f715baaeefd953bb2360134de73519d5df19d29ca/websockets-16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8b6e209ffee39ff1b6d0fa7bfef6de950c60dfb91b8fcead17da4ee539121a79", size = 175038, upload-time = "2026-01-10T09:22:47.999Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/40/1e/9771421ac2286eaab95b8575b0cb701ae3663abf8b5e1f64f1fd90d0a673/websockets-16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86890e837d61574c92a97496d590968b23c2ef0aeb8a9bc9421d174cd378ae39", size = 175328, upload-time = "2026-01-10T09:22:49.809Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/18/29/71729b4671f21e1eaa5d6573031ab810ad2936c8175f03f97f3ff164c802/websockets-16.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9b5aca38b67492ef518a8ab76851862488a478602229112c4b0d58d63a7a4d5c", size = 184915, upload-time = "2026-01-10T09:22:51.071Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/97/bb/21c36b7dbbafc85d2d480cd65df02a1dc93bf76d97147605a8e27ff9409d/websockets-16.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e0334872c0a37b606418ac52f6ab9cfd17317ac26365f7f65e203e2d0d0d359f", size = 186152, upload-time = "2026-01-10T09:22:52.224Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4a/34/9bf8df0c0cf88fa7bfe36678dc7b02970c9a7d5e065a3099292db87b1be2/websockets-16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a0b31e0b424cc6b5a04b8838bbaec1688834b2383256688cf47eb97412531da1", size = 185583, upload-time = "2026-01-10T09:22:53.443Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/47/88/4dd516068e1a3d6ab3c7c183288404cd424a9a02d585efbac226cb61ff2d/websockets-16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:485c49116d0af10ac698623c513c1cc01c9446c058a4e61e3bf6c19dff7335a2", size = 184880, upload-time = "2026-01-10T09:22:55.033Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/91/d6/7d4553ad4bf1c0421e1ebd4b18de5d9098383b5caa1d937b63df8d04b565/websockets-16.0-cp312-cp312-win32.whl", hash = "sha256:eaded469f5e5b7294e2bdca0ab06becb6756ea86894a47806456089298813c89", size = 178261, upload-time = "2026-01-10T09:22:56.251Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c3/f0/f3a17365441ed1c27f850a80b2bc680a0fa9505d733fe152fdf5e98c1c0b/websockets-16.0-cp312-cp312-win_amd64.whl", hash = "sha256:5569417dc80977fc8c2d43a86f78e0a5a22fee17565d78621b6bb264a115d4ea", size = 178693, upload-time = "2026-01-10T09:22:57.478Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cc/9c/baa8456050d1c1b08dd0ec7346026668cbc6f145ab4e314d707bb845bf0d/websockets-16.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:878b336ac47938b474c8f982ac2f7266a540adc3fa4ad74ae96fea9823a02cc9", size = 177364, upload-time = "2026-01-10T09:22:59.333Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7e/0c/8811fc53e9bcff68fe7de2bcbe75116a8d959ac699a3200f4847a8925210/websockets-16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:52a0fec0e6c8d9a784c2c78276a48a2bdf099e4ccc2a4cad53b27718dbfd0230", size = 175039, upload-time = "2026-01-10T09:23:01.171Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/aa/82/39a5f910cb99ec0b59e482971238c845af9220d3ab9fa76dd9162cda9d62/websockets-16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e6578ed5b6981005df1860a56e3617f14a6c307e6a71b4fff8c48fdc50f3ed2c", size = 175323, upload-time = "2026-01-10T09:23:02.341Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bd/28/0a25ee5342eb5d5f297d992a77e56892ecb65e7854c7898fb7d35e9b33bd/websockets-16.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:95724e638f0f9c350bb1c2b0a7ad0e83d9cc0c9259f3ea94e40d7b02a2179ae5", size = 184975, upload-time = "2026-01-10T09:23:03.756Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f9/66/27ea52741752f5107c2e41fda05e8395a682a1e11c4e592a809a90c6a506/websockets-16.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0204dc62a89dc9d50d682412c10b3542d748260d743500a85c13cd1ee4bde82", size = 186203, upload-time = "2026-01-10T09:23:05.01Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/37/e5/8e32857371406a757816a2b471939d51c463509be73fa538216ea52b792a/websockets-16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:52ac480f44d32970d66763115edea932f1c5b1312de36df06d6b219f6741eed8", size = 185653, upload-time = "2026-01-10T09:23:06.301Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9b/67/f926bac29882894669368dc73f4da900fcdf47955d0a0185d60103df5737/websockets-16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6e5a82b677f8f6f59e8dfc34ec06ca6b5b48bc4fcda346acd093694cc2c24d8f", size = 184920, upload-time = "2026-01-10T09:23:07.492Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3c/a1/3d6ccdcd125b0a42a311bcd15a7f705d688f73b2a22d8cf1c0875d35d34a/websockets-16.0-cp313-cp313-win32.whl", hash = "sha256:abf050a199613f64c886ea10f38b47770a65154dc37181bfaff70c160f45315a", size = 178255, upload-time = "2026-01-10T09:23:09.245Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6b/ae/90366304d7c2ce80f9b826096a9e9048b4bb760e44d3b873bb272cba696b/websockets-16.0-cp313-cp313-win_amd64.whl", hash = "sha256:3425ac5cf448801335d6fdc7ae1eb22072055417a96cc6b31b3861f455fbc156", size = 178689, upload-time = "2026-01-10T09:23:10.483Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f3/1d/e88022630271f5bd349ed82417136281931e558d628dd52c4d8621b4a0b2/websockets-16.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8cc451a50f2aee53042ac52d2d053d08bf89bcb31ae799cb4487587661c038a0", size = 177406, upload-time = "2026-01-10T09:23:12.178Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f2/78/e63be1bf0724eeb4616efb1ae1c9044f7c3953b7957799abb5915bffd38e/websockets-16.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:daa3b6ff70a9241cf6c7fc9e949d41232d9d7d26fd3522b1ad2b4d62487e9904", size = 175085, upload-time = "2026-01-10T09:23:13.511Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bb/f4/d3c9220d818ee955ae390cf319a7c7a467beceb24f05ee7aaaa2414345ba/websockets-16.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:fd3cb4adb94a2a6e2b7c0d8d05cb94e6f1c81a0cf9dc2694fb65c7e8d94c42e4", size = 175328, upload-time = "2026-01-10T09:23:14.727Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/63/bc/d3e208028de777087e6fb2b122051a6ff7bbcca0d6df9d9c2bf1dd869ae9/websockets-16.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:781caf5e8eee67f663126490c2f96f40906594cb86b408a703630f95550a8c3e", size = 185044, upload-time = "2026-01-10T09:23:15.939Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ad/6e/9a0927ac24bd33a0a9af834d89e0abc7cfd8e13bed17a86407a66773cc0e/websockets-16.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:caab51a72c51973ca21fa8a18bd8165e1a0183f1ac7066a182ff27107b71e1a4", size = 186279, upload-time = "2026-01-10T09:23:17.148Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b9/ca/bf1c68440d7a868180e11be653c85959502efd3a709323230314fda6e0b3/websockets-16.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:19c4dc84098e523fd63711e563077d39e90ec6702aff4b5d9e344a60cb3c0cb1", size = 185711, upload-time = "2026-01-10T09:23:18.372Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c4/f8/fdc34643a989561f217bb477cbc47a3a07212cbda91c0e4389c43c296ebf/websockets-16.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a5e18a238a2b2249c9a9235466b90e96ae4795672598a58772dd806edc7ac6d3", size = 184982, upload-time = "2026-01-10T09:23:19.652Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/dd/d1/574fa27e233764dbac9c52730d63fcf2823b16f0856b3329fc6268d6ae4f/websockets-16.0-cp314-cp314-win32.whl", hash = "sha256:a069d734c4a043182729edd3e9f247c3b2a4035415a9172fd0f1b71658a320a8", size = 177915, upload-time = "2026-01-10T09:23:21.458Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8a/f1/ae6b937bf3126b5134ce1f482365fde31a357c784ac51852978768b5eff4/websockets-16.0-cp314-cp314-win_amd64.whl", hash = "sha256:c0ee0e63f23914732c6d7e0cce24915c48f3f1512ec1d079ed01fc629dab269d", size = 178381, upload-time = "2026-01-10T09:23:22.715Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/06/9b/f791d1db48403e1f0a27577a6beb37afae94254a8c6f08be4a23e4930bc0/websockets-16.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:a35539cacc3febb22b8f4d4a99cc79b104226a756aa7400adc722e83b0d03244", size = 177737, upload-time = "2026-01-10T09:23:24.523Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bd/40/53ad02341fa33b3ce489023f635367a4ac98b73570102ad2cdd770dacc9a/websockets-16.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:b784ca5de850f4ce93ec85d3269d24d4c82f22b7212023c974c401d4980ebc5e", size = 175268, upload-time = "2026-01-10T09:23:25.781Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:569d01a4e7fba956c5ae4fc988f0d4e187900f5497ce46339c996dbf24f17641", size = 175486, upload-time = "2026-01-10T09:23:27.033Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e5/2d/7583b30208b639c8090206f95073646c2c9ffd66f44df967981a64f849ad/websockets-16.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:50f23cdd8343b984957e4077839841146f67a3d31ab0d00e6b824e74c5b2f6e8", size = 185331, upload-time = "2026-01-10T09:23:28.259Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/45/b0/cce3784eb519b7b5ad680d14b9673a31ab8dcb7aad8b64d81709d2430aa8/websockets-16.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:152284a83a00c59b759697b7f9e9cddf4e3c7861dd0d964b472b70f78f89e80e", size = 186501, upload-time = "2026-01-10T09:23:29.449Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/19/60/b8ebe4c7e89fb5f6cdf080623c9d92789a53636950f7abacfc33fe2b3135/websockets-16.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bc59589ab64b0022385f429b94697348a6a234e8ce22544e3681b2e9331b5944", size = 186062, upload-time = "2026-01-10T09:23:31.368Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/88/a8/a080593f89b0138b6cba1b28f8df5673b5506f72879322288b031337c0b8/websockets-16.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:32da954ffa2814258030e5a57bc73a3635463238e797c7375dc8091327434206", size = 185356, upload-time = "2026-01-10T09:23:32.627Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c2/b6/b9afed2afadddaf5ebb2afa801abf4b0868f42f8539bfe4b071b5266c9fe/websockets-16.0-cp314-cp314t-win32.whl", hash = "sha256:5a4b4cc550cb665dd8a47f868c8d04c8230f857363ad3c9caf7a0c3bf8c61ca6", size = 178085, upload-time = "2026-01-10T09:23:33.816Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9f/3e/28135a24e384493fa804216b79a6a6759a38cc4ff59118787b9fb693df93/websockets-16.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b14dc141ed6d2dde437cddb216004bcac6a1df0935d79656387bd41632ba0bbd", size = 178531, upload-time = "2026-01-10T09:23:35.016Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6f/28/258ebab549c2bf3e64d2b0217b973467394a9cea8c42f70418ca2c5d0d2e/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec", size = 171598, upload-time = "2026-01-10T09:23:45.395Z" },
|
||||||
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user