Compare commits
23 Commits
5b2d5655d8
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 64ee9797ff | |||
| b13606dcbf | |||
| e48c22e0f7 | |||
| c10d785bfa | |||
| da8716cccc | |||
| e667af9201 | |||
| 02d9e06077 | |||
| 5dbbeb3394 | |||
| 94cb2441e2 | |||
| 502992f69d | |||
| c31a9c01b6 | |||
| 5b04a6aac4 | |||
| c395492583 | |||
| 10f2da14a1 | |||
| a7af0faefc | |||
| 1eef99e3b4 | |||
| c5a563f047 | |||
| 47aeebd86f | |||
| 21933cdef9 | |||
| 34a8ce730a | |||
| 3073c4e4b5 | |||
| b5ebedb2b9 | |||
| 37c3bf0aeb |
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
__pycache__/*
|
||||||
|
*.pyc
|
||||||
|
cookies/*
|
||||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/pymd3_vue_location_sim.iml" filepath="$PROJECT_DIR$/.idea/pymd3_vue_location_sim.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
15
.idea/pymd3_vue_location_sim.iml
generated
Normal file
15
.idea/pymd3_vue_location_sim.iml
generated
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module external.system.id="pyproject.toml" type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="jdk" jdkName="uv (pymd3_vue_location_sim)" jdkType="Python SDK" />
|
||||||
|
</component>
|
||||||
|
<component name="PyDocumentationSettings">
|
||||||
|
<option name="format" value="PLAIN" />
|
||||||
|
<option name="myDocStringFormat" value="Plain" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
1
.python-version
Normal file
1
.python-version
Normal file
@@ -0,0 +1 @@
|
|||||||
|
3.14
|
||||||
BIN
__pycache__/main.cpython-314.pyc
Normal file
BIN
__pycache__/main.cpython-314.pyc
Normal file
Binary file not shown.
BIN
__pycache__/server.cpython-314.pyc
Normal file
BIN
__pycache__/server.cpython-314.pyc
Normal file
Binary file not shown.
BIN
geocache.db
Normal file
BIN
geocache.db
Normal file
Binary file not shown.
50
main.bk
50
main.bk
@@ -1,50 +0,0 @@
|
|||||||
from flask import Flask, request, jsonify
|
|
||||||
from flask_cors import CORS
|
|
||||||
|
|
||||||
app = Flask(__name__, static_folder="../front-end/dist/assets", template_folder="../front-end/dist")
|
|
||||||
CORS(app)
|
|
||||||
|
|
||||||
@app.route('/')
|
|
||||||
def index():
|
|
||||||
return app.send_static_file('index.html')
|
|
||||||
|
|
||||||
# Essential for handling client-side routing (e.g., Vue Router history mode)
|
|
||||||
@app.route('/<path:path>')
|
|
||||||
def static_files(path):
|
|
||||||
return app.send_static_file(path)
|
|
||||||
|
|
||||||
@app.route('/api/set', methods=['POST'])
|
|
||||||
def handle_json_data():
|
|
||||||
data = request.get_json()
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return jsonify({'error': 'Missing JSON data'}), 400
|
|
||||||
|
|
||||||
if 'lat' not in data:
|
|
||||||
return jsonify({'error': 'Missing lat in JSON data'}), 400
|
|
||||||
|
|
||||||
if 'lng' not in data:
|
|
||||||
return jsonify({'error': 'Missing lng in JSON data'}), 400
|
|
||||||
|
|
||||||
# Process the data (e.g., save to a database)
|
|
||||||
lat = data['lat']
|
|
||||||
lng = data['lng']
|
|
||||||
|
|
||||||
# Return a JSON response
|
|
||||||
return jsonify({
|
|
||||||
'message': f'lat: {lat}, lng: {lng} received successfully!',
|
|
||||||
'data': data
|
|
||||||
}), 200
|
|
||||||
|
|
||||||
@app.route('/api/status', methods=['GET'])
|
|
||||||
def get_data():
|
|
||||||
return jsonify(message="Hello from Flask API!")
|
|
||||||
|
|
||||||
@app.errorhandler(404)
|
|
||||||
def not_found(error):
|
|
||||||
return jsonify({'error': 'Not found'}), 404
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
app.run(debug=True, host='0.0.0.0', port=5000)
|
|
||||||
48
main.py
48
main.py
@@ -1,48 +1,18 @@
|
|||||||
import asyncio
|
|
||||||
import dataclasses
|
|
||||||
import json
|
|
||||||
import logging
|
|
||||||
import random
|
|
||||||
import sys
|
|
||||||
import socketio
|
|
||||||
import tempfile
|
import tempfile
|
||||||
from contextlib import nullcontext
|
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from pathlib import Path
|
from typing import Annotated
|
||||||
from typing import Annotated, Optional, TextIO
|
|
||||||
|
|
||||||
import typer
|
import typer
|
||||||
from typer_injector import InjectingTyper
|
import os
|
||||||
|
|
||||||
from pymobiledevice3.bonjour import DEFAULT_BONJOUR_TIMEOUT, browse_remotepairing_manual_pairing
|
from pymobiledevice3.remote.common import TunnelProtocol
|
||||||
from pymobiledevice3.cli.cli_common import (
|
from pymobiledevice3.remote.module_imports import verify_tunnel_imports
|
||||||
RSDServiceProviderDep,
|
|
||||||
async_command,
|
|
||||||
print_json,
|
|
||||||
prompt_device_list,
|
|
||||||
sudo_required,
|
|
||||||
user_requested_colored_output,
|
|
||||||
)
|
|
||||||
from pymobiledevice3.common import get_home_folder
|
|
||||||
from pymobiledevice3.exceptions import NoDeviceConnectedError
|
|
||||||
from pymobiledevice3.pair_records import PAIRING_RECORD_EXT, get_remote_pairing_record_filename
|
|
||||||
from pymobiledevice3.remote.common import ConnectionType, TunnelProtocol
|
|
||||||
from pymobiledevice3.remote.module_imports import MAX_IDLE_TIMEOUT, start_tunnel, verify_tunnel_imports
|
|
||||||
from pymobiledevice3.remote.remote_service_discovery import RSD_PORT
|
|
||||||
from pymobiledevice3.remote.tunnel_service import (
|
|
||||||
RemotePairingManualPairingService,
|
|
||||||
get_core_device_tunnel_services,
|
|
||||||
get_remote_pairing_tunnel_services,
|
|
||||||
)
|
|
||||||
from pymobiledevice3.remote.utils import get_rsds
|
|
||||||
from pymobiledevice3.tunneld.api import TUNNELD_DEFAULT_ADDRESS
|
from pymobiledevice3.tunneld.api import TUNNELD_DEFAULT_ADDRESS
|
||||||
from pymobiledevice3.utils import run_in_loop
|
from src.pymd3_vue_location_sim.server import TunneldRunnerSio, LocationSimulationState
|
||||||
from server import TunneldRunnerSio, LocationSimulationState, logger
|
from src.pymd3_vue_location_sim.json_formatter import logger
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
cli_tunneld(host="0.0.0.0", port=8000)
|
port = int(os.getenv("PORT", 49151))
|
||||||
|
cli_tunneld(host="0.0.0.0", port=port)
|
||||||
|
|
||||||
def cli_tunneld(
|
def cli_tunneld(
|
||||||
host: Annotated[str, typer.Option(help="Address to bind the tunneld server to.")] = TUNNELD_DEFAULT_ADDRESS[0],
|
host: Annotated[str, typer.Option(help="Address to bind the tunneld server to.")] = TUNNELD_DEFAULT_ADDRESS[0],
|
||||||
@@ -93,4 +63,4 @@ def cli_tunneld(
|
|||||||
|
|
||||||
# 4. Entry point (always last)
|
# 4. Entry point (always last)
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
@@ -1,12 +1,27 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "back-end"
|
name = "pymd3_vue_location_sim"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
requires-python = ">=3.14"
|
requires-python = ">=3.14"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"click>=8.3.1",
|
||||||
|
"daemonize>=2.5.0",
|
||||||
"fastapi==0.135.1",
|
"fastapi==0.135.1",
|
||||||
|
"geopy[aiohttp]==2.4.1",
|
||||||
|
"httpx>=0.28.1",
|
||||||
|
"numpy==2.4.3",
|
||||||
"pydantic==2.12.5",
|
"pydantic==2.12.5",
|
||||||
"pymobiledevice3==9.0.0",
|
"pyicloud>=2.4.1",
|
||||||
|
"pymobiledevice3==9.8.1",
|
||||||
|
"python-dotenv>=1.2.2",
|
||||||
"python-socketio==5.16.1",
|
"python-socketio==5.16.1",
|
||||||
|
"sqlalchemy>=2.0.48",
|
||||||
|
"sqlalchemy-orm>=1.2.10",
|
||||||
|
"typer>=0.24.1",
|
||||||
"typing==3.10.0.0",
|
"typing==3.10.0.0",
|
||||||
"uvicorn==0.41.0",
|
"uvicorn==0.41.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["uv_build>=0.11.2,<0.12"]
|
||||||
|
build-backend = "uv_build"
|
||||||
|
|||||||
568
server.py
568
server.py
@@ -1,568 +0,0 @@
|
|||||||
import asyncio
|
|
||||||
import dataclasses
|
|
||||||
import json
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import signal
|
|
||||||
import traceback
|
|
||||||
import warnings
|
|
||||||
import fastapi
|
|
||||||
import random
|
|
||||||
from fastapi import FastAPI
|
|
||||||
from typing import Optional
|
|
||||||
import socketio
|
|
||||||
from contextlib import asynccontextmanager, suppress
|
|
||||||
from ssl import SSLEOFError
|
|
||||||
from typing import Optional, Union
|
|
||||||
|
|
||||||
import construct
|
|
||||||
|
|
||||||
from pymobiledevice3.bonjour import browse_remoted
|
|
||||||
from pymobiledevice3.cli.cli_common import print_json
|
|
||||||
|
|
||||||
with warnings.catch_warnings():
|
|
||||||
# Ignore: "Core Pydantic V1 functionality isn't compatible with Python 3.14 or greater."
|
|
||||||
warnings.simplefilter("ignore", category=UserWarning)
|
|
||||||
import fastapi
|
|
||||||
|
|
||||||
import uvicorn
|
|
||||||
from construct import StreamError
|
|
||||||
from fastapi import FastAPI
|
|
||||||
from packaging.version import Version
|
|
||||||
|
|
||||||
from pymobiledevice3 import usbmux
|
|
||||||
from pymobiledevice3.exceptions import (
|
|
||||||
ConnectionFailedError,
|
|
||||||
ConnectionFailedToUsbmuxdError,
|
|
||||||
ConnectionTerminatedError,
|
|
||||||
DeviceNotFoundError,
|
|
||||||
GetProhibitedError,
|
|
||||||
IncorrectModeError,
|
|
||||||
InvalidServiceError,
|
|
||||||
LockdownError,
|
|
||||||
MuxException,
|
|
||||||
PairingError,
|
|
||||||
QuicProtocolNotSupportedError,
|
|
||||||
StreamClosedError,
|
|
||||||
TunneldConnectionError
|
|
||||||
)
|
|
||||||
from pymobiledevice3.lockdown import create_using_usbmux, get_mobdev2_lockdowns
|
|
||||||
from pymobiledevice3.osu.os_utils import get_os_utils
|
|
||||||
from pymobiledevice3.remote.common import TunnelProtocol
|
|
||||||
from pymobiledevice3.remote.module_imports import start_tunnel
|
|
||||||
from pymobiledevice3.remote.remote_service_discovery import RSD_PORT, RemoteServiceDiscoveryService
|
|
||||||
from pymobiledevice3.remote.tunnel_service import (
|
|
||||||
CoreDeviceTunnelProxy,
|
|
||||||
RemotePairingProtocol,
|
|
||||||
TunnelResult,
|
|
||||||
create_core_device_tunnel_service_using_rsd,
|
|
||||||
get_remote_pairing_tunnel_services,
|
|
||||||
)
|
|
||||||
from pymobiledevice3.remote.utils import get_rsds, stop_remoted
|
|
||||||
from pymobiledevice3.utils import asyncio_print_traceback
|
|
||||||
from pymobiledevice3.services.dvt.instruments.location_simulation import LocationSimulation
|
|
||||||
from pymobiledevice3.services.dvt.instruments.dvt_provider import DvtProvider
|
|
||||||
from pymobiledevice3.tunneld.server import TunneldCore, TunnelTask
|
|
||||||
from pymobiledevice3.tunneld.api import (
|
|
||||||
TUNNELD_DEFAULT_ADDRESS,
|
|
||||||
get_tunneld_device_by_udid,
|
|
||||||
get_tunneld_devices,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class JsonFormatter(logging.Formatter):
|
|
||||||
def format(self, record: logging.LogRecord) -> str:
|
|
||||||
payload = {
|
|
||||||
"ts": self.formatTime(record, "%Y-%m-%dT%H:%M:%S%z"),
|
|
||||||
"level": record.levelname,
|
|
||||||
"logger": record.name,
|
|
||||||
"message": record.getMessage(),
|
|
||||||
}
|
|
||||||
if record.exc_info:
|
|
||||||
payload["exc_info"] = self.formatException(record.exc_info)
|
|
||||||
return json.dumps(payload, ensure_ascii=True)
|
|
||||||
|
|
||||||
|
|
||||||
handler = logging.StreamHandler()
|
|
||||||
handler.setFormatter(JsonFormatter())
|
|
||||||
root_logger = logging.getLogger()
|
|
||||||
root_logger.handlers = [handler]
|
|
||||||
root_logger.setLevel(logging.INFO)
|
|
||||||
logger = logging.getLogger("ios-api")
|
|
||||||
|
|
||||||
# bugfix: after the device reboots, it might take some time for remoted to start answering the bonjour queries
|
|
||||||
REATTEMPT_INTERVAL = 5
|
|
||||||
REATTEMPT_COUNT = 5
|
|
||||||
|
|
||||||
REMOTEPAIRING_INTERVAL = 5
|
|
||||||
MOBDEV2_INTERVAL = 5
|
|
||||||
|
|
||||||
# USB monitor will periodically forget what interfaces it has seen
|
|
||||||
# and force a full rescan. The value is number of iterations of the
|
|
||||||
# inner loop (which sleeps one second each) before blowing away the
|
|
||||||
# `previous_ips` cache.
|
|
||||||
USB_MONITOR_RESCAN_INTERVAL = 30
|
|
||||||
|
|
||||||
USBMUX_INTERVAL = 2
|
|
||||||
OSUTILS = get_os_utils()
|
|
||||||
TUNNEL_ACQUIRE_TIMEOUT_SECONDS = 15
|
|
||||||
DVT_CONNECT_TIMEOUT_SECONDS = 20
|
|
||||||
|
|
||||||
|
|
||||||
class LocationSimulationState:
|
|
||||||
def __init__(self):
|
|
||||||
self.latitude: Optional[float] = None
|
|
||||||
self.longitude: Optional[float] = None
|
|
||||||
self.udid: Optional[str] = None
|
|
||||||
self.simulation_active: bool = False
|
|
||||||
self.queue: asyncio.Queue = asyncio.Queue()
|
|
||||||
self.simulation_task: Optional[asyncio.Task] = None
|
|
||||||
self.sio: socketio.AsyncServer = socketio.AsyncServer(async_mode="asgi", cors_allowed_origins="*")
|
|
||||||
|
|
||||||
|
|
||||||
class TunneldRunnerSio:
|
|
||||||
"""TunneldRunner orchestrate between the webserver and TunneldCore"""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def create(
|
|
||||||
cls,
|
|
||||||
host: str,
|
|
||||||
port: int,
|
|
||||||
context: LocationSimulationState = LocationSimulationState(),
|
|
||||||
protocol: TunnelProtocol = TunnelProtocol.QUIC,
|
|
||||||
usb_monitor: bool = True,
|
|
||||||
wifi_monitor: bool = True,
|
|
||||||
usbmux_monitor: bool = True,
|
|
||||||
mobdev2_monitor: bool = True,
|
|
||||||
) -> None:
|
|
||||||
cls(
|
|
||||||
host,
|
|
||||||
port,
|
|
||||||
protocol=protocol,
|
|
||||||
usb_monitor=usb_monitor,
|
|
||||||
wifi_monitor=wifi_monitor,
|
|
||||||
usbmux_monitor=usbmux_monitor,
|
|
||||||
mobdev2_monitor=mobdev2_monitor,
|
|
||||||
context=context,
|
|
||||||
)._run_app()
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
host: str,
|
|
||||||
port: int,
|
|
||||||
context: LocationSimulationState = LocationSimulationState(),
|
|
||||||
protocol: TunnelProtocol = TunnelProtocol.QUIC,
|
|
||||||
usb_monitor: bool = True,
|
|
||||||
wifi_monitor: bool = True,
|
|
||||||
usbmux_monitor: bool = True,
|
|
||||||
mobdev2_monitor: bool = True,
|
|
||||||
):
|
|
||||||
@asynccontextmanager
|
|
||||||
async def lifespan(app: FastAPI):
|
|
||||||
self._tunneld_core.start()
|
|
||||||
yield
|
|
||||||
logger.info("Closing tunneld tasks...")
|
|
||||||
await empty_queue()
|
|
||||||
await self._tunneld_core.close()
|
|
||||||
await self.context.sio.shutdown()
|
|
||||||
|
|
||||||
self.host = host
|
|
||||||
self.port = port
|
|
||||||
self.protocol = protocol
|
|
||||||
self.context = context
|
|
||||||
self._tunneld_api_address = ("127.0.0.1" if host in ("0.0.0.0", "::") else host, port)
|
|
||||||
self._app = FastAPI(title="iOS Device Management API", lifespan=lifespan, cors_allowed_origins="*")
|
|
||||||
self._asgi_app = socketio.ASGIApp(self.context.sio, self._app)
|
|
||||||
self._tunneld_core = TunneldCore(
|
|
||||||
protocol=protocol,
|
|
||||||
wifi_monitor=wifi_monitor,
|
|
||||||
usb_monitor=usb_monitor,
|
|
||||||
usbmux_monitor=usbmux_monitor,
|
|
||||||
mobdev2_monitor=mobdev2_monitor,
|
|
||||||
)
|
|
||||||
|
|
||||||
async def get_tun(
|
|
||||||
udid: Optional[str] = None, max_retries: int = 10, retry_delay: float = 0.5
|
|
||||||
) -> RemoteServiceDiscoveryService:
|
|
||||||
"""Try to connect to tunneld with retries to handle startup delay."""
|
|
||||||
for attempt in range(max_retries):
|
|
||||||
try:
|
|
||||||
if udid:
|
|
||||||
rsd = await get_tunneld_device_by_udid(udid, self._tunneld_api_address)
|
|
||||||
if rsd is not None:
|
|
||||||
logger.info("Connected to tunnel for udid %s after %s retries", udid, attempt)
|
|
||||||
return rsd
|
|
||||||
|
|
||||||
rsds = await get_tunneld_devices(self._tunneld_api_address)
|
|
||||||
if rsds:
|
|
||||||
if udid:
|
|
||||||
logger.warning("Tunnel for udid %s not found; using first available tunnel", udid)
|
|
||||||
logger.info("Connected to tunneld after %s retries", attempt)
|
|
||||||
return rsds[0]
|
|
||||||
except TunneldConnectionError:
|
|
||||||
if attempt < max_retries - 1:
|
|
||||||
logger.info("Waiting for tunneld to be ready... (attempt %s/%s)", attempt + 1, max_retries)
|
|
||||||
await asyncio.sleep(retry_delay)
|
|
||||||
else:
|
|
||||||
logger.error("Failed to connect to tunneld after max retries")
|
|
||||||
raise
|
|
||||||
raise TunneldConnectionError()
|
|
||||||
|
|
||||||
async def empty_queue():
|
|
||||||
"""Empties all items from an asyncio.Queue."""
|
|
||||||
logger.info("Clearing location simulation queue... resetting ios location")
|
|
||||||
q = self.context.queue
|
|
||||||
while not q.empty():
|
|
||||||
try:
|
|
||||||
q.get_nowait()
|
|
||||||
q.task_done()
|
|
||||||
await q.join()
|
|
||||||
except asyncio.QueueEmpty:
|
|
||||||
break
|
|
||||||
tun = await get_tun(self.context.udid)
|
|
||||||
if tun is not None:
|
|
||||||
async with DvtProvider(tun) as dvt, LocationSimulationQueue(dvt, self.context) as locate_simulation:
|
|
||||||
await locate_simulation.clear()
|
|
||||||
self.context.simulation_active = False
|
|
||||||
|
|
||||||
async def start_queue():
|
|
||||||
logger.info("Starting location simulation worker...")
|
|
||||||
self.context.simulation_active = True
|
|
||||||
try:
|
|
||||||
if self.context.udid is None:
|
|
||||||
active_udids = sorted(
|
|
||||||
{t.udid for t in self._tunneld_core.tunnel_tasks.values() if t.udid is not None and t.tunnel is not None}
|
|
||||||
)
|
|
||||||
if len(active_udids) == 1:
|
|
||||||
self.context.udid = active_udids[0]
|
|
||||||
logger.info("Simulation worker: auto-selected udid=%s from active tunnel", self.context.udid)
|
|
||||||
elif len(active_udids) == 0:
|
|
||||||
logger.error("Simulation worker: no active tunnel with udid available")
|
|
||||||
await self.context.sio.emit(
|
|
||||||
"error",
|
|
||||||
{"type": "simulation_no_tunnel", "message": "No active tunnel found. Start tunnel first."},
|
|
||||||
namespace="/",
|
|
||||||
)
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
logger.error("Simulation worker: multiple active tunnels; explicit udid required: %s", active_udids)
|
|
||||||
await self.context.sio.emit(
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"type": "simulation_udid_required",
|
|
||||||
"message": "Multiple active tunnels found; provide udid in start_simulate_location.",
|
|
||||||
"udids": active_udids,
|
|
||||||
},
|
|
||||||
namespace="/",
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
logger.info("Simulation worker: acquiring tunnel (udid=%s)", self.context.udid)
|
|
||||||
tun = await asyncio.wait_for(
|
|
||||||
get_tun(self.context.udid),
|
|
||||||
timeout=TUNNEL_ACQUIRE_TIMEOUT_SECONDS,
|
|
||||||
)
|
|
||||||
logger.info("Simulation worker: tunnel acquired, connecting DVT provider")
|
|
||||||
dvt_provider = DvtProvider(tun)
|
|
||||||
dvt = await asyncio.wait_for(dvt_provider.__aenter__(), timeout=DVT_CONNECT_TIMEOUT_SECONDS)
|
|
||||||
logger.info("Simulation worker: DVT provider connected, starting queue playback")
|
|
||||||
try:
|
|
||||||
async with LocationSimulationQueue(dvt, self.context) as locate_simulation:
|
|
||||||
await locate_simulation.play_queue()
|
|
||||||
finally:
|
|
||||||
logger.info("Simulation worker: closing DVT provider")
|
|
||||||
await dvt_provider.__aexit__(None, None, None)
|
|
||||||
logger.info("Simulation worker: DVT provider closed")
|
|
||||||
except TimeoutError:
|
|
||||||
logger.error(
|
|
||||||
"Simulation worker timeout. tunnel_timeout=%ss dvt_timeout=%ss udid=%s",
|
|
||||||
TUNNEL_ACQUIRE_TIMEOUT_SECONDS,
|
|
||||||
DVT_CONNECT_TIMEOUT_SECONDS,
|
|
||||||
self.context.udid,
|
|
||||||
)
|
|
||||||
await self.context.sio.emit(
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"type": "simulation_timeout",
|
|
||||||
"udid": self.context.udid,
|
|
||||||
"tunnel_timeout_seconds": TUNNEL_ACQUIRE_TIMEOUT_SECONDS,
|
|
||||||
"dvt_timeout_seconds": DVT_CONNECT_TIMEOUT_SECONDS,
|
|
||||||
},
|
|
||||||
namespace="/",
|
|
||||||
)
|
|
||||||
except Exception:
|
|
||||||
logger.exception("Simulation worker crashed")
|
|
||||||
await self.context.sio.emit(
|
|
||||||
"error",
|
|
||||||
{"type": "simulation_crash", "udid": self.context.udid},
|
|
||||||
namespace="/",
|
|
||||||
)
|
|
||||||
finally:
|
|
||||||
self.context.simulation_active = False
|
|
||||||
self.context.simulation_task = None
|
|
||||||
|
|
||||||
def iterate_multidim(d):
|
|
||||||
mydict = {}
|
|
||||||
for key, value in d.items():
|
|
||||||
if isinstance(value, dict):
|
|
||||||
iterate_multidim(value)
|
|
||||||
elif isinstance(value, str) or isinstance(value, int) or isinstance(value, float) or isinstance(value, bool) or isinstance(value, list):
|
|
||||||
mydict[key] = value
|
|
||||||
else:
|
|
||||||
mydict[key] = ''
|
|
||||||
return mydict
|
|
||||||
|
|
||||||
@self._app.get("/")
|
|
||||||
@self.context.sio.event
|
|
||||||
async def list_tunnels() -> dict[str, list[dict]]:
|
|
||||||
"""Retrieve the available tunnels and format them as {UUID: TUNNEL_ADDRESS}"""
|
|
||||||
tunnels = {}
|
|
||||||
for ip, active_tunnel in self._tunneld_core.tunnel_tasks.items():
|
|
||||||
if (active_tunnel.udid is None) or (active_tunnel.tunnel is None):
|
|
||||||
continue
|
|
||||||
if active_tunnel.udid not in tunnels:
|
|
||||||
tunnels[active_tunnel.udid] = []
|
|
||||||
tunnels[active_tunnel.udid].append({
|
|
||||||
"tunnel-address": active_tunnel.tunnel.address,
|
|
||||||
"tunnel-port": active_tunnel.tunnel.port,
|
|
||||||
"interface": ip,
|
|
||||||
})
|
|
||||||
return tunnels
|
|
||||||
|
|
||||||
@self._app.get("/device_info")
|
|
||||||
async def device_info():
|
|
||||||
"""Get device information"""
|
|
||||||
tunnels = {}
|
|
||||||
for ip, active_tunnel in self._tunneld_core.tunnel_tasks.items():
|
|
||||||
if (active_tunnel.udid is None) or (active_tunnel.tunnel is None):
|
|
||||||
continue
|
|
||||||
if active_tunnel.udid not in tunnels:
|
|
||||||
tunnels[active_tunnel.udid] = {}
|
|
||||||
try:
|
|
||||||
lockdown = await create_using_usbmux(serial=active_tunnel.udid, autopair=False)
|
|
||||||
tunnels[active_tunnel.udid] = iterate_multidim(lockdown.all_values)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Failed to create lockdown session for device {active_tunnel.udid}: {e}")
|
|
||||||
continue
|
|
||||||
return tunnels
|
|
||||||
|
|
||||||
@self._app.get("/shutdown")
|
|
||||||
async def shutdown() -> fastapi.Response:
|
|
||||||
"""Shutdown Tunneld"""
|
|
||||||
os.kill(os.getpid(), signal.SIGINT)
|
|
||||||
data = {"operation": "shutdown", "data": True, "message": "Server shutting down..."}
|
|
||||||
return generate_http_response(data)
|
|
||||||
|
|
||||||
@self._app.get("/clear_tunnels")
|
|
||||||
async def clear_tunnels() -> fastapi.Response:
|
|
||||||
self._tunneld_core.clear()
|
|
||||||
data = {"operation": "clear_tunnels", "data": True, "message": "Cleared tunnels..."}
|
|
||||||
return generate_http_response(data)
|
|
||||||
|
|
||||||
@self._app.get("/cancel")
|
|
||||||
async def cancel_tunnel(udid: str) -> fastapi.Response:
|
|
||||||
self._tunneld_core.cancel(udid=udid)
|
|
||||||
data = {"operation": "cancel", "udid": udid, "data": True, "message": f"tunnel {udid} Canceled ..."}
|
|
||||||
return generate_http_response(data)
|
|
||||||
|
|
||||||
@self._app.get("/hello")
|
|
||||||
async def hello() -> fastapi.Response:
|
|
||||||
data = {"message": "Hello, I'm alive"}
|
|
||||||
return generate_http_response(data)
|
|
||||||
|
|
||||||
def generate_http_response(
|
|
||||||
data: dict, status_code: int = 200, media_type: str = "application/json"
|
|
||||||
) -> fastapi.Response:
|
|
||||||
return fastapi.Response(status_code=status_code, media_type=media_type, content=json.dumps(data))
|
|
||||||
|
|
||||||
@self._app.get("/start-tunnel")
|
|
||||||
@self.context.sio.event
|
|
||||||
async def start_tunnel(
|
|
||||||
udid: str, ip: Optional[str] = None, connection_type: Optional[str] = None
|
|
||||||
) -> fastapi.Response:
|
|
||||||
udid_tunnels = [
|
|
||||||
t.tunnel for t in self._tunneld_core.tunnel_tasks.values() if t.udid == udid and t.tunnel is not None
|
|
||||||
]
|
|
||||||
if len(udid_tunnels) > 0:
|
|
||||||
self.context.udid = udid
|
|
||||||
data = {
|
|
||||||
"interface": udid_tunnels[0].interface,
|
|
||||||
"port": udid_tunnels[0].port,
|
|
||||||
"address": udid_tunnels[0].address,
|
|
||||||
}
|
|
||||||
return generate_http_response(data)
|
|
||||||
|
|
||||||
queue = asyncio.Queue()
|
|
||||||
created_task = False
|
|
||||||
|
|
||||||
try:
|
|
||||||
if not created_task and connection_type in ("usbmux", None):
|
|
||||||
task_identifier = f"usbmux-{udid}"
|
|
||||||
try:
|
|
||||||
async with await create_using_usbmux(udid) as lockdown:
|
|
||||||
service = await CoreDeviceTunnelProxy.create(lockdown)
|
|
||||||
task = asyncio.create_task(
|
|
||||||
self._tunneld_core.start_tunnel_task(
|
|
||||||
task_identifier, service, protocol=TunnelProtocol.TCP, queue=queue
|
|
||||||
),
|
|
||||||
name=f"start-tunnel-task-{task_identifier}",
|
|
||||||
)
|
|
||||||
self._tunneld_core.tunnel_tasks[task_identifier] = TunnelTask(task=task, udid=udid)
|
|
||||||
created_task = True
|
|
||||||
except (ConnectionFailedError, InvalidServiceError, MuxException):
|
|
||||||
pass
|
|
||||||
if connection_type in ("usb", None):
|
|
||||||
for rsd in await get_rsds(udid=udid):
|
|
||||||
rsd_ip = rsd.service.address[0]
|
|
||||||
if ip is not None and rsd_ip != ip:
|
|
||||||
await rsd.close()
|
|
||||||
continue
|
|
||||||
task = asyncio.create_task(
|
|
||||||
self._tunneld_core.start_tunnel_task(
|
|
||||||
rsd_ip, await create_core_device_tunnel_service_using_rsd(rsd), queue=queue
|
|
||||||
),
|
|
||||||
name=f"start-tunnel-usb-{rsd_ip}",
|
|
||||||
)
|
|
||||||
self._tunneld_core.tunnel_tasks[rsd_ip] = TunnelTask(task=task, udid=rsd.udid)
|
|
||||||
created_task = True
|
|
||||||
if not created_task and connection_type in ("wifi", None):
|
|
||||||
for remotepairing in await get_remote_pairing_tunnel_services(udid=udid):
|
|
||||||
remotepairing_ip = remotepairing.hostname
|
|
||||||
if ip is not None and remotepairing_ip != ip:
|
|
||||||
await remotepairing.close()
|
|
||||||
continue
|
|
||||||
task = asyncio.create_task(
|
|
||||||
self._tunneld_core.start_tunnel_task(remotepairing_ip, remotepairing, queue=queue),
|
|
||||||
name=f"start-tunnel-wifi-{remotepairing_ip}",
|
|
||||||
)
|
|
||||||
self._tunneld_core.tunnel_tasks[remotepairing_ip] = TunnelTask(
|
|
||||||
task=task, udid=remotepairing.remote_identifier
|
|
||||||
)
|
|
||||||
created_task = True
|
|
||||||
except Exception as e:
|
|
||||||
return fastapi.Response(
|
|
||||||
status_code=501,
|
|
||||||
content=json.dumps({
|
|
||||||
"error": {
|
|
||||||
"exception": e.__class__.__name__,
|
|
||||||
"traceback": traceback.format_exc(),
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
if not created_task:
|
|
||||||
return fastapi.Response(status_code=501, content=json.dumps({"error": "task not created"}))
|
|
||||||
|
|
||||||
tunnel: Optional[TunnelResult] = await queue.get()
|
|
||||||
if tunnel is not None:
|
|
||||||
self.context.udid = udid
|
|
||||||
data = {"interface": tunnel.interface, "port": tunnel.port, "address": tunnel.address}
|
|
||||||
return generate_http_response(data)
|
|
||||||
else:
|
|
||||||
return fastapi.Response(
|
|
||||||
status_code=404, content=json.dumps({"error": "something went wrong during tunnel creation"})
|
|
||||||
)
|
|
||||||
|
|
||||||
@self.context.sio.event
|
|
||||||
async def connect(sid, environ):
|
|
||||||
logger.info("Client connected: %s", sid)
|
|
||||||
await self.context.sio.emit("connect", sid, namespace="/")
|
|
||||||
|
|
||||||
@self.context.sio.event
|
|
||||||
async def request_update(sid, data):
|
|
||||||
logger.info("Update request from %s", sid)
|
|
||||||
|
|
||||||
# await self.context.sio.emit("status_update", await get_status())
|
|
||||||
|
|
||||||
@self.context.sio.event
|
|
||||||
async def message(sid, data):
|
|
||||||
logger.info("Received message from %s: %s", data, sid)
|
|
||||||
await self.context.sio.emit("message", f"Received message from {sid}: {data}", namespace="/")
|
|
||||||
|
|
||||||
@self.context.sio.event
|
|
||||||
async def simulate_location(sid, data):
|
|
||||||
logger.info("Simulate location request from %s: %s", sid, data)
|
|
||||||
latitude = data.get("latitude") if isinstance(data, dict) else getattr(data, "latitude", None)
|
|
||||||
longitude = data.get("longitude") if isinstance(data, dict) else getattr(data, "longitude", None)
|
|
||||||
delay = data.get("delay", 0) if isinstance(data, dict) else getattr(data, "delay", 0)
|
|
||||||
if latitude is not None and longitude is not None:
|
|
||||||
logger.info("Adding location %s, %s with %ss delay to the queue", latitude, longitude, delay)
|
|
||||||
await self.context.queue.put((latitude, longitude, delay))
|
|
||||||
await self.context.sio.emit("simulation", {"status": self.context.simulation_active,
|
|
||||||
"data": {"latitude": self.context.latitude,
|
|
||||||
"cur_longitude": longitude, "next_move": delay}},
|
|
||||||
namespace="/")
|
|
||||||
else:
|
|
||||||
logger.warning("Invalid location data received from %s: %s", sid, data)
|
|
||||||
await self.context.sio.emit("error", "Invalid location data", namespace="/")
|
|
||||||
|
|
||||||
@self.context.sio.event
|
|
||||||
async def start_simulate_location(sid, data):
|
|
||||||
logger.info("Start location simulation request from %s", sid)
|
|
||||||
if isinstance(data, dict) and data.get("udid"):
|
|
||||||
self.context.udid = data["udid"]
|
|
||||||
if self.context.simulation_task is None or self.context.simulation_task.done():
|
|
||||||
self.context.simulation_active = True
|
|
||||||
self.context.simulation_task = asyncio.create_task(
|
|
||||||
start_queue(),
|
|
||||||
name="location-simulation-worker",
|
|
||||||
)
|
|
||||||
await self.context.sio.emit("simulation", {"status": self.context.simulation_active, "data": None},
|
|
||||||
namespace="/")
|
|
||||||
|
|
||||||
@self.context.sio.event
|
|
||||||
async def end_simulate_location(sid, data):
|
|
||||||
logger.info("End location simulation request from %s", sid)
|
|
||||||
if self.context.simulation_task is not None and not self.context.simulation_task.done():
|
|
||||||
await self.context.queue.put((None, None, None))
|
|
||||||
with suppress(asyncio.CancelledError):
|
|
||||||
await self.context.simulation_task
|
|
||||||
await empty_queue()
|
|
||||||
await self.context.sio.emit("simulation", {"status": self.context.simulation_active, "data": None},
|
|
||||||
namespace="/")
|
|
||||||
|
|
||||||
@self.context.sio.event
|
|
||||||
async def disconnect(sid):
|
|
||||||
logger.info("Client disconnected: %s", sid)
|
|
||||||
|
|
||||||
@self.context.sio.event
|
|
||||||
async def start_tunneld(sid, data):
|
|
||||||
logger.info("Start tunneld request from %s: %s", sid, data)
|
|
||||||
try:
|
|
||||||
self._tunneld_core.start()
|
|
||||||
logger.info("Tunneld started successfully")
|
|
||||||
except Exception as e:
|
|
||||||
logger.error("Error starting tunneld: %s", e)
|
|
||||||
|
|
||||||
def _run_app(self) -> None:
|
|
||||||
uvicorn.run(self._asgi_app, host=self.host, port=self.port, loop="asyncio", workers=1)
|
|
||||||
|
|
||||||
|
|
||||||
class LocationSimulationQueue(LocationSimulation):
|
|
||||||
def __init__(self, dvt, context: LocationSimulationState):
|
|
||||||
super().__init__(dvt)
|
|
||||||
self.context = context
|
|
||||||
|
|
||||||
async def play_queue(self, disable_sleep: bool = False, timing_randomness_range: int = 0) -> None:
|
|
||||||
while True:
|
|
||||||
latitude, longitude, delay = await self.context.queue.get()
|
|
||||||
if (latitude, longitude, delay) == (None, None, None):
|
|
||||||
break
|
|
||||||
if delay > 0 and not disable_sleep:
|
|
||||||
if timing_randomness_range > 0:
|
|
||||||
delay = delay + random.uniform(-timing_randomness_range, timing_randomness_range)
|
|
||||||
for i in range(delay, 0, -1):
|
|
||||||
await self.context.sio.emit("simulation", {"status": self.context.simulation_active,
|
|
||||||
"data": {"latitude": self.context.latitude,
|
|
||||||
"longitude": self.context.longitude,
|
|
||||||
"next_move": i}}, namespace="/")
|
|
||||||
await asyncio.sleep(1)
|
|
||||||
await self.set(latitude, longitude)
|
|
||||||
self.context.latitude = latitude
|
|
||||||
self.context.longitude = longitude
|
|
||||||
await self.context.sio.emit("simulation", {"status": self.context.simulation_active,
|
|
||||||
"data": {"latitude": self.context.latitude,
|
|
||||||
"longitude": self.context.longitude,
|
|
||||||
"next_move": None}}, namespace="/")
|
|
||||||
logger.info("Set simulated location to %s, %s after %ss delay", latitude, longitude, delay)
|
|
||||||
self.context.queue.task_done()
|
|
||||||
75
socktest.py
75
socktest.py
@@ -1,75 +0,0 @@
|
|||||||
import socketio
|
|
||||||
from fastapi import FastAPI
|
|
||||||
from fastapi.responses import HTMLResponse
|
|
||||||
|
|
||||||
# 1. Create the FastAPI app
|
|
||||||
app = FastAPI()
|
|
||||||
|
|
||||||
# 2. Create the Socket.IO server (Async mode for FastAPI)
|
|
||||||
sio = socketio.AsyncServer(async_mode='asgi', cors_allowed_origins='*')
|
|
||||||
|
|
||||||
# 3. Wrap FastAPI with Socket.IO
|
|
||||||
# This allows 'socket_app' to handle socket traffic and pass
|
|
||||||
# everything else to 'app'
|
|
||||||
socket_app = socketio.ASGIApp(sio, app)
|
|
||||||
|
|
||||||
# --- Socket.IO Events ---
|
|
||||||
|
|
||||||
@sio.event
|
|
||||||
async def connect(sid, environ):
|
|
||||||
print(f"Client connected: {sid}")
|
|
||||||
await sio.emit('response', {'data': 'Connected to Server!'})
|
|
||||||
|
|
||||||
@sio.event
|
|
||||||
async def message(sid, data):
|
|
||||||
print(f"Received from {sid}: {data}")
|
|
||||||
# Broadcast to everyone (including sender)
|
|
||||||
await sio.emit('response', {'data': f"Echo: {data}"})
|
|
||||||
|
|
||||||
@sio.event
|
|
||||||
async def disconnect(sid):
|
|
||||||
print(f"Client disconnected: {sid}")
|
|
||||||
|
|
||||||
# --- FastAPI Routes ---
|
|
||||||
|
|
||||||
html_client = """
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>FastAPI Socket.IO Test</title>
|
|
||||||
<!-- Load Socket.IO Client from CDN -->
|
|
||||||
<script src="https://cdn.socket.io/4.7.5/socket.io.min.js"></script>
|
|
||||||
<script>
|
|
||||||
const socket = io();
|
|
||||||
|
|
||||||
socket.on('connect', () => {
|
|
||||||
document.getElementById('status').innerText = 'Connected: ' + socket.id;
|
|
||||||
document.getElementById('status').style.color = 'green';
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on('response', (data) => {
|
|
||||||
const li = document.createElement("li");
|
|
||||||
li.innerText = JSON.stringify(data);
|
|
||||||
document.getElementById("messages").appendChild(li);
|
|
||||||
});
|
|
||||||
|
|
||||||
function sendMessage() {
|
|
||||||
const input = document.getElementById("msg");
|
|
||||||
socket.emit('message', input.value);
|
|
||||||
input.value = "";
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>Socket.IO Test</h1>
|
|
||||||
<h3 id="status" style="color:red">Disconnected</h3>
|
|
||||||
<input id="msg" type="text" placeholder="Type a message..." />
|
|
||||||
<button onclick="sendMessage()">Send</button>
|
|
||||||
<ul id="messages"></ul>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
"""
|
|
||||||
|
|
||||||
@app.get("/")
|
|
||||||
async def index():
|
|
||||||
return HTMLResponse(html_client)
|
|
||||||
0
src/__init__.py
Normal file
0
src/__init__.py
Normal file
0
src/pymd3_vue_location_sim/__init__.py
Normal file
0
src/pymd3_vue_location_sim/__init__.py
Normal file
138
src/pymd3_vue_location_sim/geo_cache.py
Normal file
138
src/pymd3_vue_location_sim/geo_cache.py
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
import logging
|
||||||
|
import sqlite3
|
||||||
|
import json
|
||||||
|
from geopy.geocoders import Nominatim
|
||||||
|
from geopy.adapters import AioHTTPAdapter
|
||||||
|
from geopy.extra.rate_limiter import AsyncRateLimiter
|
||||||
|
|
||||||
|
logger = logging.getLogger("ios-api")
|
||||||
|
CACHE_LOOKUP_SQL = "SELECT address, favorite FROM location_cache WHERE lat_lon = ?"
|
||||||
|
CACHE_UPSERT_SQL = """
|
||||||
|
INSERT INTO location_cache (lat_lon, address)
|
||||||
|
VALUES (?, ?)
|
||||||
|
ON CONFLICT(lat_lon) DO UPDATE SET address = excluded.address
|
||||||
|
"""
|
||||||
|
FAVORITE_LOOKUP_SQL = "SELECT favorite FROM location_cache WHERE favorite IS NOT NULL"
|
||||||
|
FAVORITE_UPSERT_SQL = """
|
||||||
|
INSERT INTO location_cache (lat_lon, favorite)
|
||||||
|
VALUES (?, ?)
|
||||||
|
ON CONFLICT(lat_lon) DO UPDATE SET favorite = excluded.favorite
|
||||||
|
"""
|
||||||
|
FAVORITE_CLEAR_SQL = "UPDATE location_cache SET favorite = NULL WHERE lat_lon = ?"
|
||||||
|
|
||||||
|
|
||||||
|
class AsyncReverseGeocoder:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
db_path: str = "geocache.db",
|
||||||
|
user_agent: str = "pymd3_vue_location_sim/0.1.0 (iam@williambr.uno)",
|
||||||
|
):
|
||||||
|
self.db_path = db_path
|
||||||
|
self.user_agent = user_agent
|
||||||
|
self._init_db()
|
||||||
|
|
||||||
|
def _init_db(self) -> None:
|
||||||
|
"""Initializes the SQLite database."""
|
||||||
|
with sqlite3.connect(self.db_path) as conn:
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute('''
|
||||||
|
CREATE TABLE IF NOT EXISTS location_cache (
|
||||||
|
lat_lon TEXT PRIMARY KEY,
|
||||||
|
address TEXT,
|
||||||
|
favorite TEXT
|
||||||
|
|
||||||
|
)
|
||||||
|
''')
|
||||||
|
cursor.execute("PRAGMA table_info(location_cache)")
|
||||||
|
columns = {row[1] for row in cursor.fetchall()}
|
||||||
|
if "favorite" not in columns:
|
||||||
|
cursor.execute("ALTER TABLE location_cache ADD COLUMN favorite TEXT")
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _cache_key(lat: float, lon: float) -> str:
|
||||||
|
return f"{lat:.5f},{lon:.5f}"
|
||||||
|
|
||||||
|
def _read_cached_address(self, key: str) -> dict | None:
|
||||||
|
with sqlite3.connect(self.db_path) as conn:
|
||||||
|
cursor = conn.execute(CACHE_LOOKUP_SQL, (key,))
|
||||||
|
row = cursor.fetchone()
|
||||||
|
cached = {}
|
||||||
|
if row:
|
||||||
|
cached['address'] = json.loads(row[0]) if row[0] else {}
|
||||||
|
cached['favorite'] = json.loads(row[1]) if row[1] else {}
|
||||||
|
return cached if row else None
|
||||||
|
|
||||||
|
def _store_cached_address(self, key: str, address_data: dict) -> None:
|
||||||
|
with sqlite3.connect(self.db_path) as conn:
|
||||||
|
conn.execute(CACHE_UPSERT_SQL, (key, json.dumps(address_data)))
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
def _read_favorites(self) -> list | None:
|
||||||
|
with sqlite3.connect(self.db_path) as conn:
|
||||||
|
cursor = conn.execute(FAVORITE_LOOKUP_SQL)
|
||||||
|
rows = cursor.fetchall()
|
||||||
|
favorites = [json.loads(row[0]) for row in rows if row[0]]
|
||||||
|
return favorites if favorites else None
|
||||||
|
|
||||||
|
async def clear_favorite(self, lat: float, lon: float) -> bool:
|
||||||
|
key = self._cache_key(lat, lon)
|
||||||
|
cached = self._read_cached_address(key)
|
||||||
|
if cached and cached.get("favorite"):
|
||||||
|
favorite = cached.get("favorite")
|
||||||
|
name = favorite.get("name") if isinstance(favorite, dict) else key
|
||||||
|
logger.info("Clearing favorite %s", name)
|
||||||
|
with sqlite3.connect(self.db_path) as conn:
|
||||||
|
cursor = conn.execute(FAVORITE_CLEAR_SQL, (key,))
|
||||||
|
conn.commit()
|
||||||
|
return cursor.rowcount > 0
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def set_favorite(self, lat: float, lon: float, favorite_data: dict) -> bool:
|
||||||
|
key = self._cache_key(lat, lon)
|
||||||
|
name = favorite_data.get("name")
|
||||||
|
if not name:
|
||||||
|
return False
|
||||||
|
logger.info("Setting favorite location %s to location_cache for %s", name, key)
|
||||||
|
try:
|
||||||
|
with sqlite3.connect(self.db_path) as conn:
|
||||||
|
conn.execute(FAVORITE_UPSERT_SQL, (key, json.dumps(favorite_data)))
|
||||||
|
conn.commit()
|
||||||
|
return True
|
||||||
|
except sqlite3.Error as e:
|
||||||
|
logger.exception("Failed to set favorite location %s to location_cache for %s: %s", name, key, e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def get_favorites(self) -> list | None:
|
||||||
|
"""Reverse geocode with SQLite cache."""
|
||||||
|
logger.info("Checking location_cache for favorites")
|
||||||
|
favorites = self._read_favorites()
|
||||||
|
return favorites
|
||||||
|
|
||||||
|
async def get_address(self, lat: float, lon: float) -> dict | None:
|
||||||
|
"""Reverse geocode with SQLite cache."""
|
||||||
|
key = self._cache_key(lat, lon)
|
||||||
|
cached_address = self._read_cached_address(key)
|
||||||
|
if cached_address is not None:
|
||||||
|
logger.info("Found cached address for %s", key)
|
||||||
|
return cached_address
|
||||||
|
|
||||||
|
async with Nominatim(
|
||||||
|
user_agent=self.user_agent,
|
||||||
|
adapter_factory=AioHTTPAdapter
|
||||||
|
) as geolocator:
|
||||||
|
try:
|
||||||
|
reverse = AsyncRateLimiter(
|
||||||
|
geolocator.reverse, min_delay_seconds=1)
|
||||||
|
location = await reverse(key)
|
||||||
|
if location:
|
||||||
|
response = {}
|
||||||
|
logger.info("Nominatim response: %s", location)
|
||||||
|
response['address'] = location.raw.get("address", {})
|
||||||
|
self._store_cached_address(key, response['address'])
|
||||||
|
return response
|
||||||
|
return None
|
||||||
|
except Exception:
|
||||||
|
logger.exception("Reverse geocoding failed for key=%s", key)
|
||||||
|
return None
|
||||||
342
src/pymd3_vue_location_sim/icloud_monitor.py
Normal file
342
src/pymd3_vue_location_sim/icloud_monitor.py
Normal file
@@ -0,0 +1,342 @@
|
|||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import textwrap
|
||||||
|
from collections.abc import Callable
|
||||||
|
|
||||||
|
import click
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from pyicloud import PyiCloudService
|
||||||
|
from pyicloud.exceptions import (
|
||||||
|
PyiCloud2FARequiredException,
|
||||||
|
PyiCloud2SARequiredException,
|
||||||
|
PyiCloudAuthRequiredException,
|
||||||
|
PyiCloudFailedLoginException,
|
||||||
|
PyiCloudNoStoredPasswordAvailableException,
|
||||||
|
PyiCloudPasswordException,
|
||||||
|
)
|
||||||
|
|
||||||
|
from .models import ICloudReturnData
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
logger = logging.getLogger("ios-api")
|
||||||
|
COOKIE_DIRECTORY = "./cookies"
|
||||||
|
ENV_APPLE_ID = "APPLE_ID"
|
||||||
|
ENV_APPLE_PW = "APPLE_PW"
|
||||||
|
ENV_SELECTED_DEVICE_ID = "SELECTED_DEVICE_ID"
|
||||||
|
ENV_SELECTED_DEVICE_NAME = "SELECTED_DEVICE_NAME"
|
||||||
|
ENV_AUTH_INIT_TIMEOUT = "ICLOUD_AUTH_INIT_TIMEOUT_SECONDS"
|
||||||
|
BACKOFF_SCHEDULE = (15, 30, 60, 120, 300)
|
||||||
|
AUTH_EXCEPTIONS = (
|
||||||
|
PyiCloudAuthRequiredException,
|
||||||
|
PyiCloudFailedLoginException,
|
||||||
|
PyiCloudPasswordException,
|
||||||
|
PyiCloud2FARequiredException,
|
||||||
|
PyiCloud2SARequiredException,
|
||||||
|
PyiCloudNoStoredPasswordAvailableException,
|
||||||
|
)
|
||||||
|
|
||||||
|
class FindMyMonitor:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
queue: asyncio.Queue,
|
||||||
|
token_file: str = "icloud_token.txt",
|
||||||
|
sio=None,
|
||||||
|
get_client_sids: Callable[[], list[str]] | None = None,
|
||||||
|
code_timeout_seconds: int = 180,
|
||||||
|
):
|
||||||
|
self.username = os.getenv(ENV_APPLE_ID)
|
||||||
|
self.password = os.getenv(ENV_APPLE_PW)
|
||||||
|
self.token_file = token_file
|
||||||
|
self.selected_device_id = os.getenv(ENV_SELECTED_DEVICE_ID)
|
||||||
|
self.selected_device_name = os.getenv(ENV_SELECTED_DEVICE_NAME)
|
||||||
|
self.selected_device = None
|
||||||
|
self.queue = queue
|
||||||
|
self.api = None
|
||||||
|
self.device = None
|
||||||
|
self.running = True
|
||||||
|
self.sio = sio
|
||||||
|
self.get_client_sids = get_client_sids
|
||||||
|
self.code_timeout_seconds = code_timeout_seconds
|
||||||
|
self.auth_init_timeout_seconds = int(
|
||||||
|
os.getenv(ENV_AUTH_INIT_TIMEOUT, "0")
|
||||||
|
)
|
||||||
|
self._logged_candidates = False
|
||||||
|
self._no_location_streak = 0
|
||||||
|
self._auth_error_streak = 0
|
||||||
|
self._fetch_lock = asyncio.Lock()
|
||||||
|
|
||||||
|
async def _create_api_session(self, has_token: bool) -> bool:
|
||||||
|
try:
|
||||||
|
init_args = [self.username]
|
||||||
|
if not has_token:
|
||||||
|
init_args.append(self.password)
|
||||||
|
init_task = asyncio.to_thread(
|
||||||
|
PyiCloudService, *init_args, cookie_directory=COOKIE_DIRECTORY
|
||||||
|
)
|
||||||
|
if self.auth_init_timeout_seconds > 0:
|
||||||
|
self.api = await asyncio.wait_for(
|
||||||
|
init_task, timeout=self.auth_init_timeout_seconds
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.api = await init_task
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
source = "cookies" if has_token else "credentials"
|
||||||
|
logger.exception("Failed to initialize iCloud session from %s", source)
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def _request_code_from_vue(self, prompt: str) -> str | None:
|
||||||
|
if self.sio is None or self.get_client_sids is None:
|
||||||
|
logger.warning("2FA request skipped: Socket.IO context not configured")
|
||||||
|
return None
|
||||||
|
sids = self.get_client_sids()
|
||||||
|
if not sids:
|
||||||
|
logger.warning("2FA request skipped: no connected Socket.IO clients")
|
||||||
|
return None
|
||||||
|
|
||||||
|
payload = {"prompt": prompt, "digits": 6}
|
||||||
|
logger.info("Emitting icloud_2fa_request to %s connected client(s)", len(sids))
|
||||||
|
for sid in sids:
|
||||||
|
try:
|
||||||
|
# Ask one connected UI client for the code and wait for ACK response.
|
||||||
|
response = await self.sio.call(
|
||||||
|
"icloud_2fa_request",
|
||||||
|
payload,
|
||||||
|
to=sid,
|
||||||
|
namespace="/",
|
||||||
|
timeout=self.code_timeout_seconds,
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
logger.exception("Failed to retrieve 2FA code from sid=%s", sid)
|
||||||
|
continue
|
||||||
|
|
||||||
|
code = response.get("code") if isinstance(response, dict) else response
|
||||||
|
code_str = str(code).strip() if code is not None else ""
|
||||||
|
if len(code_str) == 6 and code_str.isdigit():
|
||||||
|
return code_str
|
||||||
|
logger.warning("Invalid 2FA code payload from sid=%s", sid)
|
||||||
|
return None
|
||||||
|
|
||||||
|
async def authenticate(self) -> bool:
|
||||||
|
"""Authenticates with iCloud, handling 2FA and token storage."""
|
||||||
|
if not self.username:
|
||||||
|
logger.warning("APPLE_ID is not configured; skipping iCloud monitor authentication")
|
||||||
|
return False
|
||||||
|
has_token = os.path.exists(self.token_file)
|
||||||
|
if not has_token and not self.password:
|
||||||
|
logger.warning(
|
||||||
|
"No stored iCloud session and APPLE_PW is not configured; skipping iCloud monitor authentication"
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
"Initializing iCloud session from %s",
|
||||||
|
"stored cookies" if has_token else "credentials",
|
||||||
|
)
|
||||||
|
if not await self._create_api_session(has_token=has_token):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if self.api.requires_2fa:
|
||||||
|
logger.info("Two-factor authentication required.")
|
||||||
|
code = await self._request_code_from_vue("Enter the 6-digit Apple verification code")
|
||||||
|
if code is None:
|
||||||
|
if sys.stdin and sys.stdin.isatty():
|
||||||
|
code = str(
|
||||||
|
await asyncio.to_thread(
|
||||||
|
click.prompt,
|
||||||
|
"Please enter the 6-digit code sent to your trusted device",
|
||||||
|
type=int,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
logger.warning(
|
||||||
|
"2FA required but no interactive terminal or Vue responder is available; deferring authentication"
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
result = await asyncio.to_thread(self.api.validate_2fa_code, code)
|
||||||
|
logger.info("2FA validation result: %s", result)
|
||||||
|
|
||||||
|
if not result:
|
||||||
|
logger.warning("Failed to verify 2FA code")
|
||||||
|
return False
|
||||||
|
|
||||||
|
await asyncio.to_thread(self.api.trust_session)
|
||||||
|
|
||||||
|
if self.api.requires_2sa:
|
||||||
|
logger.info(textwrap.dedent("""
|
||||||
|
Two-step authentication required.
|
||||||
|
Please select a device to receive a SMS verification code:
|
||||||
|
"""))
|
||||||
|
for i, device in enumerate(self.api.trusted_devices):
|
||||||
|
logger.info(
|
||||||
|
" %s: %s (%s)",
|
||||||
|
i + 1,
|
||||||
|
device.get("deviceName", "Unknown device"),
|
||||||
|
device.get("phoneNumber", "Unknown number"),
|
||||||
|
)
|
||||||
|
|
||||||
|
if not (sys.stdin and sys.stdin.isatty()):
|
||||||
|
logger.warning(
|
||||||
|
"2SA required but no interactive terminal is available; deferring authentication"
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
device_index = await asyncio.to_thread(click.prompt, "Please select a device number", type=int) - 1
|
||||||
|
device = self.api.trusted_devices[device_index]
|
||||||
|
if not await asyncio.to_thread(self.api.send_verification_code, device):
|
||||||
|
logger.warning("Failed to send verification code")
|
||||||
|
return False
|
||||||
|
|
||||||
|
code = await asyncio.to_thread(click.prompt, "Please enter verification code", type=int)
|
||||||
|
if not await asyncio.to_thread(self.api.validate_verification_code, device, code):
|
||||||
|
logger.warning("Failed to verify verification code")
|
||||||
|
return False
|
||||||
|
|
||||||
|
logger.info("Successfully authenticated.")
|
||||||
|
return True
|
||||||
|
|
||||||
|
async def get_location(self) -> ICloudReturnData | None:
|
||||||
|
"""Fetches the latest latitude and longitude."""
|
||||||
|
if not self.api:
|
||||||
|
await self.authenticate()
|
||||||
|
|
||||||
|
# pyicloud 2.4.1 refresh lives on the FindMy manager, not PyiCloudService.
|
||||||
|
devices_manager = await asyncio.to_thread(lambda: self.api.devices)
|
||||||
|
await asyncio.to_thread(devices_manager.refresh, True)
|
||||||
|
|
||||||
|
# One-time diagnostics to help verify exact device selection among duplicates.
|
||||||
|
if not self._logged_candidates:
|
||||||
|
for d in devices_manager:
|
||||||
|
status = d.status()
|
||||||
|
logger.debug(
|
||||||
|
"iCloud candidate id=%s name=%s model=%s deviceStatus=%s has_location=%s features=%s",
|
||||||
|
d.data.get("id"),
|
||||||
|
d.name,
|
||||||
|
d.model_name,
|
||||||
|
status.get("deviceStatus"),
|
||||||
|
d.data.get("location") is not None,
|
||||||
|
d.data.get("features"),
|
||||||
|
)
|
||||||
|
self._logged_candidates = True
|
||||||
|
|
||||||
|
# Select by ID first (exact), then by name, then first device if no selectors set.
|
||||||
|
self.selected_device = None
|
||||||
|
for device in devices_manager:
|
||||||
|
if self.selected_device_id and device.data.get("id") == self.selected_device_id:
|
||||||
|
self.selected_device = device
|
||||||
|
break
|
||||||
|
if self.selected_device is None:
|
||||||
|
for device in devices_manager:
|
||||||
|
if self.selected_device_name and device.name == self.selected_device_name:
|
||||||
|
self.selected_device = device
|
||||||
|
break
|
||||||
|
if self.selected_device is None and not self.selected_device_id and not self.selected_device_name:
|
||||||
|
for device in devices_manager:
|
||||||
|
self.selected_device = device
|
||||||
|
break
|
||||||
|
|
||||||
|
if self.selected_device:
|
||||||
|
location = self.selected_device.location
|
||||||
|
status = self.selected_device.status()
|
||||||
|
logger.info(
|
||||||
|
"iCloud device=%s location_available=%s status=%s",
|
||||||
|
self.selected_device.name,
|
||||||
|
self.selected_device.location_available,
|
||||||
|
status,
|
||||||
|
)
|
||||||
|
if location:
|
||||||
|
data = {
|
||||||
|
"latitude": location['latitude'],
|
||||||
|
"longitude": location['longitude'],
|
||||||
|
"timeStamp": location['timeStamp'],
|
||||||
|
"altitude": location['altitude'],
|
||||||
|
"horizontalAccuracy": location['horizontalAccuracy'],
|
||||||
|
"verticalAccuracy": location['verticalAccuracy'],
|
||||||
|
"batteryLevel": status['batteryLevel'],
|
||||||
|
"deviceDisplayName": status['deviceDisplayName'],
|
||||||
|
"deviceStatus": status['deviceStatus'],
|
||||||
|
"name": status['name']
|
||||||
|
}
|
||||||
|
response = ICloudReturnData(**data)
|
||||||
|
return response
|
||||||
|
logger.info("Location payload is None for device=%s", self.selected_device.name)
|
||||||
|
return None
|
||||||
|
|
||||||
|
logger.warning(
|
||||||
|
"No iCloud device matched SELECTED_DEVICE_ID='%s' or SELECTED_DEVICE_NAME='%s'.",
|
||||||
|
self.selected_device_id,
|
||||||
|
self.selected_device_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
self.running = True
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.running = False
|
||||||
|
|
||||||
|
def _no_location_backoff_seconds(self, base_interval: int) -> int:
|
||||||
|
idx = min(self._no_location_streak - 1, len(BACKOFF_SCHEDULE) - 1)
|
||||||
|
return max(base_interval, BACKOFF_SCHEDULE[idx])
|
||||||
|
|
||||||
|
def _auth_backoff_seconds(self, base_interval: int) -> int:
|
||||||
|
idx = min(self._auth_error_streak - 1, len(BACKOFF_SCHEDULE) - 1)
|
||||||
|
return max(base_interval, BACKOFF_SCHEDULE[idx])
|
||||||
|
|
||||||
|
async def refresh_location(self):
|
||||||
|
"""Fetch one location update while serializing iCloud API access."""
|
||||||
|
async with self._fetch_lock:
|
||||||
|
return await self.get_location()
|
||||||
|
|
||||||
|
async def run_monitor(self, interval=60):
|
||||||
|
"""Runs the monitor loop."""
|
||||||
|
if not await self.authenticate():
|
||||||
|
return
|
||||||
|
|
||||||
|
if not self.running:
|
||||||
|
self.start()
|
||||||
|
|
||||||
|
while self.running:
|
||||||
|
sleep_seconds = interval
|
||||||
|
try:
|
||||||
|
device_data = await self.refresh_location()
|
||||||
|
if device_data is not None:
|
||||||
|
self._no_location_streak = 0
|
||||||
|
self._auth_error_streak = 0
|
||||||
|
logger.info(
|
||||||
|
"%s - Location: %s, %s",
|
||||||
|
device_data.timeStamp,
|
||||||
|
device_data.latitude,
|
||||||
|
device_data.longitude,
|
||||||
|
)
|
||||||
|
await self.queue.put(device_data)
|
||||||
|
else:
|
||||||
|
self._no_location_streak += 1
|
||||||
|
sleep_seconds = self._no_location_backoff_seconds(interval)
|
||||||
|
logger.info(
|
||||||
|
"No iCloud location found for device id='%s' name='%s' streak=%s next_retry=%ss",
|
||||||
|
self.selected_device_id,
|
||||||
|
self.selected_device_name,
|
||||||
|
self._no_location_streak,
|
||||||
|
sleep_seconds,
|
||||||
|
)
|
||||||
|
except AUTH_EXCEPTIONS as e:
|
||||||
|
self._auth_error_streak += 1
|
||||||
|
sleep_seconds = self._auth_backoff_seconds(interval)
|
||||||
|
logger.warning(
|
||||||
|
"iCloud auth error (%s). Re-authenticating; streak=%s next_retry=%ss",
|
||||||
|
type(e).__name__,
|
||||||
|
self._auth_error_streak,
|
||||||
|
sleep_seconds,
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
await self.authenticate()
|
||||||
|
except Exception:
|
||||||
|
logger.exception("iCloud re-authentication failed")
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception("iCloud monitor loop error: %s", e)
|
||||||
|
sleep_seconds = max(interval, 30)
|
||||||
|
|
||||||
|
await asyncio.sleep(sleep_seconds)
|
||||||
18
src/pymd3_vue_location_sim/json_formatter.py
Normal file
18
src/pymd3_vue_location_sim/json_formatter.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import logging
|
||||||
|
import json
|
||||||
|
|
||||||
|
handler = logging.StreamHandler()
|
||||||
|
root_logger = logging.getLogger()
|
||||||
|
logger = logging.getLogger("ios-api")
|
||||||
|
|
||||||
|
class JsonFormatter(logging.Formatter):
|
||||||
|
def format(self, record: logging.LogRecord) -> str:
|
||||||
|
payload = {
|
||||||
|
"ts": self.formatTime(record, "%Y-%m-%dT%H:%M:%S%z"),
|
||||||
|
"level": record.levelname,
|
||||||
|
"logger": record.name,
|
||||||
|
"message": record.getMessage(),
|
||||||
|
}
|
||||||
|
if record.exc_info:
|
||||||
|
payload["exc_info"] = self.formatException(record.exc_info)
|
||||||
|
return json.dumps(payload, ensure_ascii=True)
|
||||||
82
src/pymd3_vue_location_sim/models.py
Normal file
82
src/pymd3_vue_location_sim/models.py
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class Coordinate(BaseModel):
|
||||||
|
latitude: float
|
||||||
|
longitude: float
|
||||||
|
|
||||||
|
|
||||||
|
class ScheduledCoordinate(Coordinate):
|
||||||
|
delay: int = 0
|
||||||
|
start: Optional[str] = None
|
||||||
|
end: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
|
class SimulationStatusData(Coordinate):
|
||||||
|
start: float
|
||||||
|
end: Optional[float] = None
|
||||||
|
next_move: Optional[float] = None
|
||||||
|
|
||||||
|
|
||||||
|
class SimulationStatus(BaseModel):
|
||||||
|
status: bool
|
||||||
|
data: Optional[SimulationStatusData] = None
|
||||||
|
|
||||||
|
|
||||||
|
class SimulationRequestData(ScheduledCoordinate):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class SimulationRequest(BaseModel):
|
||||||
|
status: bool
|
||||||
|
data: Optional[SimulationRequestData] = None
|
||||||
|
|
||||||
|
|
||||||
|
class SimulationRequestResponseData(ScheduledCoordinate):
|
||||||
|
loc_id: str
|
||||||
|
|
||||||
|
|
||||||
|
class SimulationQueueList(BaseModel):
|
||||||
|
data: Optional[SimulationRequestResponseData] = None
|
||||||
|
|
||||||
|
|
||||||
|
class SimulationRequestResponse(BaseModel):
|
||||||
|
status: bool
|
||||||
|
data: Optional[SimulationRequestResponseData] = None
|
||||||
|
|
||||||
|
|
||||||
|
class SimulationQueueDict(BaseModel):
|
||||||
|
location_id: dict[str, SimulationRequestResponseData]
|
||||||
|
|
||||||
|
|
||||||
|
class ICloudLocationData(Coordinate):
|
||||||
|
timestamp: str
|
||||||
|
|
||||||
|
|
||||||
|
class ICloudReturnData(Coordinate):
|
||||||
|
timeStamp: int
|
||||||
|
altitude: float
|
||||||
|
horizontalAccuracy: float
|
||||||
|
verticalAccuracy: float
|
||||||
|
batteryLevel: float
|
||||||
|
deviceDisplayName: str
|
||||||
|
deviceStatus: int
|
||||||
|
name: str
|
||||||
|
|
||||||
|
|
||||||
|
class LatLng(Coordinate):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ORSRequest(BaseModel):
|
||||||
|
geometry_simplify: bool
|
||||||
|
coordinates: list[list[float]]
|
||||||
|
|
||||||
|
|
||||||
|
# Backward compatibility aliases for existing imports.
|
||||||
|
iCloudLocationData = ICloudLocationData
|
||||||
|
iCloudReturnData = ICloudReturnData
|
||||||
2504
src/pymd3_vue_location_sim/server.py
Normal file
2504
src/pymd3_vue_location_sim/server.py
Normal file
File diff suppressed because it is too large
Load Diff
684
uv.lock
generated
684
uv.lock
generated
@@ -2,6 +2,78 @@ version = 1
|
|||||||
revision = 3
|
revision = 3
|
||||||
requires-python = ">=3.14"
|
requires-python = ">=3.14"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aiohappyeyeballs"
|
||||||
|
version = "2.6.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aiohttp"
|
||||||
|
version = "3.13.5"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "aiohappyeyeballs" },
|
||||||
|
{ name = "aiosignal" },
|
||||||
|
{ name = "attrs" },
|
||||||
|
{ name = "frozenlist" },
|
||||||
|
{ name = "multidict" },
|
||||||
|
{ name = "propcache" },
|
||||||
|
{ name = "yarl" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/77/9a/152096d4808df8e4268befa55fba462f440f14beab85e8ad9bf990516918/aiohttp-3.13.5.tar.gz", hash = "sha256:9d98cc980ecc96be6eb4c1994ce35d28d8b1f5e5208a23b421187d1209dbb7d1", size = 7858271, upload-time = "2026-03-31T22:01:03.343Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5d/ce/46572759afc859e867a5bc8ec3487315869013f59281ce61764f76d879de/aiohttp-3.13.5-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:eb4639f32fd4a9904ab8fb45bf3383ba71137f3d9d4ba25b3b3f3109977c5b8c", size = 745721, upload-time = "2026-03-31T21:58:50.229Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/13/fe/8a2efd7626dbe6049b2ef8ace18ffda8a4dfcbe1bcff3ac30c0c7575c20b/aiohttp-3.13.5-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:7e5dc4311bd5ac493886c63cbf76ab579dbe4641268e7c74e48e774c74b6f2be", size = 497663, upload-time = "2026-03-31T21:58:52.232Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9b/91/cc8cc78a111826c54743d88651e1687008133c37e5ee615fee9b57990fac/aiohttp-3.13.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:756c3c304d394977519824449600adaf2be0ccee76d206ee339c5e76b70ded25", size = 499094, upload-time = "2026-03-31T21:58:54.566Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0a/33/a8362cb15cf16a3af7e86ed11962d5cd7d59b449202dc576cdc731310bde/aiohttp-3.13.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecc26751323224cf8186efcf7fbcbc30f4e1d8c7970659daf25ad995e4032a56", size = 1726701, upload-time = "2026-03-31T21:58:56.864Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/45/0c/c091ac5c3a17114bd76cbf85d674650969ddf93387876cf67f754204bd77/aiohttp-3.13.5-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10a75acfcf794edf9d8db50e5a7ec5fc818b2a8d3f591ce93bc7b1210df016d2", size = 1683360, upload-time = "2026-03-31T21:58:59.072Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/23/73/bcee1c2b79bc275e964d1446c55c54441a461938e70267c86afaae6fba27/aiohttp-3.13.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0f7a18f258d124cd678c5fe072fe4432a4d5232b0657fca7c1847f599233c83a", size = 1773023, upload-time = "2026-03-31T21:59:01.776Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c7/ef/720e639df03004fee2d869f771799d8c23046dec47d5b81e396c7cda583a/aiohttp-3.13.5-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:df6104c009713d3a89621096f3e3e88cc323fd269dbd7c20afe18535094320be", size = 1853795, upload-time = "2026-03-31T21:59:04.568Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bd/c9/989f4034fb46841208de7aeeac2c6d8300745ab4f28c42f629ba77c2d916/aiohttp-3.13.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:241a94f7de7c0c3b616627aaad530fe2cb620084a8b144d3be7b6ecfe95bae3b", size = 1730405, upload-time = "2026-03-31T21:59:07.221Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ce/75/ee1fd286ca7dc599d824b5651dad7b3be7ff8d9a7e7b3fe9820d9180f7db/aiohttp-3.13.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c974fb66180e58709b6fc402846f13791240d180b74de81d23913abe48e96d94", size = 1558082, upload-time = "2026-03-31T21:59:09.484Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c3/20/1e9e6650dfc436340116b7aa89ff8cb2bbdf0abc11dfaceaad8f74273a10/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:6e27ea05d184afac78aabbac667450c75e54e35f62238d44463131bd3f96753d", size = 1692346, upload-time = "2026-03-31T21:59:12.068Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d8/40/8ebc6658d48ea630ac7903912fe0dd4e262f0e16825aa4c833c56c9f1f56/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a79a6d399cef33a11b6f004c67bb07741d91f2be01b8d712d52c75711b1e07c7", size = 1698891, upload-time = "2026-03-31T21:59:14.552Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d8/78/ea0ae5ec8ba7a5c10bdd6e318f1ba5e76fcde17db8275188772afc7917a4/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c632ce9c0b534fbe25b52c974515ed674937c5b99f549a92127c85f771a78772", size = 1742113, upload-time = "2026-03-31T21:59:17.068Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8a/66/9d308ed71e3f2491be1acb8769d96c6f0c47d92099f3bc9119cada27b357/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:fceedde51fbd67ee2bcc8c0b33d0126cc8b51ef3bbde2f86662bd6d5a6f10ec5", size = 1553088, upload-time = "2026-03-31T21:59:19.541Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/da/a6/6cc25ed8dfc6e00c90f5c6d126a98e2cf28957ad06fa1036bd34b6f24a2c/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f92995dfec9420bb69ae629abf422e516923ba79ba4403bc750d94fb4a6c68c1", size = 1757976, upload-time = "2026-03-31T21:59:22.311Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c1/2b/cce5b0ffe0de99c83e5e36d8f828e4161e415660a9f3e58339d07cce3006/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20ae0ff08b1f2c8788d6fb85afcb798654ae6ba0b747575f8562de738078457b", size = 1712444, upload-time = "2026-03-31T21:59:24.635Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6c/cf/9e1795b4160c58d29421eafd1a69c6ce351e2f7c8d3c6b7e4ca44aea1a5b/aiohttp-3.13.5-cp314-cp314-win32.whl", hash = "sha256:b20df693de16f42b2472a9c485e1c948ee55524786a0a34345511afdd22246f3", size = 438128, upload-time = "2026-03-31T21:59:27.291Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/22/4d/eaedff67fc805aeba4ba746aec891b4b24cebb1a7d078084b6300f79d063/aiohttp-3.13.5-cp314-cp314-win_amd64.whl", hash = "sha256:f85c6f327bf0b8c29da7d93b1cabb6363fb5e4e160a32fa241ed2dce21b73162", size = 464029, upload-time = "2026-03-31T21:59:29.429Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/79/11/c27d9332ee20d68dd164dc12a6ecdef2e2e35ecc97ed6cf0d2442844624b/aiohttp-3.13.5-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:1efb06900858bb618ff5cee184ae2de5828896c448403d51fb633f09e109be0a", size = 778758, upload-time = "2026-03-31T21:59:31.547Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/04/fb/377aead2e0a3ba5f09b7624f702a964bdf4f08b5b6728a9799830c80041e/aiohttp-3.13.5-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:fee86b7c4bd29bdaf0d53d14739b08a106fdda809ca5fe032a15f52fae5fe254", size = 512883, upload-time = "2026-03-31T21:59:34.098Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bb/a6/aa109a33671f7a5d3bd78b46da9d852797c5e665bfda7d6b373f56bff2ec/aiohttp-3.13.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:20058e23909b9e65f9da62b396b77dfa95965cbe840f8def6e572538b1d32e36", size = 516668, upload-time = "2026-03-31T21:59:36.497Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/79/b3/ca078f9f2fa9563c36fb8ef89053ea2bb146d6f792c5104574d49d8acb63/aiohttp-3.13.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cf20a8d6868cb15a73cab329ffc07291ba8c22b1b88176026106ae39aa6df0f", size = 1883461, upload-time = "2026-03-31T21:59:38.723Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b7/e3/a7ad633ca1ca497b852233a3cce6906a56c3225fb6d9217b5e5e60b7419d/aiohttp-3.13.5-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:330f5da04c987f1d5bdb8ae189137c77139f36bd1cb23779ca1a354a4b027800", size = 1747661, upload-time = "2026-03-31T21:59:41.187Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/33/b9/cd6fe579bed34a906d3d783fe60f2fa297ef55b27bb4538438ee49d4dc41/aiohttp-3.13.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f1cbf0c7926d315c3c26c2da41fd2b5d2fe01ac0e157b78caefc51a782196cf", size = 1863800, upload-time = "2026-03-31T21:59:43.84Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c0/3f/2c1e2f5144cefa889c8afd5cf431994c32f3b29da9961698ff4e3811b79a/aiohttp-3.13.5-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:53fc049ed6390d05423ba33103ded7281fe897cf97878f369a527070bd95795b", size = 1958382, upload-time = "2026-03-31T21:59:46.187Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/66/1d/f31ec3f1013723b3babe3609e7f119c2c2fb6ef33da90061a705ef3e1bc8/aiohttp-3.13.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:898703aa2667e3c5ca4c54ca36cd73f58b7a38ef87a5606414799ebce4d3fd3a", size = 1803724, upload-time = "2026-03-31T21:59:48.656Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0e/b4/57712dfc6f1542f067daa81eb61da282fab3e6f1966fca25db06c4fc62d5/aiohttp-3.13.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0494a01ca9584eea1e5fbd6d748e61ecff218c51b576ee1999c23db7066417d8", size = 1640027, upload-time = "2026-03-31T21:59:51.284Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/25/3c/734c878fb43ec083d8e31bf029daae1beafeae582d1b35da234739e82ee7/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6cf81fe010b8c17b09495cbd15c1d35afbc8fb405c0c9cf4738e5ae3af1d65be", size = 1806644, upload-time = "2026-03-31T21:59:53.753Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/20/a5/f671e5cbec1c21d044ff3078223f949748f3a7f86b14e34a365d74a5d21f/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:c564dd5f09ddc9d8f2c2d0a301cd30a79a2cc1b46dd1a73bef8f0038863d016b", size = 1791630, upload-time = "2026-03-31T21:59:56.239Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0b/63/fb8d0ad63a0b8a99be97deac8c04dacf0785721c158bdf23d679a87aa99e/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:2994be9f6e51046c4f864598fd9abeb4fba6e88f0b2152422c9666dcd4aea9c6", size = 1809403, upload-time = "2026-03-31T21:59:59.103Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/59/0c/bfed7f30662fcf12206481c2aac57dedee43fe1c49275e85b3a1e1742294/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:157826e2fa245d2ef46c83ea8a5faf77ca19355d278d425c29fda0beb3318037", size = 1634924, upload-time = "2026-03-31T22:00:02.116Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/17/d6/fd518d668a09fd5a3319ae5e984d4d80b9a4b3df4e21c52f02251ef5a32e/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:a8aca50daa9493e9e13c0f566201a9006f080e7c50e5e90d0b06f53146a54500", size = 1836119, upload-time = "2026-03-31T22:00:04.756Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/78/b7/15fb7a9d52e112a25b621c67b69c167805cb1f2ab8f1708a5c490d1b52fe/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3b13560160d07e047a93f23aaa30718606493036253d5430887514715b67c9d9", size = 1772072, upload-time = "2026-03-31T22:00:07.494Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7e/df/57ba7f0c4a553fc2bd8b6321df236870ec6fd64a2a473a8a13d4f733214e/aiohttp-3.13.5-cp314-cp314t-win32.whl", hash = "sha256:9a0f4474b6ea6818b41f82172d799e4b3d29e22c2c520ce4357856fced9af2f8", size = 471819, upload-time = "2026-03-31T22:00:10.277Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/62/29/2f8418269e46454a26171bfdd6a055d74febf32234e474930f2f60a17145/aiohttp-3.13.5-cp314-cp314t-win_amd64.whl", hash = "sha256:18a2f6c1182c51baa1d28d68fea51513cb2a76612f038853c0ad3c145423d3d9", size = 505441, upload-time = "2026-03-31T22:00:12.791Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aiosignal"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "frozenlist" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "annotated-doc"
|
name = "annotated-doc"
|
||||||
version = "0.0.4"
|
version = "0.0.4"
|
||||||
@@ -89,26 +161,12 @@ wheels = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "back-end"
|
name = "attrs"
|
||||||
version = "0.1.0"
|
version = "26.1.0"
|
||||||
source = { virtual = "." }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/82a0fe20a541c03148528be8cac2408564a6c9a0cc7e9171802bc1d26985/attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32", size = 952055, upload-time = "2026-03-19T14:22:25.026Z" }
|
||||||
{ name = "fastapi" },
|
wheels = [
|
||||||
{ name = "pydantic" },
|
{ url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" },
|
||||||
{ name = "pymobiledevice3" },
|
|
||||||
{ name = "python-socketio" },
|
|
||||||
{ name = "typing" },
|
|
||||||
{ name = "uvicorn" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.metadata]
|
|
||||||
requires-dist = [
|
|
||||||
{ name = "fastapi", specifier = "==0.135.1" },
|
|
||||||
{ name = "pydantic", specifier = "==2.12.5" },
|
|
||||||
{ name = "pymobiledevice3", specifier = "==9.0.0" },
|
|
||||||
{ name = "python-socketio", specifier = "==5.16.1" },
|
|
||||||
{ name = "typing", specifier = "==3.10.0.0" },
|
|
||||||
{ name = "uvicorn", specifier = "==0.41.0" },
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -412,6 +470,85 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/e4/72/42e900510195b23a56bde950d26a51f8b723846bfcaa0286e90287f0422b/fastapi-0.135.1-py3-none-any.whl", hash = "sha256:46e2fc5745924b7c840f71ddd277382af29ce1cdb7d5eab5bf697e3fb9999c9e", size = 116999, upload-time = "2026-03-01T18:18:30.831Z" },
|
{ url = "https://files.pythonhosted.org/packages/e4/72/42e900510195b23a56bde950d26a51f8b723846bfcaa0286e90287f0422b/fastapi-0.135.1-py3-none-any.whl", hash = "sha256:46e2fc5745924b7c840f71ddd277382af29ce1cdb7d5eab5bf697e3fb9999c9e", size = 116999, upload-time = "2026-03-01T18:18:30.831Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fido2"
|
||||||
|
version = "2.1.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "cryptography" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/e7/3c/c65377e48c144afca6b02c69f10c0fe936db556096a4e2c9798e2aa72db6/fido2-2.1.1.tar.gz", hash = "sha256:f1379f845870cc7fc64c7f07323c3ce41e8c96c37054e79e0acd5630b3fec5ac", size = 4455940, upload-time = "2026-01-19T11:08:34.683Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e2/ab/d0fa89cc4b982800dd88daa799612f11642bf9393851715d9eaeba3cfcac/fido2-2.1.1-py3-none-any.whl", hash = "sha256:f85c16c8084abf6530b6c6ec3a0cf8575943321842e06916686943a8b784182c", size = 226945, upload-time = "2026-01-19T11:08:29.675Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "frozenlist"
|
||||||
|
version = "1.8.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f1/c8/85da824b7e7b9b6e7f7705b2ecaf9591ba6f79c1177f324c2735e41d36a2/frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0", size = 86127, upload-time = "2025-10-06T05:37:08.438Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8e/e8/a1185e236ec66c20afd72399522f142c3724c785789255202d27ae992818/frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f", size = 49698, upload-time = "2025-10-06T05:37:09.48Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a1/93/72b1736d68f03fda5fdf0f2180fb6caaae3894f1b854d006ac61ecc727ee/frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c", size = 49749, upload-time = "2025-10-06T05:37:10.569Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a7/b2/fabede9fafd976b991e9f1b9c8c873ed86f202889b864756f240ce6dd855/frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2", size = 231298, upload-time = "2025-10-06T05:37:11.993Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3a/3b/d9b1e0b0eed36e70477ffb8360c49c85c8ca8ef9700a4e6711f39a6e8b45/frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8", size = 232015, upload-time = "2025-10-06T05:37:13.194Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/dc/94/be719d2766c1138148564a3960fc2c06eb688da592bdc25adcf856101be7/frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686", size = 225038, upload-time = "2025-10-06T05:37:14.577Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e4/09/6712b6c5465f083f52f50cf74167b92d4ea2f50e46a9eea0523d658454ae/frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e", size = 240130, upload-time = "2025-10-06T05:37:15.781Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f8/d4/cd065cdcf21550b54f3ce6a22e143ac9e4836ca42a0de1022da8498eac89/frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a", size = 242845, upload-time = "2025-10-06T05:37:17.037Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/62/c3/f57a5c8c70cd1ead3d5d5f776f89d33110b1addae0ab010ad774d9a44fb9/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128", size = 229131, upload-time = "2025-10-06T05:37:18.221Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6c/52/232476fe9cb64f0742f3fde2b7d26c1dac18b6d62071c74d4ded55e0ef94/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f", size = 240542, upload-time = "2025-10-06T05:37:19.771Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5f/85/07bf3f5d0fb5414aee5f47d33c6f5c77bfe49aac680bfece33d4fdf6a246/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7", size = 237308, upload-time = "2025-10-06T05:37:20.969Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/11/99/ae3a33d5befd41ac0ca2cc7fd3aa707c9c324de2e89db0e0f45db9a64c26/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30", size = 238210, upload-time = "2025-10-06T05:37:22.252Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b2/60/b1d2da22f4970e7a155f0adde9b1435712ece01b3cd45ba63702aea33938/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7", size = 231972, upload-time = "2025-10-06T05:37:23.5Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3f/ab/945b2f32de889993b9c9133216c068b7fcf257d8595a0ac420ac8677cab0/frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806", size = 40536, upload-time = "2025-10-06T05:37:25.581Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/59/ad/9caa9b9c836d9ad6f067157a531ac48b7d36499f5036d4141ce78c230b1b/frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0", size = 44330, upload-time = "2025-10-06T05:37:26.928Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/82/13/e6950121764f2676f43534c555249f57030150260aee9dcf7d64efda11dd/frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b", size = 40627, upload-time = "2025-10-06T05:37:28.075Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c0/c7/43200656ecc4e02d3f8bc248df68256cd9572b3f0017f0a0c4e93440ae23/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d", size = 89238, upload-time = "2025-10-06T05:37:29.373Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d1/29/55c5f0689b9c0fb765055629f472c0de484dcaf0acee2f7707266ae3583c/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed", size = 50738, upload-time = "2025-10-06T05:37:30.792Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930", size = 51739, upload-time = "2025-10-06T05:37:32.127Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/62/1c/3d8622e60d0b767a5510d1d3cf21065b9db874696a51ea6d7a43180a259c/frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c", size = 284186, upload-time = "2025-10-06T05:37:33.21Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2d/14/aa36d5f85a89679a85a1d44cd7a6657e0b1c75f61e7cad987b203d2daca8/frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24", size = 292196, upload-time = "2025-10-06T05:37:36.107Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/05/23/6bde59eb55abd407d34f77d39a5126fb7b4f109a3f611d3929f14b700c66/frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37", size = 273830, upload-time = "2025-10-06T05:37:37.663Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d2/3f/22cff331bfad7a8afa616289000ba793347fcd7bc275f3b28ecea2a27909/frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a", size = 294289, upload-time = "2025-10-06T05:37:39.261Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a4/89/5b057c799de4838b6c69aa82b79705f2027615e01be996d2486a69ca99c4/frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2", size = 300318, upload-time = "2025-10-06T05:37:43.213Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/30/de/2c22ab3eb2a8af6d69dc799e48455813bab3690c760de58e1bf43b36da3e/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef", size = 282814, upload-time = "2025-10-06T05:37:45.337Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/59/f7/970141a6a8dbd7f556d94977858cfb36fa9b66e0892c6dd780d2219d8cd8/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe", size = 291762, upload-time = "2025-10-06T05:37:46.657Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c1/15/ca1adae83a719f82df9116d66f5bb28bb95557b3951903d39135620ef157/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8", size = 289470, upload-time = "2025-10-06T05:37:47.946Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ac/83/dca6dc53bf657d371fbc88ddeb21b79891e747189c5de990b9dfff2ccba1/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a", size = 289042, upload-time = "2025-10-06T05:37:49.499Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/96/52/abddd34ca99be142f354398700536c5bd315880ed0a213812bc491cff5e4/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e", size = 283148, upload-time = "2025-10-06T05:37:50.745Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/af/d3/76bd4ed4317e7119c2b7f57c3f6934aba26d277acc6309f873341640e21f/frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df", size = 44676, upload-time = "2025-10-06T05:37:52.222Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/89/76/c615883b7b521ead2944bb3480398cbb07e12b7b4e4d073d3752eb721558/frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd", size = 49451, upload-time = "2025-10-06T05:37:53.425Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e0/a3/5982da14e113d07b325230f95060e2169f5311b1017ea8af2a29b374c289/frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79", size = 42507, upload-time = "2025-10-06T05:37:54.513Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "geographiclib"
|
||||||
|
version = "2.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/df/78/4892343230a9d29faa1364564e525307a37e54ad776ea62c12129dbba704/geographiclib-2.1.tar.gz", hash = "sha256:6a6545e6262d0ed3522e13c515713718797e37ed8c672c31ad7b249f372ef108", size = 37004, upload-time = "2025-08-21T21:34:26Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/31/b3/802576f2ea5dcb48501bb162e4c7b7b3ca5654a42b2c968ef98a797a4c79/geographiclib-2.1-py3-none-any.whl", hash = "sha256:e2a873b9b9e7fc38721ad73d5f4e6c9ed140d428a339970f505c07056997d40b", size = 40740, upload-time = "2025-08-21T21:34:24.955Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "geopy"
|
||||||
|
version = "2.4.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "geographiclib" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/0e/fd/ef6d53875ceab72c1fad22dbed5ec1ad04eb378c2251a6a8024bad890c3b/geopy-2.4.1.tar.gz", hash = "sha256:50283d8e7ad07d89be5cb027338c6365a32044df3ae2556ad3f52f4840b3d0d1", size = 117625, upload-time = "2023-11-23T21:49:32.734Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e5/15/cf2a69ade4b194aa524ac75112d5caac37414b20a3a03e6865dfe0bd1539/geopy-2.4.1-py3-none-any.whl", hash = "sha256:ae8b4bc5c1131820f4d75fce9d4aaaca0c85189b3aa5d64c3dcaf5e3b7b882a7", size = 125437, upload-time = "2023-11-23T21:49:30.421Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.optional-dependencies]
|
||||||
|
aiohttp = [
|
||||||
|
{ name = "aiohttp" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpxpy"
|
name = "gpxpy"
|
||||||
version = "1.6.2"
|
version = "1.6.2"
|
||||||
@@ -421,6 +558,29 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/44/9f/62df6c1e52462bdd04275b36cec49efa9e8af7e7b834499eb288f73dcfbc/gpxpy-1.6.2-py3-none-any.whl", hash = "sha256:289bc2d80f116c988d0a1e763fda22838f83005573ece2bbc6521817b26fb40a", size = 42649, upload-time = "2023-11-29T17:25:35.76Z" },
|
{ url = "https://files.pythonhosted.org/packages/44/9f/62df6c1e52462bdd04275b36cec49efa9e8af7e7b834499eb288f73dcfbc/gpxpy-1.6.2-py3-none-any.whl", hash = "sha256:289bc2d80f116c988d0a1e763fda22838f83005573ece2bbc6521817b26fb40a", size = 42649, upload-time = "2023-11-29T17:25:35.76Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "greenlet"
|
||||||
|
version = "3.3.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/a3/51/1664f6b78fc6ebbd98019a1fd730e83fa78f2db7058f72b1463d3612b8db/greenlet-3.3.2.tar.gz", hash = "sha256:2eaf067fc6d886931c7962e8c6bede15d2f01965560f3359b27c80bde2d151f2", size = 188267, upload-time = "2026-02-20T20:54:15.531Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3f/ae/8bffcbd373b57a5992cd077cbe8858fff39110480a9d50697091faea6f39/greenlet-3.3.2-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:8d1658d7291f9859beed69a776c10822a0a799bc4bfe1bd4272bb60e62507dab", size = 279650, upload-time = "2026-02-20T20:18:00.783Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d1/c0/45f93f348fa49abf32ac8439938726c480bd96b2a3c6f4d949ec0124b69f/greenlet-3.3.2-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:18cb1b7337bca281915b3c5d5ae19f4e76d35e1df80f4ad3c1a7be91fadf1082", size = 650295, upload-time = "2026-02-20T20:47:34.036Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b3/de/dd7589b3f2b8372069ab3e4763ea5329940fc7ad9dcd3e272a37516d7c9b/greenlet-3.3.2-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c2e47408e8ce1c6f1ceea0dffcdf6ebb85cc09e55c7af407c99f1112016e45e9", size = 662163, upload-time = "2026-02-20T20:56:01.295Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d2/d8/09bfa816572a4d83bccd6750df1926f79158b1c36c5f73786e26dbe4ee38/greenlet-3.3.2-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63d10328839d1973e5ba35e98cccbca71b232b14051fd957b6f8b6e8e80d0506", size = 664160, upload-time = "2026-02-20T20:21:04.015Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/48/cf/56832f0c8255d27f6c35d41b5ec91168d74ec721d85f01a12131eec6b93c/greenlet-3.3.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8e4ab3cfb02993c8cc248ea73d7dae6cec0253e9afa311c9b37e603ca9fad2ce", size = 1619181, upload-time = "2026-02-20T20:49:36.052Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0a/23/b90b60a4aabb4cec0796e55f25ffbfb579a907c3898cd2905c8918acaa16/greenlet-3.3.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:94ad81f0fd3c0c0681a018a976e5c2bd2ca2d9d94895f23e7bb1af4e8af4e2d5", size = 1687713, upload-time = "2026-02-20T20:21:11.684Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f3/ca/2101ca3d9223a1dc125140dbc063644dca76df6ff356531eb27bc267b446/greenlet-3.3.2-cp314-cp314-win_amd64.whl", hash = "sha256:8c4dd0f3997cf2512f7601563cc90dfb8957c0cff1e3a1b23991d4ea1776c492", size = 232034, upload-time = "2026-02-20T20:20:08.186Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f6/4a/ecf894e962a59dea60f04877eea0fd5724618da89f1867b28ee8b91e811f/greenlet-3.3.2-cp314-cp314-win_arm64.whl", hash = "sha256:cd6f9e2bbd46321ba3bbb4c8a15794d32960e3b0ae2cc4d49a1a53d314805d71", size = 231437, upload-time = "2026-02-20T20:18:59.722Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/98/6d/8f2ef704e614bcf58ed43cfb8d87afa1c285e98194ab2cfad351bf04f81e/greenlet-3.3.2-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:e26e72bec7ab387ac80caa7496e0f908ff954f31065b0ffc1f8ecb1338b11b54", size = 286617, upload-time = "2026-02-20T20:19:29.856Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5e/0d/93894161d307c6ea237a43988f27eba0947b360b99ac5239ad3fe09f0b47/greenlet-3.3.2-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b466dff7a4ffda6ca975979bab80bdadde979e29fc947ac3be4451428d8b0e4", size = 655189, upload-time = "2026-02-20T20:47:35.742Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f5/2c/d2d506ebd8abcb57386ec4f7ba20f4030cbe56eae541bc6fd6ef399c0b41/greenlet-3.3.2-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b8bddc5b73c9720bea487b3bffdb1840fe4e3656fba3bd40aa1489e9f37877ff", size = 658225, upload-time = "2026-02-20T20:56:02.527Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8e/30/3a09155fbf728673a1dea713572d2d31159f824a37c22da82127056c44e4/greenlet-3.3.2-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b26b0f4428b871a751968285a1ac9648944cea09807177ac639b030bddebcea4", size = 657907, upload-time = "2026-02-20T20:21:05.259Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f3/fd/d05a4b7acd0154ed758797f0a43b4c0962a843bedfe980115e842c5b2d08/greenlet-3.3.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1fb39a11ee2e4d94be9a76671482be9398560955c9e568550de0224e41104727", size = 1618857, upload-time = "2026-02-20T20:49:37.309Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6f/e1/50ee92a5db521de8f35075b5eff060dd43d39ebd46c2181a2042f7070385/greenlet-3.3.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:20154044d9085151bc309e7689d6f7ba10027f8f5a8c0676ad398b951913d89e", size = 1680010, upload-time = "2026-02-20T20:21:13.427Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/29/4b/45d90626aef8e65336bed690106d1382f7a43665e2249017e9527df8823b/greenlet-3.3.2-cp314-cp314t-win_amd64.whl", hash = "sha256:c04c5e06ec3e022cbfe2cd4a846e1d4e50087444f875ff6d2c2ad8445495cf1a", size = 237086, upload-time = "2026-02-20T20:20:45.786Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "h11"
|
name = "h11"
|
||||||
version = "0.16.0"
|
version = "0.16.0"
|
||||||
@@ -436,6 +596,34 @@ version = "3.3"
|
|||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/55/b3/279b1d57fa3681725d0db8820405cdcb4e62a9239c205e4ceac4391c78e4/hexdump-3.3.zip", hash = "sha256:d781a43b0c16ace3f9366aade73e8ad3a7bd5137d58f0b45ab2d3f54876f20db", size = 12658, upload-time = "2016-01-22T14:40:19.589Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/55/b3/279b1d57fa3681725d0db8820405cdcb4e62a9239c205e4ceac4391c78e4/hexdump-3.3.zip", hash = "sha256:d781a43b0c16ace3f9366aade73e8ad3a7bd5137d58f0b45ab2d3f54876f20db", size = 12658, upload-time = "2016-01-22T14:40:19.589Z" }
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpcore"
|
||||||
|
version = "1.0.9"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "certifi" },
|
||||||
|
{ name = "h11" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" }
|
||||||
|
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" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpx"
|
||||||
|
version = "0.28.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "anyio" },
|
||||||
|
{ name = "certifi" },
|
||||||
|
{ name = "httpcore" },
|
||||||
|
{ name = "idna" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "humanfriendly"
|
name = "humanfriendly"
|
||||||
version = "10.0"
|
version = "10.0"
|
||||||
@@ -475,6 +663,15 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/9c/1f/19ebc343cc71a7ffa78f17018535adc5cbdd87afb31d7c34874680148b32/ifaddr-0.2.0-py3-none-any.whl", hash = "sha256:085e0305cfe6f16ab12d72e2024030f5d52674afad6911bb1eee207177b8a748", size = 12314, upload-time = "2022-06-15T21:40:25.756Z" },
|
{ url = "https://files.pythonhosted.org/packages/9c/1f/19ebc343cc71a7ffa78f17018535adc5cbdd87afb31d7c34874680148b32/ifaddr-0.2.0-py3-none-any.whl", hash = "sha256:085e0305cfe6f16ab12d72e2024030f5d52674afad6911bb1eee207177b8a748", size = 12314, upload-time = "2022-06-15T21:40:25.756Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inflection"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/e1/7e/691d061b7329bc8d54edbf0ec22fbfb2afe61facb681f9aaa9bff7a27d04/inflection-0.5.1.tar.gz", hash = "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417", size = 15091, upload-time = "2020-08-22T08:16:29.139Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/59/91/aa6bde563e0085a02a435aa99b49ef75b0a4b062635e606dab23ce18d720/inflection-0.5.1-py2.py3-none-any.whl", hash = "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2", size = 9454, upload-time = "2020-08-22T08:16:27.816Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "inquirer3"
|
name = "inquirer3"
|
||||||
version = "0.6.1"
|
version = "0.6.1"
|
||||||
@@ -491,21 +688,20 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipsw-parser"
|
name = "ipsw-parser"
|
||||||
version = "1.5.0"
|
version = "1.6.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "cached-property" },
|
|
||||||
{ name = "click" },
|
|
||||||
{ name = "coloredlogs" },
|
{ name = "coloredlogs" },
|
||||||
{ name = "construct" },
|
{ name = "construct" },
|
||||||
{ name = "plumbum" },
|
{ name = "plumbum" },
|
||||||
{ name = "pyimg4" },
|
{ name = "pyimg4" },
|
||||||
{ name = "remotezip2" },
|
{ name = "remotezip2" },
|
||||||
{ name = "requests" },
|
{ name = "requests" },
|
||||||
|
{ name = "typer" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/2c/96/c820ec1e2f50d398c2442b2f8759448a896a300745c2920c4cf7ba89dd4c/ipsw_parser-1.5.0.tar.gz", hash = "sha256:5becd2000017b7b8549cc6b6e3f5149541792bf6353663d0f77932965bf26aad", size = 51957, upload-time = "2025-11-18T21:57:37.881Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/fc/8a/bae825b78838c86b05bd7ca3bf26e98dfcf3d0955619fe717402a628dfa7/ipsw_parser-1.6.0.tar.gz", hash = "sha256:d3121ae9f2a12bae6604972a9e00f6168cdedb3ad3db6b178061b4995e8fd14f", size = 53471, upload-time = "2026-03-17T20:27:27.524Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/d1/99/b5805555d14abf34d9534c9e8ba81d629107fa5d3bd7f110ca752a21d1c2/ipsw_parser-1.5.0-py3-none-any.whl", hash = "sha256:740248a1937d7b7dacc5d98e758b578ed88c357638126a8a71d4b0c100a3c9eb", size = 36611, upload-time = "2025-11-18T21:57:36.975Z" },
|
{ url = "https://files.pythonhosted.org/packages/a8/a3/9671c80252fc7a8b870b01639c3ae821d39f9489ac346bce7d8bfbf168f4/ipsw_parser-1.6.0-py3-none-any.whl", hash = "sha256:0e1f2b726c053617c65b0cef04afeecdf73ad14cc17e7e58d6382209d6693466", size = 37623, upload-time = "2026-03-17T20:27:26.518Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -541,6 +737,39 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" },
|
{ url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jaraco-classes"
|
||||||
|
version = "3.4.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "more-itertools" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/06/c0/ed4a27bc5571b99e3cff68f8a9fa5b56ff7df1c2251cc715a652ddd26402/jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd", size = 11780, upload-time = "2024-03-31T07:27:36.643Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790", size = 6777, upload-time = "2024-03-31T07:27:34.792Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jaraco-context"
|
||||||
|
version = "6.1.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/af/50/4763cd07e722bb6285316d390a164bc7e479db9d90daa769f22578f698b4/jaraco_context-6.1.2.tar.gz", hash = "sha256:f1a6c9d391e661cc5b8d39861ff077a7dc24dc23833ccee564b234b81c82dfe3", size = 16801, upload-time = "2026-03-20T22:13:33.922Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl", hash = "sha256:bf8150b79a2d5d91ae48629d8b427a8f7ba0e1097dd6202a9059f29a36379535", size = 7871, upload-time = "2026-03-20T22:13:32.808Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jaraco-functools"
|
||||||
|
version = "4.4.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "more-itertools" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/0f/27/056e0638a86749374d6f57d0b0db39f29509cce9313cf91bdc0ac4d91084/jaraco_functools-4.4.0.tar.gz", hash = "sha256:da21933b0417b89515562656547a77b4931f98176eb173644c0d35032a33d6bb", size = 19943, upload-time = "2025-12-21T09:29:43.6Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fd/c4/813bb09f0985cb21e959f21f2464169eca882656849adf727ac7bb7e1767/jaraco_functools-4.4.0-py3-none-any.whl", hash = "sha256:9eec1e36f45c818d9bf307c8948eb03b2b56cd44087b3cdc989abca1f20b9176", size = 10481, upload-time = "2025-12-21T09:29:42.27Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jedi"
|
name = "jedi"
|
||||||
version = "0.19.2"
|
version = "0.19.2"
|
||||||
@@ -553,6 +782,15 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" },
|
{ url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jeepney"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/7b/6f/357efd7602486741aa73ffc0617fb310a29b588ed0fd69c2399acbb85b0c/jeepney-0.9.0.tar.gz", hash = "sha256:cf0e9e845622b81e4a28df94c40345400256ec608d0e55bb8a3feaa9163f5732", size = 106758, upload-time = "2025-02-27T18:51:01.684Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl", hash = "sha256:97e5714520c16fc0a45695e5365a2e11b81ea79bba796e26f9f1d178cb182683", size = 49010, upload-time = "2025-02-27T18:51:00.104Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jinxed"
|
name = "jinxed"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
@@ -566,18 +804,33 @@ wheels = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "la-panic"
|
name = "keyring"
|
||||||
version = "0.5.0"
|
version = "25.7.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "cached-property" },
|
{ name = "jaraco-classes" },
|
||||||
{ name = "click" },
|
{ name = "jaraco-context" },
|
||||||
{ name = "coloredlogs" },
|
{ name = "jaraco-functools" },
|
||||||
{ name = "setuptools" },
|
{ name = "jeepney", marker = "sys_platform == 'linux'" },
|
||||||
|
{ name = "pywin32-ctypes", marker = "sys_platform == 'win32'" },
|
||||||
|
{ name = "secretstorage", marker = "sys_platform == 'linux'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/85/28/757e1ccd939162caa27c8a6173d490deb986c38a7fd73fe2f264f6d7485d/la-panic-0.5.0.tar.gz", hash = "sha256:5239025d1e96aaed1fbd1c4a5d35572fd70cf42ddd68839ff1e4f1d21e3e279b", size = 57320, upload-time = "2023-11-12T17:49:33.159Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/43/4b/674af6ef2f97d56f0ab5153bf0bfa28ccb6c3ed4d1babf4305449668807b/keyring-25.7.0.tar.gz", hash = "sha256:fe01bd85eb3f8fb3dd0405defdeac9a5b4f6f0439edbb3149577f244a2e8245b", size = 63516, upload-time = "2025-11-16T16:26:09.482Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/63/8a/59eb5256cb0449c6f052453a1ce1fc32eed77ebd93b6be43f0136a7428a8/la_panic-0.5.0-py3-none-any.whl", hash = "sha256:5e224e5d038a020897606baf36e3aecbd33a5e56d82d0ac9cd72bcc0d5c3007d", size = 51866, upload-time = "2023-11-12T17:49:31.277Z" },
|
{ url = "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl", hash = "sha256:be4a0b195f149690c166e850609a477c532ddbfbaed96a404d4e43f8d5e2689f", size = 39160, upload-time = "2025-11-16T16:26:08.402Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "keyrings-alt"
|
||||||
|
version = "5.0.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "jaraco-classes" },
|
||||||
|
{ name = "jaraco-context" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/5c/7b/e3bf53326e0753bee11813337b1391179582ba5c6851b13e0d9502d15a50/keyrings_alt-5.0.2.tar.gz", hash = "sha256:8f097ebe9dc8b185106502b8cdb066c926d2180e13b4689fd4771a3eab7d69fb", size = 29229, upload-time = "2024-08-14T01:09:28.12Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4a/0d/9c59313ab43d0858a9a665e80763bd830dc78d5f379afc3815e123c486c2/keyrings.alt-5.0.2-py3-none-any.whl", hash = "sha256:6be74693192f3f37bbb752bfac9b86e6177076b17d2ac12a390f1d6abff8ac7c", size = 17930, upload-time = "2024-08-14T01:09:26.785Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -631,6 +884,98 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
|
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "more-itertools"
|
||||||
|
version = "10.8.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/ea/5d/38b681d3fce7a266dd9ab73c66959406d565b3e85f21d5e66e1181d93721/more_itertools-10.8.0.tar.gz", hash = "sha256:f638ddf8a1a0d134181275fb5d58b086ead7c6a72429ad725c67503f13ba30bd", size = 137431, upload-time = "2025-09-02T15:23:11.018Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl", hash = "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b", size = 69667, upload-time = "2025-09-02T15:23:09.635Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "multidict"
|
||||||
|
version = "6.7.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/1a/c2/c2d94cbe6ac1753f3fc980da97b3d930efe1da3af3c9f5125354436c073d/multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d", size = 102010, upload-time = "2026-01-26T02:46:45.979Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/91/cc/db74228a8be41884a567e88a62fd589a913708fcf180d029898c17a9a371/multidict-6.7.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8f333ec9c5eb1b7105e3b84b53141e66ca05a19a605368c55450b6ba208cb9ee", size = 75190, upload-time = "2026-01-26T02:45:10.651Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d5/22/492f2246bb5b534abd44804292e81eeaf835388901f0c574bac4eeec73c5/multidict-6.7.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a407f13c188f804c759fc6a9f88286a565c242a76b27626594c133b82883b5c2", size = 44486, upload-time = "2026-01-26T02:45:11.938Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f1/4f/733c48f270565d78b4544f2baddc2fb2a245e5a8640254b12c36ac7ac68e/multidict-6.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0e161ddf326db5577c3a4cc2d8648f81456e8a20d40415541587a71620d7a7d1", size = 43219, upload-time = "2026-01-26T02:45:14.346Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/24/bb/2c0c2287963f4259c85e8bcbba9182ced8d7fca65c780c38e99e61629d11/multidict-6.7.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1e3a8bb24342a8201d178c3b4984c26ba81a577c80d4d525727427460a50c22d", size = 245132, upload-time = "2026-01-26T02:45:15.712Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a7/f9/44d4b3064c65079d2467888794dea218d1601898ac50222ab8a9a8094460/multidict-6.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97231140a50f5d447d3164f994b86a0bed7cd016e2682f8650d6a9158e14fd31", size = 252420, upload-time = "2026-01-26T02:45:17.293Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8b/13/78f7275e73fa17b24c9a51b0bd9d73ba64bb32d0ed51b02a746eb876abe7/multidict-6.7.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6b10359683bd8806a200fd2909e7c8ca3a7b24ec1d8132e483d58e791d881048", size = 233510, upload-time = "2026-01-26T02:45:19.356Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4b/25/8167187f62ae3cbd52da7893f58cb036b47ea3fb67138787c76800158982/multidict-6.7.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:283ddac99f7ac25a4acadbf004cb5ae34480bbeb063520f70ce397b281859362", size = 264094, upload-time = "2026-01-26T02:45:20.834Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a1/e7/69a3a83b7b030cf283fb06ce074a05a02322359783424d7edf0f15fe5022/multidict-6.7.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:538cec1e18c067d0e6103aa9a74f9e832904c957adc260e61cd9d8cf0c3b3d37", size = 260786, upload-time = "2026-01-26T02:45:22.818Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fe/3b/8ec5074bcfc450fe84273713b4b0a0dd47c0249358f5d82eb8104ffe2520/multidict-6.7.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eee46ccb30ff48a1e35bb818cc90846c6be2b68240e42a78599166722cea709", size = 248483, upload-time = "2026-01-26T02:45:24.368Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/48/5a/d5a99e3acbca0e29c5d9cba8f92ceb15dce78bab963b308ae692981e3a5d/multidict-6.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa263a02f4f2dd2d11a7b1bb4362aa7cb1049f84a9235d31adf63f30143469a0", size = 248403, upload-time = "2026-01-26T02:45:25.982Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/35/48/e58cd31f6c7d5102f2a4bf89f96b9cf7e00b6c6f3d04ecc44417c00a5a3c/multidict-6.7.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2e1425e2f99ec5bd36c15a01b690a1a2456209c5deed58f95469ffb46039ccbb", size = 240315, upload-time = "2026-01-26T02:45:27.487Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/94/33/1cd210229559cb90b6786c30676bb0c58249ff42f942765f88793b41fdce/multidict-6.7.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:497394b3239fc6f0e13a78a3e1b61296e72bf1c5f94b4c4eb80b265c37a131cd", size = 245528, upload-time = "2026-01-26T02:45:28.991Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/64/f2/6e1107d226278c876c783056b7db43d800bb64c6131cec9c8dfb6903698e/multidict-6.7.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:233b398c29d3f1b9676b4b6f75c518a06fcb2ea0b925119fb2c1bc35c05e1601", size = 258784, upload-time = "2026-01-26T02:45:30.503Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4d/c1/11f664f14d525e4a1b5327a82d4de61a1db604ab34c6603bb3c2cc63ad34/multidict-6.7.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:93b1818e4a6e0930454f0f2af7dfce69307ca03cdcfb3739bf4d91241967b6c1", size = 251980, upload-time = "2026-01-26T02:45:32.603Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e1/9f/75a9ac888121d0c5bbd4ecf4eead45668b1766f6baabfb3b7f66a410e231/multidict-6.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f33dc2a3abe9249ea5d8360f969ec7f4142e7ac45ee7014d8f8d5acddf178b7b", size = 243602, upload-time = "2026-01-26T02:45:34.043Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9a/e7/50bf7b004cc8525d80dbbbedfdc7aed3e4c323810890be4413e589074032/multidict-6.7.1-cp314-cp314-win32.whl", hash = "sha256:3ab8b9d8b75aef9df299595d5388b14530839f6422333357af1339443cff777d", size = 40930, upload-time = "2026-01-26T02:45:36.278Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e0/bf/52f25716bbe93745595800f36fb17b73711f14da59ed0bb2eba141bc9f0f/multidict-6.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:5e01429a929600e7dab7b166062d9bb54a5eed752384c7384c968c2afab8f50f", size = 45074, upload-time = "2026-01-26T02:45:37.546Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/97/ab/22803b03285fa3a525f48217963da3a65ae40f6a1b6f6cf2768879e208f9/multidict-6.7.1-cp314-cp314-win_arm64.whl", hash = "sha256:4885cb0e817aef5d00a2e8451d4665c1808378dc27c2705f1bf4ef8505c0d2e5", size = 42471, upload-time = "2026-01-26T02:45:38.889Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e0/6d/f9293baa6146ba9507e360ea0292b6422b016907c393e2f63fc40ab7b7b5/multidict-6.7.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0458c978acd8e6ea53c81eefaddbbee9c6c5e591f41b3f5e8e194780fe026581", size = 82401, upload-time = "2026-01-26T02:45:40.254Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7a/68/53b5494738d83558d87c3c71a486504d8373421c3e0dbb6d0db48ad42ee0/multidict-6.7.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c0abd12629b0af3cf590982c0b413b1e7395cd4ec026f30986818ab95bfaa94a", size = 48143, upload-time = "2026-01-26T02:45:41.635Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:14525a5f61d7d0c94b368a42cff4c9a4e7ba2d52e2672a7b23d84dc86fb02b0c", size = 46507, upload-time = "2026-01-26T02:45:42.99Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e4/fc/6800d0e5b3875568b4083ecf5f310dcf91d86d52573160834fb4bfcf5e4f/multidict-6.7.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17307b22c217b4cf05033dabefe68255a534d637c6c9b0cc8382718f87be4262", size = 239358, upload-time = "2026-01-26T02:45:44.376Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/41/75/4ad0973179361cdf3a113905e6e088173198349131be2b390f9fa4da5fc6/multidict-6.7.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a7e590ff876a3eaf1c02a4dfe0724b6e69a9e9de6d8f556816f29c496046e59", size = 246884, upload-time = "2026-01-26T02:45:47.167Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c3/9c/095bb28b5da139bd41fb9a5d5caff412584f377914bd8787c2aa98717130/multidict-6.7.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5fa6a95dfee63893d80a34758cd0e0c118a30b8dcb46372bf75106c591b77889", size = 225878, upload-time = "2026-01-26T02:45:48.698Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/07/d0/c0a72000243756e8f5a277b6b514fa005f2c73d481b7d9e47cd4568aa2e4/multidict-6.7.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a0543217a6a017692aa6ae5cc39adb75e587af0f3a82288b1492eb73dd6cc2a4", size = 253542, upload-time = "2026-01-26T02:45:50.164Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c0/6b/f69da15289e384ecf2a68837ec8b5ad8c33e973aa18b266f50fe55f24b8c/multidict-6.7.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f99fe611c312b3c1c0ace793f92464d8cd263cc3b26b5721950d977b006b6c4d", size = 252403, upload-time = "2026-01-26T02:45:51.779Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a2/76/b9669547afa5a1a25cd93eaca91c0da1c095b06b6d2d8ec25b713588d3a1/multidict-6.7.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9004d8386d133b7e6135679424c91b0b854d2d164af6ea3f289f8f2761064609", size = 244889, upload-time = "2026-01-26T02:45:53.27Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7e/a9/a50d2669e506dad33cfc45b5d574a205587b7b8a5f426f2fbb2e90882588/multidict-6.7.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e628ef0e6859ffd8273c69412a2465c4be4a9517d07261b33334b5ec6f3c7489", size = 241982, upload-time = "2026-01-26T02:45:54.919Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c5/bb/1609558ad8b456b4827d3c5a5b775c93b87878fd3117ed3db3423dfbce1b/multidict-6.7.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:841189848ba629c3552035a6a7f5bf3b02eb304e9fea7492ca220a8eda6b0e5c", size = 232415, upload-time = "2026-01-26T02:45:56.981Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d8/59/6f61039d2aa9261871e03ab9dc058a550d240f25859b05b67fd70f80d4b3/multidict-6.7.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ce1bbd7d780bb5a0da032e095c951f7014d6b0a205f8318308140f1a6aba159e", size = 240337, upload-time = "2026-01-26T02:45:58.698Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a1/29/fdc6a43c203890dc2ae9249971ecd0c41deaedfe00d25cb6564b2edd99eb/multidict-6.7.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b26684587228afed0d50cf804cc71062cc9c1cdf55051c4c6345d372947b268c", size = 248788, upload-time = "2026-01-26T02:46:00.862Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a9/14/a153a06101323e4cf086ecee3faadba52ff71633d471f9685c42e3736163/multidict-6.7.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9f9af11306994335398293f9958071019e3ab95e9a707dc1383a35613f6abcb9", size = 242842, upload-time = "2026-01-26T02:46:02.824Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/41/5f/604ae839e64a4a6efc80db94465348d3b328ee955e37acb24badbcd24d83/multidict-6.7.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b4938326284c4f1224178a560987b6cf8b4d38458b113d9b8c1db1a836e640a2", size = 240237, upload-time = "2026-01-26T02:46:05.898Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5f/60/c3a5187bf66f6fb546ff4ab8fb5a077cbdd832d7b1908d4365c7f74a1917/multidict-6.7.1-cp314-cp314t-win32.whl", hash = "sha256:98655c737850c064a65e006a3df7c997cd3b220be4ec8fe26215760b9697d4d7", size = 48008, upload-time = "2026-01-26T02:46:07.468Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0c/f7/addf1087b860ac60e6f382240f64fb99f8bfb532bb06f7c542b83c29ca61/multidict-6.7.1-cp314-cp314t-win_amd64.whl", hash = "sha256:497bde6223c212ba11d462853cfa4f0ae6ef97465033e7dc9940cdb3ab5b48e5", size = 53542, upload-time = "2026-01-26T02:46:08.809Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4c/81/4629d0aa32302ef7b2ec65c75a728cc5ff4fa410c50096174c1632e70b3e/multidict-6.7.1-cp314-cp314t-win_arm64.whl", hash = "sha256:2bbd113e0d4af5db41d5ebfe9ccaff89de2120578164f86a5d17d5a576d1e5b2", size = 44719, upload-time = "2026-01-26T02:46:11.146Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/81/08/7036c080d7117f28a4af526d794aab6a84463126db031b007717c1a6676e/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56", size = 12319, upload-time = "2026-01-26T02:46:44.004Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mypy-extensions"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "numpy"
|
||||||
|
version = "2.4.3"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/10/8b/c265f4823726ab832de836cdd184d0986dcf94480f81e8739692a7ac7af2/numpy-2.4.3.tar.gz", hash = "sha256:483a201202b73495f00dbc83796c6ae63137a9bdade074f7648b3e32613412dd", size = 20727743, upload-time = "2026-03-09T07:58:53.426Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/70/ae/3936f79adebf8caf81bd7a599b90a561334a658be4dcc7b6329ebf4ee8de/numpy-2.4.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:5884ce5c7acfae1e4e1b6fde43797d10aa506074d25b531b4f54bde33c0c31d4", size = 16664563, upload-time = "2026-03-09T07:57:43.817Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9b/62/760f2b55866b496bb1fa7da2a6db076bef908110e568b02fcfc1422e2a3a/numpy-2.4.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:297837823f5bc572c5f9379b0c9f3a3365f08492cbdc33bcc3af174372ebb168", size = 14702161, upload-time = "2026-03-09T07:57:46.169Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/32/af/a7a39464e2c0a21526fb4fb76e346fb172ebc92f6d1c7a07c2c139cc17b1/numpy-2.4.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:a111698b4a3f8dcbe54c64a7708f049355abd603e619013c346553c1fd4ca90b", size = 5208738, upload-time = "2026-03-09T07:57:48.506Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/29/8c/2a0cf86a59558fa078d83805589c2de490f29ed4fb336c14313a161d358a/numpy-2.4.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:4bd4741a6a676770e0e97fe9ab2e51de01183df3dcbcec591d26d331a40de950", size = 6543618, upload-time = "2026-03-09T07:57:50.591Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/aa/b8/612ce010c0728b1c363fa4ea3aa4c22fe1c5da1de008486f8c2f5cb92fae/numpy-2.4.3-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:54f29b877279d51e210e0c80709ee14ccbbad647810e8f3d375561c45ef613dd", size = 15680676, upload-time = "2026-03-09T07:57:52.34Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a9/7e/4f120ecc54ba26ddf3dc348eeb9eb063f421de65c05fc961941798feea18/numpy-2.4.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:679f2a834bae9020f81534671c56fd0cc76dd7e5182f57131478e23d0dc59e24", size = 16613492, upload-time = "2026-03-09T07:57:54.91Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2c/86/1b6020db73be330c4b45d5c6ee4295d59cfeef0e3ea323959d053e5a6909/numpy-2.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d84f0f881cb2225c2dfd7f78a10a5645d487a496c6668d6cc39f0f114164f3d0", size = 17031789, upload-time = "2026-03-09T07:57:57.641Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/07/3a/3b90463bf41ebc21d1b7e06079f03070334374208c0f9a1f05e4ae8455e7/numpy-2.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d213c7e6e8d211888cc359bab7199670a00f5b82c0978b9d1c75baf1eddbeac0", size = 18339941, upload-time = "2026-03-09T07:58:00.577Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a8/74/6d736c4cd962259fd8bae9be27363eb4883a2f9069763747347544c2a487/numpy-2.4.3-cp314-cp314-win32.whl", hash = "sha256:52077feedeff7c76ed7c9f1a0428558e50825347b7545bbb8523da2cd55c547a", size = 6007503, upload-time = "2026-03-09T07:58:03.331Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/48/39/c56ef87af669364356bb011922ef0734fc49dad51964568634c72a009488/numpy-2.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:0448e7f9caefb34b4b7dd2b77f21e8906e5d6f0365ad525f9f4f530b13df2afc", size = 12444915, upload-time = "2026-03-09T07:58:06.353Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9d/1f/ab8528e38d295fd349310807496fabb7cf9fe2e1f70b97bc20a483ea9d4a/numpy-2.4.3-cp314-cp314-win_arm64.whl", hash = "sha256:b44fd60341c4d9783039598efadd03617fa28d041fc37d22b62d08f2027fa0e7", size = 10494875, upload-time = "2026-03-09T07:58:08.734Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e6/ef/b7c35e4d5ef141b836658ab21a66d1a573e15b335b1d111d31f26c8ef80f/numpy-2.4.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0a195f4216be9305a73c0e91c9b026a35f2161237cf1c6de9b681637772ea657", size = 14822225, upload-time = "2026-03-09T07:58:11.034Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cd/8d/7730fa9278cf6648639946cc816e7cc89f0d891602584697923375f801ed/numpy-2.4.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:cd32fbacb9fd1bf041bf8e89e4576b6f00b895f06d00914820ae06a616bdfef7", size = 5328769, upload-time = "2026-03-09T07:58:13.67Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/47/01/d2a137317c958b074d338807c1b6a383406cdf8b8e53b075d804cc3d211d/numpy-2.4.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:2e03c05abaee1f672e9d67bc858f300b5ccba1c21397211e8d77d98350972093", size = 6649461, upload-time = "2026-03-09T07:58:15.912Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5c/34/812ce12bc0f00272a4b0ec0d713cd237cb390666eb6206323d1cc9cedbb2/numpy-2.4.3-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7d1ce23cce91fcea443320a9d0ece9b9305d4368875bab09538f7a5b4131938a", size = 15725809, upload-time = "2026-03-09T07:58:17.787Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/25/c0/2aed473a4823e905e765fee3dc2cbf504bd3e68ccb1150fbdabd5c39f527/numpy-2.4.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c59020932feb24ed49ffd03704fbab89f22aa9c0d4b180ff45542fe8918f5611", size = 16655242, upload-time = "2026-03-09T07:58:20.476Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f2/c8/7e052b2fc87aa0e86de23f20e2c42bd261c624748aa8efd2c78f7bb8d8c6/numpy-2.4.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9684823a78a6cd6ad7511fc5e25b07947d1d5b5e2812c93fe99d7d4195130720", size = 17080660, upload-time = "2026-03-09T07:58:23.067Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f3/3d/0876746044db2adcb11549f214d104f2e1be00f07a67edbb4e2812094847/numpy-2.4.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0200b25c687033316fb39f0ff4e3e690e8957a2c3c8d22499891ec58c37a3eb5", size = 18380384, upload-time = "2026-03-09T07:58:25.839Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/07/12/8160bea39da3335737b10308df4f484235fd297f556745f13092aa039d3b/numpy-2.4.3-cp314-cp314t-win32.whl", hash = "sha256:5e10da9e93247e554bb1d22f8edc51847ddd7dde52d85ce31024c1b4312bfba0", size = 6154547, upload-time = "2026-03-09T07:58:28.289Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/42/f3/76534f61f80d74cc9cdf2e570d3d4eeb92c2280a27c39b0aaf471eda7b48/numpy-2.4.3-cp314-cp314t-win_amd64.whl", hash = "sha256:45f003dbdffb997a03da2d1d0cb41fbd24a87507fb41605c0420a3db5bd4667b", size = 12633645, upload-time = "2026-03-09T07:58:30.384Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1f/b6/7c0d4334c15983cec7f92a69e8ce9b1e6f31857e5ee3a413ac424e6bd63d/numpy-2.4.3-cp314-cp314t-win_arm64.whl", hash = "sha256:4d382735cecd7bcf090172489a525cd7d4087bc331f7df9f60ddc9a296cf208e", size = 10565454, upload-time = "2026-03-09T07:58:33.031Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "opack2"
|
name = "opack2"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
@@ -740,6 +1085,45 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" },
|
{ url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "propcache"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442, upload-time = "2025-10-08T19:49:02.291Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8e/5c/bca52d654a896f831b8256683457ceddd490ec18d9ec50e97dfd8fc726a8/propcache-0.4.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3f7124c9d820ba5548d431afb4632301acf965db49e666aa21c305cbe8c6de12", size = 78152, upload-time = "2025-10-08T19:47:51.051Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/65/9b/03b04e7d82a5f54fb16113d839f5ea1ede58a61e90edf515f6577c66fa8f/propcache-0.4.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c0d4b719b7da33599dfe3b22d3db1ef789210a0597bc650b7cee9c77c2be8c5c", size = 44869, upload-time = "2025-10-08T19:47:52.594Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b2/fa/89a8ef0468d5833a23fff277b143d0573897cf75bd56670a6d28126c7d68/propcache-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9f302f4783709a78240ebc311b793f123328716a60911d667e0c036bc5dcbded", size = 46596, upload-time = "2025-10-08T19:47:54.073Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/86/bd/47816020d337f4a746edc42fe8d53669965138f39ee117414c7d7a340cfe/propcache-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c80ee5802e3fb9ea37938e7eecc307fb984837091d5fd262bb37238b1ae97641", size = 206981, upload-time = "2025-10-08T19:47:55.715Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/df/f6/c5fa1357cc9748510ee55f37173eb31bfde6d94e98ccd9e6f033f2fc06e1/propcache-0.4.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ed5a841e8bb29a55fb8159ed526b26adc5bdd7e8bd7bf793ce647cb08656cdf4", size = 211490, upload-time = "2025-10-08T19:47:57.499Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/80/1e/e5889652a7c4a3846683401a48f0f2e5083ce0ec1a8a5221d8058fbd1adf/propcache-0.4.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:55c72fd6ea2da4c318e74ffdf93c4fe4e926051133657459131a95c846d16d44", size = 215371, upload-time = "2025-10-08T19:47:59.317Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b2/f2/889ad4b2408f72fe1a4f6a19491177b30ea7bf1a0fd5f17050ca08cfc882/propcache-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8326e144341460402713f91df60ade3c999d601e7eb5ff8f6f7862d54de0610d", size = 201424, upload-time = "2025-10-08T19:48:00.67Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/27/73/033d63069b57b0812c8bd19f311faebeceb6ba31b8f32b73432d12a0b826/propcache-0.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:060b16ae65bc098da7f6d25bf359f1f31f688384858204fe5d652979e0015e5b", size = 197566, upload-time = "2025-10-08T19:48:02.604Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/dc/89/ce24f3dc182630b4e07aa6d15f0ff4b14ed4b9955fae95a0b54c58d66c05/propcache-0.4.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:89eb3fa9524f7bec9de6e83cf3faed9d79bffa560672c118a96a171a6f55831e", size = 193130, upload-time = "2025-10-08T19:48:04.499Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a9/24/ef0d5fd1a811fb5c609278d0209c9f10c35f20581fcc16f818da959fc5b4/propcache-0.4.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:dee69d7015dc235f526fe80a9c90d65eb0039103fe565776250881731f06349f", size = 202625, upload-time = "2025-10-08T19:48:06.213Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f5/02/98ec20ff5546f68d673df2f7a69e8c0d076b5abd05ca882dc7ee3a83653d/propcache-0.4.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5558992a00dfd54ccbc64a32726a3357ec93825a418a401f5cc67df0ac5d9e49", size = 204209, upload-time = "2025-10-08T19:48:08.432Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a0/87/492694f76759b15f0467a2a93ab68d32859672b646aa8a04ce4864e7932d/propcache-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c9b822a577f560fbd9554812526831712c1436d2c046cedee4c3796d3543b144", size = 197797, upload-time = "2025-10-08T19:48:09.968Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ee/36/66367de3575db1d2d3f3d177432bd14ee577a39d3f5d1b3d5df8afe3b6e2/propcache-0.4.1-cp314-cp314-win32.whl", hash = "sha256:ab4c29b49d560fe48b696cdcb127dd36e0bc2472548f3bf56cc5cb3da2b2984f", size = 38140, upload-time = "2025-10-08T19:48:11.232Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0c/2a/a758b47de253636e1b8aef181c0b4f4f204bf0dd964914fb2af90a95b49b/propcache-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:5a103c3eb905fcea0ab98be99c3a9a5ab2de60228aa5aceedc614c0281cf6153", size = 41257, upload-time = "2025-10-08T19:48:12.707Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/34/5e/63bd5896c3fec12edcbd6f12508d4890d23c265df28c74b175e1ef9f4f3b/propcache-0.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:74c1fb26515153e482e00177a1ad654721bf9207da8a494a0c05e797ad27b992", size = 38097, upload-time = "2025-10-08T19:48:13.923Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/99/85/9ff785d787ccf9bbb3f3106f79884a130951436f58392000231b4c737c80/propcache-0.4.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:824e908bce90fb2743bd6b59db36eb4f45cd350a39637c9f73b1c1ea66f5b75f", size = 81455, upload-time = "2025-10-08T19:48:15.16Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/90/85/2431c10c8e7ddb1445c1f7c4b54d886e8ad20e3c6307e7218f05922cad67/propcache-0.4.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2b5e7db5328427c57c8e8831abda175421b709672f6cfc3d630c3b7e2146393", size = 46372, upload-time = "2025-10-08T19:48:16.424Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/01/20/b0972d902472da9bcb683fa595099911f4d2e86e5683bcc45de60dd05dc3/propcache-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6f6ff873ed40292cd4969ef5310179afd5db59fdf055897e282485043fc80ad0", size = 48411, upload-time = "2025-10-08T19:48:17.577Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e2/e3/7dc89f4f21e8f99bad3d5ddb3a3389afcf9da4ac69e3deb2dcdc96e74169/propcache-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49a2dc67c154db2c1463013594c458881a069fcf98940e61a0569016a583020a", size = 275712, upload-time = "2025-10-08T19:48:18.901Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/20/67/89800c8352489b21a8047c773067644e3897f02ecbbd610f4d46b7f08612/propcache-0.4.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:005f08e6a0529984491e37d8dbc3dd86f84bd78a8ceb5fa9a021f4c48d4984be", size = 273557, upload-time = "2025-10-08T19:48:20.762Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e2/a1/b52b055c766a54ce6d9c16d9aca0cad8059acd9637cdf8aa0222f4a026ef/propcache-0.4.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5c3310452e0d31390da9035c348633b43d7e7feb2e37be252be6da45abd1abcc", size = 280015, upload-time = "2025-10-08T19:48:22.592Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/48/c8/33cee30bd890672c63743049f3c9e4be087e6780906bfc3ec58528be59c1/propcache-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c3c70630930447f9ef1caac7728c8ad1c56bc5015338b20fed0d08ea2480b3a", size = 262880, upload-time = "2025-10-08T19:48:23.947Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0c/b1/8f08a143b204b418285c88b83d00edbd61afbc2c6415ffafc8905da7038b/propcache-0.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8e57061305815dfc910a3634dcf584f08168a8836e6999983569f51a8544cd89", size = 260938, upload-time = "2025-10-08T19:48:25.656Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cf/12/96e4664c82ca2f31e1c8dff86afb867348979eb78d3cb8546a680287a1e9/propcache-0.4.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:521a463429ef54143092c11a77e04056dd00636f72e8c45b70aaa3140d639726", size = 247641, upload-time = "2025-10-08T19:48:27.207Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/18/ed/e7a9cfca28133386ba52278136d42209d3125db08d0a6395f0cba0c0285c/propcache-0.4.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:120c964da3fdc75e3731aa392527136d4ad35868cc556fd09bb6d09172d9a367", size = 262510, upload-time = "2025-10-08T19:48:28.65Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f5/76/16d8bf65e8845dd62b4e2b57444ab81f07f40caa5652b8969b87ddcf2ef6/propcache-0.4.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:d8f353eb14ee3441ee844ade4277d560cdd68288838673273b978e3d6d2c8f36", size = 263161, upload-time = "2025-10-08T19:48:30.133Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e7/70/c99e9edb5d91d5ad8a49fa3c1e8285ba64f1476782fed10ab251ff413ba1/propcache-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ab2943be7c652f09638800905ee1bab2c544e537edb57d527997a24c13dc1455", size = 257393, upload-time = "2025-10-08T19:48:31.567Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/08/02/87b25304249a35c0915d236575bc3574a323f60b47939a2262b77632a3ee/propcache-0.4.1-cp314-cp314t-win32.whl", hash = "sha256:05674a162469f31358c30bcaa8883cb7829fa3110bf9c0991fe27d7896c42d85", size = 42546, upload-time = "2025-10-08T19:48:32.872Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cb/ef/3c6ecf8b317aa982f309835e8f96987466123c6e596646d4e6a1dfcd080f/propcache-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:990f6b3e2a27d683cb7602ed6c86f15ee6b43b1194736f9baaeb93d0016633b1", size = 46259, upload-time = "2025-10-08T19:48:34.226Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c4/2d/346e946d4951f37eca1e4f55be0f0174c52cd70720f84029b02f296f4a38/propcache-0.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ecef2343af4cc68e05131e45024ba34f6095821988a9d0a02aa7c73fcc448aa9", size = 40428, upload-time = "2025-10-08T19:48:35.441Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "psutil"
|
name = "psutil"
|
||||||
version = "7.2.2"
|
version = "7.2.2"
|
||||||
@@ -791,16 +1175,14 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pycrashreport"
|
name = "pycrashreport"
|
||||||
version = "1.2.7"
|
version = "2.0.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "cached-property" },
|
{ name = "typer" },
|
||||||
{ name = "click" },
|
|
||||||
{ name = "la-panic" },
|
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/d5/0b/534e02c6badef117b5a4054c065b50e6055d833b983b024d57afb425b618/pycrashreport-1.2.7.tar.gz", hash = "sha256:8f4d52d3292c1ec479fac589633d1477d19fbeb6ab01960969389c6a9c63ed7f", size = 100834, upload-time = "2025-08-25T07:15:42.872Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/aa/9c/1e1c2d84f746972cbe4d5e65f816008c64e427fc680f55115aa313683c23/pycrashreport-2.0.0.tar.gz", hash = "sha256:31d5e32faa3a047fe01e923bde3eaf1ec86b23e264babf2fc8f7b61fe4812342", size = 102682, upload-time = "2026-03-30T22:35:19.705Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/09/ac/751f4e55f5f3de5f152a5891682da3c25a8c57c7058a2274ca5a430a9fe2/pycrashreport-1.2.7-py3-none-any.whl", hash = "sha256:70a448ec44b86b016ce81346552d32400cc2c51d7e1928420e98a37461319866", size = 33056, upload-time = "2025-08-25T07:15:41.323Z" },
|
{ url = "https://files.pythonhosted.org/packages/ed/ec/be636536ab13a63e3385a82c841d08ce2a51712ffc2a337cd24afc12e038/pycrashreport-2.0.0-py3-none-any.whl", hash = "sha256:12feb922c3349cdb33b468d105915f5f829c53df25640c5c2241bc4182bdb422", size = 34244, upload-time = "2026-03-30T22:35:18.478Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -897,6 +1279,25 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/96/17/58ee1f079114ea360601ccd331fd73032701abfe9278495e3dec0c35ef3f/pygnuutils-0.1.1-py3-none-any.whl", hash = "sha256:3b690540cc13f2c763250ee5cc647e9c81055d1002b1bcf7ac07ea6d259a21c5", size = 46351, upload-time = "2023-05-12T12:56:58.211Z" },
|
{ url = "https://files.pythonhosted.org/packages/96/17/58ee1f079114ea360601ccd331fd73032701abfe9278495e3dec0c35ef3f/pygnuutils-0.1.1-py3-none-any.whl", hash = "sha256:3b690540cc13f2c763250ee5cc647e9c81055d1002b1bcf7ac07ea6d259a21c5", size = 46351, upload-time = "2023-05-12T12:56:58.211Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyicloud"
|
||||||
|
version = "2.4.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "certifi" },
|
||||||
|
{ name = "click" },
|
||||||
|
{ name = "fido2" },
|
||||||
|
{ name = "keyring" },
|
||||||
|
{ name = "keyrings-alt" },
|
||||||
|
{ name = "requests" },
|
||||||
|
{ name = "srp" },
|
||||||
|
{ name = "tzlocal" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/0c/f0/48aeab9d92690b6a7cf31200159c369441cdae1ac9d93d6bf69c096bf001/pyicloud-2.4.1.tar.gz", hash = "sha256:9c13bc46e08cabd87c4d4418133b5a303f30c3ef0478b6d1b13aa74c2e5334f6", size = 141404, upload-time = "2026-02-21T17:08:18.109Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/36/d2/875b873d54d3bc7dad37b50fd255b357f8adaa105af5bb2b02443cafc783/pyicloud-2.4.1-py3-none-any.whl", hash = "sha256:a767ada7cc2961428f8c2d0ce327102ae7666e3835610945409247fcf9d85e68", size = 66974, upload-time = "2026-02-21T17:08:16.196Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyimg4"
|
name = "pyimg4"
|
||||||
version = "0.8.8"
|
version = "0.8.8"
|
||||||
@@ -935,14 +1336,56 @@ version = "0.3.4"
|
|||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/7d/dc/9ae75ede398b7adf538f2d1dca0f96c645c4e96789f8039340a0ed6a8a8f/pylzss-0.3.4.tar.gz", hash = "sha256:16818631742488e53a34fda0d402d80edb2b812e11877801e21a9e5ce9b9db1c", size = 25144, upload-time = "2023-11-24T00:26:37.787Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/7d/dc/9ae75ede398b7adf538f2d1dca0f96c645c4e96789f8039340a0ed6a8a8f/pylzss-0.3.4.tar.gz", hash = "sha256:16818631742488e53a34fda0d402d80edb2b812e11877801e21a9e5ce9b9db1c", size = 25144, upload-time = "2023-11-24T00:26:37.787Z" }
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pymd3-vue-location-sim"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = { editable = "." }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "click" },
|
||||||
|
{ name = "daemonize" },
|
||||||
|
{ name = "fastapi" },
|
||||||
|
{ name = "geopy", extra = ["aiohttp"] },
|
||||||
|
{ name = "httpx" },
|
||||||
|
{ name = "numpy" },
|
||||||
|
{ name = "pydantic" },
|
||||||
|
{ name = "pyicloud" },
|
||||||
|
{ name = "pymobiledevice3" },
|
||||||
|
{ name = "python-dotenv" },
|
||||||
|
{ name = "python-socketio" },
|
||||||
|
{ name = "sqlalchemy" },
|
||||||
|
{ name = "sqlalchemy-orm" },
|
||||||
|
{ name = "typer" },
|
||||||
|
{ name = "typing" },
|
||||||
|
{ name = "uvicorn" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.metadata]
|
||||||
|
requires-dist = [
|
||||||
|
{ name = "click", specifier = ">=8.3.1" },
|
||||||
|
{ name = "daemonize", specifier = ">=2.5.0" },
|
||||||
|
{ name = "fastapi", specifier = "==0.135.1" },
|
||||||
|
{ name = "geopy", extras = ["aiohttp"], specifier = "==2.4.1" },
|
||||||
|
{ name = "httpx", specifier = ">=0.28.1" },
|
||||||
|
{ name = "numpy", specifier = "==2.4.3" },
|
||||||
|
{ name = "pydantic", specifier = "==2.12.5" },
|
||||||
|
{ name = "pyicloud", specifier = ">=2.4.1" },
|
||||||
|
{ name = "pymobiledevice3", specifier = "==9.8.1" },
|
||||||
|
{ name = "python-dotenv", specifier = ">=1.2.2" },
|
||||||
|
{ name = "python-socketio", specifier = "==5.16.1" },
|
||||||
|
{ name = "sqlalchemy", specifier = ">=2.0.48" },
|
||||||
|
{ name = "sqlalchemy-orm", specifier = ">=1.2.10" },
|
||||||
|
{ name = "typer", specifier = ">=0.24.1" },
|
||||||
|
{ name = "typing", specifier = "==3.10.0.0" },
|
||||||
|
{ name = "uvicorn", specifier = "==0.41.0" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pymobiledevice3"
|
name = "pymobiledevice3"
|
||||||
version = "9.0.0"
|
version = "9.8.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "asn1" },
|
{ name = "asn1" },
|
||||||
{ name = "bpylist2" },
|
{ name = "bpylist2" },
|
||||||
{ name = "click" },
|
|
||||||
{ name = "coloredlogs" },
|
{ name = "coloredlogs" },
|
||||||
{ name = "construct" },
|
{ name = "construct" },
|
||||||
{ name = "construct-typing" },
|
{ name = "construct-typing" },
|
||||||
@@ -983,9 +1426,9 @@ dependencies = [
|
|||||||
{ name = "wsproto" },
|
{ name = "wsproto" },
|
||||||
{ name = "xonsh" },
|
{ name = "xonsh" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/1d/89/aed5abbb6a4ece29bed2b9e85ccfbc28a8197658a4923e8cd2d5193796d8/pymobiledevice3-9.0.0.tar.gz", hash = "sha256:e85c169d67cf17d1dcf4ce26e3a84a801e86d13a0144ff7fb57eb532745ddcfb", size = 735101, upload-time = "2026-03-11T08:37:05.172Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/a1/0e/81b8c391929cb2e2c9c831968df5c9cabc5687ab5d45fc9c345fcdb48171/pymobiledevice3-9.8.1.tar.gz", hash = "sha256:621479ad545795e52af1955e0cc6c8e807b51d81442173b3386f9d1fef21308a", size = 758015, upload-time = "2026-03-31T15:00:55.143Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/a6/ae/aaff1375b383c78729b6b25abac1458e9fd5c0c84b8da364bf204559dc16/pymobiledevice3-9.0.0-py3-none-any.whl", hash = "sha256:7366533cc8807299ef0b88c6c56a77120f7d984914ec6436191a7cc2991d3ae7", size = 789609, upload-time = "2026-03-11T08:37:01.731Z" },
|
{ url = "https://files.pythonhosted.org/packages/1a/58/3275db73730e99a6345231a7deeef5b184bd6a26b5dd40adefcb5ad0f84d/pymobiledevice3-9.8.1-py3-none-any.whl", hash = "sha256:9e1a5c8277a8a7955544579f118da8645f83ac05a1a03e79a96307242089842a", size = 797514, upload-time = "2026-03-31T15:00:53.169Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1009,6 +1452,15 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" },
|
{ url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "python-dotenv"
|
||||||
|
version = "1.2.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "python-engineio"
|
name = "python-engineio"
|
||||||
version = "4.13.1"
|
version = "4.13.1"
|
||||||
@@ -1071,6 +1523,15 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" },
|
{ url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pywin32-ctypes"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/85/9f/01a1a99704853cb63f253eea009390c88e7131c67e66a0a02099a8c917cb/pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755", size = 29471, upload-time = "2024-08-14T10:15:34.626Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8", size = 30756, upload-time = "2024-08-14T10:15:33.187Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "qh3"
|
name = "qh3"
|
||||||
version = "1.6.0"
|
version = "1.6.0"
|
||||||
@@ -1169,12 +1630,16 @@ wheels = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "setuptools"
|
name = "secretstorage"
|
||||||
version = "82.0.0"
|
version = "3.5.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/82/f3/748f4d6f65d1756b9ae577f329c951cda23fb900e4de9f70900ced962085/setuptools-82.0.0.tar.gz", hash = "sha256:22e0a2d69474c6ae4feb01951cb69d515ed23728cf96d05513d36e42b62b37cb", size = 1144893, upload-time = "2026-02-08T15:08:40.206Z" }
|
dependencies = [
|
||||||
|
{ name = "cryptography" },
|
||||||
|
{ name = "jeepney" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/1c/03/e834bcd866f2f8a49a85eaff47340affa3bfa391ee9912a952a1faa68c7b/secretstorage-3.5.0.tar.gz", hash = "sha256:f04b8e4689cbce351744d5537bf6b1329c6fc68f91fa666f60a380edddcd11be", size = 19884, upload-time = "2025-11-23T19:02:53.191Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/e1/c6/76dc613121b793286a3f91621d7b75a2b493e0390ddca50f11993eadf192/setuptools-82.0.0-py3-none-any.whl", hash = "sha256:70b18734b607bd1da571d097d236cfcfacaf01de45717d59e6e04b96877532e0", size = 1003468, upload-time = "2026-02-08T15:08:38.723Z" },
|
{ url = "https://files.pythonhosted.org/packages/b7/46/f5af3402b579fd5e11573ce652019a67074317e18c1935cc0b4ba9b35552/secretstorage-3.5.0-py3-none-any.whl", hash = "sha256:0ce65888c0725fcb2c5bc0fdb8e5438eece02c523557ea40ce0703c266248137", size = 15554, upload-time = "2025-11-23T19:02:51.545Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1207,6 +1672,56 @@ 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 = "sqlalchemy"
|
||||||
|
version = "2.0.48"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" },
|
||||||
|
{ name = "typing-extensions" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/1f/73/b4a9737255583b5fa858e0bb8e116eb94b88c910164ed2ed719147bde3de/sqlalchemy-2.0.48.tar.gz", hash = "sha256:5ca74f37f3369b45e1f6b7b06afb182af1fd5dde009e4ffd831830d98cbe5fe7", size = 9886075, upload-time = "2026-03-02T15:28:51.474Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f7/b3/f437eaa1cf028bb3c927172c7272366393e73ccd104dcf5b6963f4ab5318/sqlalchemy-2.0.48-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e2d0d88686e3d35a76f3e15a34e8c12d73fc94c1dea1cd55782e695cc14086dd", size = 2154401, upload-time = "2026-03-02T15:49:17.24Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6c/1c/b3abdf0f402aa3f60f0df6ea53d92a162b458fca2321d8f1f00278506402/sqlalchemy-2.0.48-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49b7bddc1eebf011ea5ab722fdbe67a401caa34a350d278cc7733c0e88fecb1f", size = 3274528, upload-time = "2026-03-02T15:50:41.489Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f2/5e/327428a034407651a048f5e624361adf3f9fbac9d0fa98e981e9c6ff2f5e/sqlalchemy-2.0.48-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:426c5ca86415d9b8945c7073597e10de9644802e2ff502b8e1f11a7a2642856b", size = 3279523, upload-time = "2026-03-02T15:53:32.962Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2a/ca/ece73c81a918add0965b76b868b7b5359e068380b90ef1656ee995940c02/sqlalchemy-2.0.48-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:288937433bd44e3990e7da2402fabc44a3c6c25d3704da066b85b89a85474ae0", size = 3224312, upload-time = "2026-03-02T15:50:42.996Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/88/11/fbaf1ae91fa4ee43f4fe79661cead6358644824419c26adb004941bdce7c/sqlalchemy-2.0.48-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8183dc57ae7d9edc1346e007e840a9f3d6aa7b7f165203a99e16f447150140d2", size = 3246304, upload-time = "2026-03-02T15:53:34.937Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fa/a8/5fb0deb13930b4f2f698c5541ae076c18981173e27dd00376dbaea7a9c82/sqlalchemy-2.0.48-cp314-cp314-win32.whl", hash = "sha256:1182437cb2d97988cfea04cf6cdc0b0bb9c74f4d56ec3d08b81e23d621a28cc6", size = 2116565, upload-time = "2026-03-02T15:54:38.321Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/95/7e/e83615cb63f80047f18e61e31e8e32257d39458426c23006deeaf48f463b/sqlalchemy-2.0.48-cp314-cp314-win_amd64.whl", hash = "sha256:144921da96c08feb9e2b052c5c5c1d0d151a292c6135623c6b2c041f2a45f9e0", size = 2142205, upload-time = "2026-03-02T15:54:39.831Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/83/e3/69d8711b3f2c5135e9cde5f063bc1605860f0b2c53086d40c04017eb1f77/sqlalchemy-2.0.48-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5aee45fd2c6c0f2b9cdddf48c48535e7471e42d6fb81adfde801da0bd5b93241", size = 3563519, upload-time = "2026-03-02T15:57:52.387Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f8/4f/a7cce98facca73c149ea4578981594aaa5fd841e956834931de503359336/sqlalchemy-2.0.48-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7cddca31edf8b0653090cbb54562ca027c421c58ddde2c0685f49ff56a1690e0", size = 3528611, upload-time = "2026-03-02T16:04:42.097Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cd/7d/5936c7a03a0b0cb0fa0cc425998821c6029756b0855a8f7ee70fba1de955/sqlalchemy-2.0.48-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7a936f1bb23d370b7c8cc079d5fce4c7d18da87a33c6744e51a93b0f9e97e9b3", size = 3472326, upload-time = "2026-03-02T15:57:54.423Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f4/33/cea7dfc31b52904efe3dcdc169eb4514078887dff1f5ae28a7f4c5d54b3c/sqlalchemy-2.0.48-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e004aa9248e8cb0a5f9b96d003ca7c1c0a5da8decd1066e7b53f59eb8ce7c62b", size = 3478453, upload-time = "2026-03-02T16:04:44.584Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c8/95/32107c4d13be077a9cae61e9ae49966a35dc4bf442a8852dd871db31f62e/sqlalchemy-2.0.48-cp314-cp314t-win32.whl", hash = "sha256:b8438ec5594980d405251451c5b7ea9aa58dda38eb7ac35fb7e4c696712ee24f", size = 2147209, upload-time = "2026-03-02T15:52:54.274Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d2/d7/1e073da7a4bc645eb83c76067284a0374e643bc4be57f14cc6414656f92c/sqlalchemy-2.0.48-cp314-cp314t-win_amd64.whl", hash = "sha256:d854b3970067297f3a7fbd7a4683587134aa9b3877ee15aa29eea478dc68f933", size = 2182198, upload-time = "2026-03-02T15:52:55.606Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/46/2c/9664130905f03db57961b8980b05cab624afd114bf2be2576628a9f22da4/sqlalchemy-2.0.48-py3-none-any.whl", hash = "sha256:a66fe406437dd65cacd96a72689a3aaaecaebbcd62d81c5ac1c0fdbeac835096", size = 1940202, upload-time = "2026-03-02T15:52:43.285Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sqlalchemy-orm"
|
||||||
|
version = "1.2.10"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "cached-property" },
|
||||||
|
{ name = "inflection" },
|
||||||
|
{ name = "sqlalchemy" },
|
||||||
|
{ name = "typing-inspect" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/c8/98/b0451ae949f8b16287965d4fc4a180fae50a78d9b186300e135ec22e1883/sqlalchemy-orm-1.2.10.tar.gz", hash = "sha256:7ab46d2a54a429d4fd384df9a37ad639dc87ff93be5205ed649c5ca4dad164bb", size = 21846, upload-time = "2023-05-20T09:18:19.064Z" }
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "srp"
|
||||||
|
version = "1.0.22"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "six" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/8d/fb/9210875dd162d3977580407b1c5ce6e779e770b8197a0de76819144a9755/srp-1.0.22.tar.gz", hash = "sha256:f330d0ec7387e2ac8577487b164963155d4a031bca6e2024f1b0930eb92baa5d", size = 22472, upload-time = "2024-11-01T21:52:54.006Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/89/75/5352c3ebd26e7d119042ae8de07354435a19c77fa2b44058fa97a1416783/srp-1.0.22-py3-none-any.whl", hash = "sha256:35aa8af053285a35683eb37182dcb2e46dbd85c7075d28e139f200d6bf16ea43", size = 25347, upload-time = "2024-11-01T21:52:53.021Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "srptools"
|
name = "srptools"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@@ -1332,6 +1847,19 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
|
{ url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typing-inspect"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "mypy-extensions" },
|
||||||
|
{ name = "typing-extensions" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/dc/74/1789779d91f1961fa9438e9a8710cdae6bd138c80d7303996933d117264a/typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78", size = 13825, upload-time = "2023-05-24T20:25:47.612Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f", size = 8827, upload-time = "2023-05-24T20:25:45.287Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typing-inspection"
|
name = "typing-inspection"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
@@ -1353,6 +1881,18 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" },
|
{ url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tzlocal"
|
||||||
|
version = "5.3.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "tzdata", marker = "sys_platform == 'win32'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/8b/2e/c14812d3d4d9cd1773c6be938f89e5735a1f11a9f184ac3639b93cef35d5/tzlocal-5.3.1.tar.gz", hash = "sha256:cceffc7edecefea1f595541dbd6e990cb1ea3d19bf01b2809f362a03dd7921fd", size = 30761, upload-time = "2025-03-05T21:17:41.549Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c2/14/e2a54fabd4f08cd7af1c07030603c3356b74da07f7cc056e600436edfa17/tzlocal-5.3.1-py3-none-any.whl", hash = "sha256:eb1a66c3ef5847adf7a834f1be0800581b683b5608e74f86ecbcef8ab91bb85d", size = 18026, upload-time = "2025-03-05T21:17:39.857Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "urllib3"
|
name = "urllib3"
|
||||||
version = "2.6.3"
|
version = "2.6.3"
|
||||||
@@ -1415,3 +1955,53 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/2e/c2/3dd498dc28d8f89cdd52e39950c5e591499ae423f61694c0bb4d03ed1d82/xonsh-0.22.4-py312-none-any.whl", hash = "sha256:4e538fac9f4c3d866ddbdeca068f0c0515469c997ed58d3bfee963878c6df5a5", size = 654300, upload-time = "2026-02-17T07:53:35.813Z" },
|
{ url = "https://files.pythonhosted.org/packages/2e/c2/3dd498dc28d8f89cdd52e39950c5e591499ae423f61694c0bb4d03ed1d82/xonsh-0.22.4-py312-none-any.whl", hash = "sha256:4e538fac9f4c3d866ddbdeca068f0c0515469c997ed58d3bfee963878c6df5a5", size = 654300, upload-time = "2026-02-17T07:53:35.813Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/82/7d/1f9c7147518e9f03f6ce081b5bfc4f1aceb6ec5caba849024d005e41d3be/xonsh-0.22.4-py313-none-any.whl", hash = "sha256:cc5fabf0ad0c56a2a11bed1e6a43c4ec6416a5b30f24f126b8e768547c3793e2", size = 654818, upload-time = "2026-02-17T07:53:33.477Z" },
|
{ url = "https://files.pythonhosted.org/packages/82/7d/1f9c7147518e9f03f6ce081b5bfc4f1aceb6ec5caba849024d005e41d3be/xonsh-0.22.4-py313-none-any.whl", hash = "sha256:cc5fabf0ad0c56a2a11bed1e6a43c4ec6416a5b30f24f126b8e768547c3793e2", size = 654818, upload-time = "2026-02-17T07:53:33.477Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yarl"
|
||||||
|
version = "1.23.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "idna" },
|
||||||
|
{ name = "multidict" },
|
||||||
|
{ name = "propcache" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/23/6e/beb1beec874a72f23815c1434518bfc4ed2175065173fb138c3705f658d4/yarl-1.23.0.tar.gz", hash = "sha256:53b1ea6ca88ebd4420379c330aea57e258408dd0df9af0992e5de2078dc9f5d5", size = 194676, upload-time = "2026-03-01T22:07:53.373Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/90/98/b85a038d65d1b92c3903ab89444f48d3cee490a883477b716d7a24b1a78c/yarl-1.23.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:21d1b7305a71a15b4794b5ff22e8eef96ff4a6d7f9657155e5aa419444b28912", size = 124455, upload-time = "2026-03-01T22:06:43.615Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/39/54/bc2b45559f86543d163b6e294417a107bb87557609007c007ad889afec18/yarl-1.23.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:85610b4f27f69984932a7abbe52703688de3724d9f72bceb1cca667deff27474", size = 86752, upload-time = "2026-03-01T22:06:45.425Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/24/f9/e8242b68362bffe6fb536c8db5076861466fc780f0f1b479fc4ffbebb128/yarl-1.23.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:23f371bd662cf44a7630d4d113101eafc0cfa7518a2760d20760b26021454719", size = 86291, upload-time = "2026-03-01T22:06:46.974Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ea/d8/d1cb2378c81dd729e98c716582b1ccb08357e8488e4c24714658cc6630e8/yarl-1.23.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4a80f77dc1acaaa61f0934176fccca7096d9b1ff08c8ba9cddf5ae034a24319", size = 99026, upload-time = "2026-03-01T22:06:48.459Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0a/ff/7196790538f31debe3341283b5b0707e7feb947620fc5e8236ef28d44f72/yarl-1.23.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:bd654fad46d8d9e823afbb4f87c79160b5a374ed1ff5bde24e542e6ba8f41434", size = 92355, upload-time = "2026-03-01T22:06:50.306Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c1/56/25d58c3eddde825890a5fe6aa1866228377354a3c39262235234ab5f616b/yarl-1.23.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:682bae25f0a0dd23a056739f23a134db9f52a63e2afd6bfb37ddc76292bbd723", size = 106417, upload-time = "2026-03-01T22:06:52.1Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/51/8a/882c0e7bc8277eb895b31bce0138f51a1ba551fc2e1ec6753ffc1e7c1377/yarl-1.23.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a82836cab5f197a0514235aaf7ffccdc886ccdaa2324bc0aafdd4ae898103039", size = 106422, upload-time = "2026-03-01T22:06:54.424Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/42/2b/fef67d616931055bf3d6764885990a3ac647d68734a2d6a9e1d13de437a2/yarl-1.23.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c57676bdedc94cd3bc37724cf6f8cd2779f02f6aba48de45feca073e714fe52", size = 101915, upload-time = "2026-03-01T22:06:55.895Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/18/6a/530e16aebce27c5937920f3431c628a29a4b6b430fab3fd1c117b26ff3f6/yarl-1.23.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c7f8dc16c498ff06497c015642333219871effba93e4a2e8604a06264aca5c5c", size = 100690, upload-time = "2026-03-01T22:06:58.21Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/88/08/93749219179a45e27b036e03260fda05190b911de8e18225c294ac95bbc9/yarl-1.23.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:5ee586fb17ff8f90c91cf73c6108a434b02d69925f44f5f8e0d7f2f260607eae", size = 98750, upload-time = "2026-03-01T22:06:59.794Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d9/cf/ea424a004969f5d81a362110a6ac1496d79efdc6d50c2c4b2e3ea0fc2519/yarl-1.23.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:17235362f580149742739cc3828b80e24029d08cbb9c4bda0242c7b5bc610a8e", size = 94685, upload-time = "2026-03-01T22:07:01.375Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e2/b7/14341481fe568e2b0408bcf1484c652accafe06a0ade9387b5d3fd9df446/yarl-1.23.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:0793e2bd0cf14234983bbb371591e6bea9e876ddf6896cdcc93450996b0b5c85", size = 106009, upload-time = "2026-03-01T22:07:03.151Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0a/e6/5c744a9b54f4e8007ad35bce96fbc9218338e84812d36f3390cea616881a/yarl-1.23.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:3650dc2480f94f7116c364096bc84b1d602f44224ef7d5c7208425915c0475dd", size = 100033, upload-time = "2026-03-01T22:07:04.701Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0c/23/e3bfc188d0b400f025bc49d99793d02c9abe15752138dcc27e4eaf0c4a9e/yarl-1.23.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f40e782d49630ad384db66d4d8b73ff4f1b8955dc12e26b09a3e3af064b3b9d6", size = 106483, upload-time = "2026-03-01T22:07:06.231Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/72/42/f0505f949a90b3f8b7a363d6cbdf398f6e6c58946d85c6d3a3bc70595b26/yarl-1.23.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:94f8575fbdf81749008d980c17796097e645574a3b8c28ee313931068dad14fe", size = 102175, upload-time = "2026-03-01T22:07:08.4Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/aa/65/b39290f1d892a9dd671d1c722014ca062a9c35d60885d57e5375db0404b5/yarl-1.23.0-cp314-cp314-win32.whl", hash = "sha256:c8aa34a5c864db1087d911a0b902d60d203ea3607d91f615acd3f3108ac32169", size = 83871, upload-time = "2026-03-01T22:07:09.968Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a9/5b/9b92f54c784c26e2a422e55a8d2607ab15b7ea3349e28359282f84f01d43/yarl-1.23.0-cp314-cp314-win_amd64.whl", hash = "sha256:63e92247f383c85ab00dd0091e8c3fa331a96e865459f5ee80353c70a4a42d70", size = 89093, upload-time = "2026-03-01T22:07:11.501Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e0/7d/8a84dc9381fd4412d5e7ff04926f9865f6372b4c2fd91e10092e65d29eb8/yarl-1.23.0-cp314-cp314-win_arm64.whl", hash = "sha256:70efd20be968c76ece7baa8dafe04c5be06abc57f754d6f36f3741f7aa7a208e", size = 83384, upload-time = "2026-03-01T22:07:13.069Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/dd/8d/d2fad34b1c08aa161b74394183daa7d800141aaaee207317e82c790b418d/yarl-1.23.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:9a18d6f9359e45722c064c97464ec883eb0e0366d33eda61cb19a244bf222679", size = 131019, upload-time = "2026-03-01T22:07:14.903Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/19/ff/33009a39d3ccf4b94d7d7880dfe17fb5816c5a4fe0096d9b56abceea9ac7/yarl-1.23.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:2803ed8b21ca47a43da80a6fd1ed3019d30061f7061daa35ac54f63933409412", size = 89894, upload-time = "2026-03-01T22:07:17.372Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0c/f1/dab7ac5e7306fb79c0190766a3c00b4cb8d09a1f390ded68c85a5934faf5/yarl-1.23.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:394906945aa8b19fc14a61cf69743a868bb8c465efe85eee687109cc540b98f4", size = 89979, upload-time = "2026-03-01T22:07:19.361Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/aa/b1/08e95f3caee1fad6e65017b9f26c1d79877b502622d60e517de01e72f95d/yarl-1.23.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:71d006bee8397a4a89f469b8deb22469fe7508132d3c17fa6ed871e79832691c", size = 95943, upload-time = "2026-03-01T22:07:21.266Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c0/cc/6409f9018864a6aa186c61175b977131f373f1988e198e031236916e87e4/yarl-1.23.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:62694e275c93d54f7ccedcfef57d42761b2aad5234b6be1f3e3026cae4001cd4", size = 88786, upload-time = "2026-03-01T22:07:23.129Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/76/40/cc22d1d7714b717fde2006fad2ced5efe5580606cb059ae42117542122f3/yarl-1.23.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a31de1613658308efdb21ada98cbc86a97c181aa050ba22a808120bb5be3ab94", size = 101307, upload-time = "2026-03-01T22:07:24.689Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8f/0d/476c38e85ddb4c6ec6b20b815bdd779aa386a013f3d8b85516feee55c8dc/yarl-1.23.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fb1e8b8d66c278b21d13b0a7ca22c41dd757a7c209c6b12c313e445c31dd3b28", size = 100904, upload-time = "2026-03-01T22:07:26.287Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/72/32/0abe4a76d59adf2081dcb0397168553ece4616ada1c54d1c49d8936c74f8/yarl-1.23.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50f9d8d531dfb767c565f348f33dd5139a6c43f5cbdf3f67da40d54241df93f6", size = 97728, upload-time = "2026-03-01T22:07:27.906Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b7/35/7b30f4810fba112f60f5a43237545867504e15b1c7647a785fbaf588fac2/yarl-1.23.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:575aa4405a656e61a540f4a80eaa5260f2a38fff7bfdc4b5f611840d76e9e277", size = 95964, upload-time = "2026-03-01T22:07:30.198Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2d/86/ed7a73ab85ef00e8bb70b0cb5421d8a2a625b81a333941a469a6f4022828/yarl-1.23.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:041b1a4cefacf65840b4e295c6985f334ba83c30607441ae3cf206a0eed1a2e4", size = 95882, upload-time = "2026-03-01T22:07:32.132Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/19/90/d56967f61a29d8498efb7afb651e0b2b422a1e9b47b0ab5f4e40a19b699b/yarl-1.23.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:d38c1e8231722c4ce40d7593f28d92b5fc72f3e9774fe73d7e800ec32299f63a", size = 90797, upload-time = "2026-03-01T22:07:34.404Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/72/00/8b8f76909259f56647adb1011d7ed8b321bcf97e464515c65016a47ecdf0/yarl-1.23.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:d53834e23c015ee83a99377db6e5e37d8484f333edb03bd15b4bc312cc7254fb", size = 101023, upload-time = "2026-03-01T22:07:35.953Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ac/e2/cab11b126fb7d440281b7df8e9ddbe4851e70a4dde47a202b6642586b8d9/yarl-1.23.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:2e27c8841126e017dd2a054a95771569e6070b9ee1b133366d8b31beb5018a41", size = 96227, upload-time = "2026-03-01T22:07:37.594Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c2/9b/2c893e16bfc50e6b2edf76c1a9eb6cb0c744346197e74c65e99ad8d634d0/yarl-1.23.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:76855800ac56f878847a09ce6dba727c93ca2d89c9e9d63002d26b916810b0a2", size = 100302, upload-time = "2026-03-01T22:07:39.334Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/28/ec/5498c4e3a6d5f1003beb23405671c2eb9cdbf3067d1c80f15eeafe301010/yarl-1.23.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e09fd068c2e169a7070d83d3bde728a4d48de0549f975290be3c108c02e499b4", size = 98202, upload-time = "2026-03-01T22:07:41.717Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fe/c3/cd737e2d45e70717907f83e146f6949f20cc23cd4bf7b2688727763aa458/yarl-1.23.0-cp314-cp314t-win32.whl", hash = "sha256:73309162a6a571d4cbd3b6a1dcc703c7311843ae0d1578df6f09be4e98df38d4", size = 90558, upload-time = "2026-03-01T22:07:43.433Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e1/19/3774d162f6732d1cfb0b47b4140a942a35ca82bb19b6db1f80e9e7bdc8f8/yarl-1.23.0-cp314-cp314t-win_amd64.whl", hash = "sha256:4503053d296bc6e4cbd1fad61cf3b6e33b939886c4f249ba7c78b602214fabe2", size = 97610, upload-time = "2026-03-01T22:07:45.773Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/51/47/3fa2286c3cb162c71cdb34c4224d5745a1ceceb391b2bd9b19b668a8d724/yarl-1.23.0-cp314-cp314t-win_arm64.whl", hash = "sha256:44bb7bef4ea409384e3f8bc36c063d77ea1b8d4a5b2706956c0d6695f07dcc25", size = 86041, upload-time = "2026-03-01T22:07:49.026Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/69/68/c8739671f5699c7dc470580a4f821ef37c32c4cb0b047ce223a7f115757f/yarl-1.23.0-py3-none-any.whl", hash = "sha256:a2df6afe50dea8ae15fa34c9f824a3ee958d785fd5d089063d960bae1daa0a3f", size = 48288, upload-time = "2026-03-01T22:07:51.388Z" },
|
||||||
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user