Merge backend/micro-services-restructuring into main #69
@@ -15,18 +15,18 @@ jobs:
|
||||
|
||||
- uses: https://gitea.com/actions/checkout@v4
|
||||
|
||||
- name: Install dependencies
|
||||
- name: Install pylint
|
||||
run: |
|
||||
apt-get update && apt-get install -y python3 python3-pip
|
||||
pip install pipenv
|
||||
pip install pylint
|
||||
|
||||
- name: Install packages
|
||||
run: |
|
||||
ls -la
|
||||
# only install dev-packages
|
||||
pipenv install --categories=dev-packages
|
||||
working-directory: backend
|
||||
# - name: Install packages
|
||||
# run: |
|
||||
# ls -la
|
||||
# # only install dev-packages
|
||||
# uv sync
|
||||
# working-directory: backend
|
||||
|
||||
- name: Run linter
|
||||
run: pipenv run pylint src --fail-under=9
|
||||
run: pylint src --fail-under=9
|
||||
working-directory: backend
|
||||
|
||||
6
backend/.gitignore
vendored
6
backend/.gitignore
vendored
@@ -2,7 +2,7 @@
|
||||
cache_XML/
|
||||
|
||||
# secrets
|
||||
*secrets.yaml
|
||||
*.env
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
@@ -12,8 +12,8 @@ __pycache__/
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Pytest reports
|
||||
report.html
|
||||
# Pytest html reports
|
||||
*.html
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
|
||||
@@ -1,16 +1,8 @@
|
||||
FROM python:3.12-slim-bookworm
|
||||
# use python 3.12 as a base image
|
||||
FROM docker.io/python:3.12-alpine
|
||||
|
||||
# The installer requires curl (and certificates) to download the release archive
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates
|
||||
|
||||
# Download the latest installer
|
||||
ADD https://astral.sh/uv/install.sh /uv-installer.sh
|
||||
|
||||
# Run the installer then remove it
|
||||
RUN sh /uv-installer.sh && rm /uv-installer.sh
|
||||
|
||||
# Ensure the installed binary is on the `PATH`
|
||||
ENV PATH="/root/.local/bin/:$PATH"
|
||||
# use the latest version of uv, independently of the python version
|
||||
|
kscheidecker marked this conversation as resolved
Outdated
|
||||
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
|
||||
|
||||
# Set the working directory
|
||||
WORKDIR /app
|
||||
|
||||
@@ -6,31 +6,31 @@ This repository contains the backend code for the application. It utilizes **Fas
|
||||
|
||||
### Directory Structure
|
||||
- The code for the Python application is located in the `src` directory.
|
||||
- Package management is handled with **pipenv**, and the dependencies are listed in the `Pipfile`.
|
||||
- Package management is handled with **uv**, and the dependencies are listed in the `pyproject.toml` file.
|
||||
- Since the application is designed to be deployed in a container, the `Dockerfile` is provided to build the image.
|
||||
|
||||
### Setting Up the Development Environment
|
||||
|
||||
To set up your development environment using **pipenv**, follow these steps:
|
||||
To set up your development environment using **uv**, follow these steps:
|
||||
|
||||
1. Install `pipenv` by running:
|
||||
1. Make sure you find yourself in the `backend` directory:
|
||||
```bash
|
||||
sudo apt install pipenv
|
||||
cd backend
|
||||
```
|
||||
|
||||
2. Create and activate a virtual environment:
|
||||
1. Install `uv` by running:
|
||||
```bash
|
||||
pipenv shell
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
```
|
||||
|
||||
3. Install the dependencies listed in the `Pipfile`:
|
||||
3. Install the dependencies listed in `pyproject.toml` and create the virtual environment at the same time:
|
||||
```bash
|
||||
pipenv install
|
||||
uv sync
|
||||
```
|
||||
|
||||
4. The virtual environment will be created under:
|
||||
```bash
|
||||
~/.local/share/virtualenvs/...
|
||||
backend/.venv/...
|
||||
```
|
||||
|
||||
### Deployment
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
def main():
|
||||
print("Hello from backend!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -10,6 +10,7 @@ dependencies = [
|
||||
"certifi==2024.12.14 ; python_full_version >= '3.6'",
|
||||
"charset-normalizer==3.4.1 ; python_full_version >= '3.7'",
|
||||
"click==8.1.8 ; python_full_version >= '3.7'",
|
||||
"dotenv>=0.9.9",
|
||||
"fastapi==0.115.7 ; python_full_version >= '3.8'",
|
||||
"fastapi-cli==0.0.7 ; python_full_version >= '3.8'",
|
||||
"h11==0.14.0 ; python_full_version >= '3.7'",
|
||||
@@ -20,6 +21,7 @@ dependencies = [
|
||||
"markdown-it-py==3.0.0 ; python_full_version >= '3.8'",
|
||||
"mdurl==0.1.2 ; python_full_version >= '3.7'",
|
||||
"numpy==2.2.2 ; python_full_version >= '3.10'",
|
||||
"paypalrestsdk>=1.13.3",
|
||||
"pulp==2.9.0 ; python_full_version >= '3.7'",
|
||||
"pydantic==2.10.6 ; python_full_version >= '3.8'",
|
||||
"pydantic-core==2.27.2 ; python_full_version >= '3.8'",
|
||||
@@ -36,6 +38,7 @@ dependencies = [
|
||||
"shellingham==1.5.4 ; python_full_version >= '3.7'",
|
||||
"sniffio==1.3.1 ; python_full_version >= '3.7'",
|
||||
"starlette==0.45.3 ; python_full_version >= '3.9'",
|
||||
"supabase>=2.16.0",
|
||||
"threadpoolctl==3.5.0 ; python_full_version >= '3.8'",
|
||||
"typer==0.15.1 ; python_full_version >= '3.7'",
|
||||
"typing-extensions==4.12.2 ; python_full_version >= '3.8'",
|
||||
|
||||
1094
backend/report.html
1094
backend/report.html
File diff suppressed because one or more lines are too long
@@ -28,6 +28,11 @@ This folder defines the commonly used data structures used within the project. T
|
||||
### src/tests
|
||||
This folder contains unit tests and test cases for the application's various modules. It is used to ensure the correctness and stability of the code.
|
||||
|
||||
Run the unit tests with the following command:
|
||||
```bash
|
||||
uv run pytest src --log-cli-level=DEBUG --html=report.html --self-contained-html
|
||||
```
|
||||
|
||||
### src/utils
|
||||
The `utils` folder contains utility classes and functions that provide core functionality for the application. The main component in this folder is the `LandmarkManager`, which is central to the process of fetching and organizing landmarks.
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
"""Module used for handling cache"""
|
||||
import hashlib
|
||||
|
||||
from pymemcache import serde
|
||||
from pymemcache.client.base import Client
|
||||
|
||||
@@ -73,3 +75,62 @@ else:
|
||||
encoding='utf-8',
|
||||
serde=serde.pickle_serde
|
||||
)
|
||||
|
||||
|
||||
#### Cache for payment architecture
|
||||
|
||||
def make_credit_cache_key(user_id: str, order_id: str) -> str:
|
||||
"""
|
||||
Generate a cache key from user_id and order_id using md5.
|
||||
|
||||
Args:
|
||||
user_id (str): The user's ID.
|
||||
order_id (str): The PayPal order ID.
|
||||
|
||||
Returns:
|
||||
str: A unique cache key.
|
||||
"""
|
||||
# Concatenate and hash to avoid collisions and keep key size small
|
||||
raw_key = f"{user_id}:{order_id}"
|
||||
return hashlib.md5(raw_key.encode('utf-8')).hexdigest()
|
||||
|
||||
|
||||
class CreditCache:
|
||||
"""
|
||||
Handles storing and retrieving credits to grant for a user/order.
|
||||
|
||||
Methods:
|
||||
set_credits(user_id, order_id, credits):
|
||||
Store the credits for a user/order.
|
||||
|
||||
get_credits(user_id, order_id):
|
||||
Retrieve the credits for a user/order.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def set_credits(user_id: str, order_id: str, credits_to_grant: int) -> None:
|
||||
"""
|
||||
Store the credits to be granted for a user/order.
|
||||
|
||||
Args:
|
||||
user_id (str): The user's ID.
|
||||
order_id (str): The PayPal order ID.
|
||||
credits (int): The amount of credits to grant.
|
||||
"""
|
||||
cache_key = make_credit_cache_key(user_id, order_id)
|
||||
client.set(cache_key, credits_to_grant)
|
||||
|
||||
@staticmethod
|
||||
def get_credits(user_id: str, order_id: str) -> int | None:
|
||||
"""
|
||||
Retrieve the credits to be granted for a user/order.
|
||||
|
||||
Args:
|
||||
user_id (str): The user's ID.
|
||||
order_id (str): The PayPal order ID.
|
||||
|
||||
Returns:
|
||||
int | None: The credits to grant, or None if not found.
|
||||
"""
|
||||
cache_key = make_credit_cache_key(user_id, order_id)
|
||||
return client.get(cache_key)
|
||||
|
||||
0
backend/src/configuration/__init__.py
Normal file
0
backend/src/configuration/__init__.py
Normal file
26
backend/src/configuration/environment.py
Normal file
26
backend/src/configuration/environment.py
Normal file
@@ -0,0 +1,26 @@
|
||||
"""This module is for loading variables from the environment and passes them throughout the code using the Environment dataclass"""
|
||||
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
|
||||
# Load variables from environment
|
||||
load_dotenv(override=True)
|
||||
|
remoll
commented
I don't like this. Under no circumstances should this run in prod. For testing purposes the dotenv should be loaded by the user. E.g. through I don't like this. Under no circumstances should this run in prod. For testing purposes the dotenv should be loaded by the user. E.g. through `launch.json`, or `direnv`.
remoll
commented
This should be fixed by #70 This should be fixed by #70
|
||||
|
||||
|
||||
@dataclass
|
||||
class Environment :
|
||||
|
||||
# Load supabase secrets
|
||||
supabase_url = os.environ['SUPABASE_URL']
|
||||
supabase_admin_key = os.environ['SUPABASE_ADMIN_KEY']
|
||||
supabase_test_user_id = os.environ['SUPABASE_TEST_USER_ID']
|
||||
|
||||
# Load paypal secrets
|
||||
paypal_id_sandbox = os.environ['PAYPAL_ID_SANDBOX']
|
||||
paypal_key_sandbox = os.environ['PAYPAL_KEY_SANDBOX']
|
||||
paypal_id_prod = os.environ['PAYPAL_ID_PROD']
|
||||
paypal_key_prod = os.environ['PAYPAL_KEY_PROD']
|
||||
|
||||
@@ -22,7 +22,6 @@ class LandmarkManager:
|
||||
church_coeff: float # coeff to adjsut score of churches
|
||||
nature_coeff: float # coeff to adjust score of parks
|
||||
overall_coeff: float # coeff to adjust weight of tags
|
||||
# n_important: int # number of important landmarks to consider
|
||||
|
||||
|
kscheidecker marked this conversation as resolved
Outdated
remoll
commented
Be brave! Delete it Be brave! Delete it
kscheidecker
commented
Removed in commit 510aabcb0a Removed in commit [510aabcb0a](https://git.kluster.moll.re/anydev/anyway/commit/510aabcb0a423b38114101a890aad87dc9417934)
|
||||
|
||||
def __init__(self) -> None:
|
||||
@@ -41,7 +40,6 @@ class LandmarkManager:
|
||||
self.wikipedia_bonus = parameters['wikipedia_bonus']
|
||||
self.viewpoint_bonus = parameters['viewpoint_bonus']
|
||||
self.pay_bonus = parameters['pay_bonus']
|
||||
# self.n_important = parameters['N_important']
|
||||
|
||||
with OPTIMIZER_PARAMETERS_PATH.open('r') as f:
|
||||
parameters = yaml.safe_load(f)
|
||||
@@ -187,6 +185,7 @@ class LandmarkManager:
|
||||
|
||||
# caution, when applying a list of selectors, overpass will search for elements that match ALL selectors simultaneously
|
||||
# we need to split the selectors into separate queries and merge the results
|
||||
# TODO: this can be multi-threaded once the Overpass rate-limit is not a problem anymore
|
||||
for sel in dict_to_selector_list(amenity_selector):
|
||||
# self.logger.debug(f"Current selector: {sel}")
|
||||
|
||||
|
||||
@@ -64,9 +64,10 @@ def get_landmarks(
|
||||
|
||||
@router.post("/get-nearby/landmarks/{lat}/{lon}")
|
||||
def get_landmarks_nearby(
|
||||
lat: float,
|
||||
lon: float
|
||||
) -> list[Landmark] :
|
||||
lat: float,
|
||||
lon: float,
|
||||
allow_clusters: bool = False
|
||||
) -> list[Landmark] :
|
||||
"""
|
||||
Suggests nearby landmarks based on a given latitude and longitude.
|
||||
|
||||
@@ -76,6 +77,7 @@ def get_landmarks_nearby(
|
||||
Args:
|
||||
lat (float): Latitude of the user's current location.
|
||||
lon (float): Longitude of the user's current location.
|
||||
allow_clusters (bool): Whether or not to allow the search for shopping/historical clusters when looking for nearby landmarks.
|
||||
|
||||
Returns:
|
||||
list[Landmark]: A list of selected nearby landmarks.
|
||||
@@ -104,7 +106,7 @@ def get_landmarks_nearby(
|
||||
landmarks_around = manager.generate_landmarks_list(
|
||||
center_coordinates = (lat, lon),
|
||||
|
kscheidecker marked this conversation as resolved
remoll
commented
should this be a landmark-parameter? No need to let the user choose that option. But it might be intersting to allow this to be set at runtime instead of hardcoding it. should this be a landmark-parameter? No need to let the user choose that option. But it might be intersting to allow this to be set at runtime instead of hardcoding it.
kscheidecker
commented
Also a good point! Implemented in commit bfc0c9adae Also a good point! Implemented in commit [bfc0c9adae](https://git.kluster.moll.re/anydev/anyway/commit/bfc0c9adae3877d59f4127e94e2a4916d9072a7b)
|
||||
preferences = prefs,
|
||||
allow_clusters=False,
|
||||
allow_clusters=allow_clusters,
|
||||
)
|
||||
|
||||
if len(landmarks_around) == 0 :
|
||||
|
||||
@@ -1,27 +1,18 @@
|
||||
"""Main app for backend api"""
|
||||
import logging
|
||||
from contextlib import asynccontextmanager
|
||||
from fastapi import FastAPI, HTTPException
|
||||
from fastapi import FastAPI
|
||||
|
||||
from .logging_config import configure_logging
|
||||
from .structs.landmark import Landmark
|
||||
from .structs.linked_landmarks import LinkedLandmarks
|
||||
from .structs.trip import Trip
|
||||
from .landmarks.landmarks_manager import LandmarkManager
|
||||
from .toilets.toilets_router import router as toilets_router
|
||||
from .optimization.optimization_router import router as optimization_router
|
||||
from .landmarks.landmarks_router import router as landmarks_router, get_landmarks_nearby
|
||||
from .optimization.optimizer import Optimizer
|
||||
from .optimization.refiner import Refiner
|
||||
from .cache import client as cache_client
|
||||
from .landmarks.landmarks_router import router as landmarks_router
|
||||
from .payments.payment_router import router as payment_router
|
||||
from .trips.trips_router import router as trips_router
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
manager = LandmarkManager()
|
||||
optimizer = Optimizer()
|
||||
refiner = Refiner(optimizer=optimizer)
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
@@ -32,6 +23,7 @@ async def lifespan(app: FastAPI):
|
||||
logger.info("Shutting down logging")
|
||||
|
||||
|
||||
# Create the fastapi app
|
||||
app = FastAPI(lifespan=lifespan)
|
||||
|
||||
|
||||
@@ -42,92 +34,26 @@ app = FastAPI(lifespan=lifespan)
|
||||
app.include_router(landmarks_router)
|
||||
|
||||
|
||||
# Optimizes the trip given preferences. Second step in the main trip generation pipeline
|
||||
# Optimizes the trip given preferences. Second step in the main trip generation pipeline.
|
||||
# Call with "/optimize/trip"
|
||||
app.include_router(optimization_router)
|
||||
|
||||
|
||||
# Fetches toilets near given coordinates.
|
||||
# Call with "/get/toilets" for fetching toilets around coordinates
|
||||
# Call with "/get/toilets" for fetching toilets around coordinates.
|
||||
app.include_router(toilets_router)
|
||||
|
||||
|
||||
|
||||
#### For already existing trips/landmarks
|
||||
@app.get("/trip/{trip_uuid}")
|
||||
def get_trip(trip_uuid: str) -> Trip:
|
||||
"""
|
||||
Look-up the cache for a trip that has been previously generated using its identifier.
|
||||
|
||||
Args:
|
||||
trip_uuid (str) : unique identifier for a trip.
|
||||
|
||||
Returns:
|
||||
(Trip) : the corresponding trip.
|
||||
"""
|
||||
try:
|
||||
trip = cache_client.get(f"trip_{trip_uuid}")
|
||||
return trip
|
||||
except KeyError as exc:
|
||||
logger.error(f"Failed to fetch trip with UUID {trip_uuid}: {str(exc)}")
|
||||
raise HTTPException(status_code=404, detail="Trip not found") from exc
|
||||
# Include the payment router for interacting with paypal sdk.
|
||||
# See src/payment/payment_router.py for more information on how to call.
|
||||
# Call with "/orders/new" to initiate a payment with an order request (step 1)
|
||||
# Call with "/orders/{order_id}/{user_id}capture" to capture a payment and grant the user the due credits (step 2)
|
||||
app.include_router(payment_router)
|
||||
|
||||
|
||||
@app.get("/landmark/{landmark_uuid}")
|
||||
def get_landmark(landmark_uuid: str) -> Landmark:
|
||||
"""
|
||||
Returns a Landmark from its unique identifier.
|
||||
|
||||
Args:
|
||||
landmark_uuid (str) : unique identifier for a Landmark.
|
||||
|
||||
Returns:
|
||||
(Landmark) : the corresponding Landmark.
|
||||
"""
|
||||
try:
|
||||
landmark = cache_client.get(f"landmark_{landmark_uuid}")
|
||||
return landmark
|
||||
except KeyError as exc:
|
||||
logger.error(f"Failed to fetch landmark with UUID {landmark_uuid}: {str(exc)}")
|
||||
raise HTTPException(status_code=404, detail="Landmark not found") from exc
|
||||
|
||||
|
||||
@app.post("/trip/recompute-time/{trip_uuid}/{removed_landmark_uuid}")
|
||||
def update_trip_time(trip_uuid: str, removed_landmark_uuid: str) -> Trip:
|
||||
"""
|
||||
Updates the reaching times of a given trip when removing a landmark.
|
||||
|
||||
Args:
|
||||
landmark_uuid (str) : unique identifier for a Landmark.
|
||||
|
||||
Returns:
|
||||
(Landmark) : the corresponding Landmark.
|
||||
"""
|
||||
# First, fetch the trip in the cache.
|
||||
try:
|
||||
trip = cache_client.get(f'trip_{trip_uuid}')
|
||||
except KeyError as exc:
|
||||
logger.error(f"Failed to update trip with UUID {trip_uuid} (trip not found): {str(exc)}")
|
||||
raise HTTPException(status_code=404, detail='Trip not found') from exc
|
||||
|
||||
landmarks = []
|
||||
next_uuid = trip.first_landmark_uuid
|
||||
|
||||
# Extract landmarks
|
||||
try :
|
||||
while next_uuid is not None:
|
||||
landmark = cache_client.get(f'landmark_{next_uuid}')
|
||||
# Filter out the removed landmark.
|
||||
if next_uuid != removed_landmark_uuid :
|
||||
landmarks.append(landmark)
|
||||
next_uuid = landmark.next_uuid # Prepare for the next iteration
|
||||
except KeyError as exc:
|
||||
logger.error(f"Failed to update trip with UUID {trip_uuid} : {str(exc)}")
|
||||
raise HTTPException(status_code=404, detail=f'landmark {next_uuid} not found') from exc
|
||||
|
||||
# Re-link every thing and compute times again
|
||||
linked_tour = LinkedLandmarks(landmarks)
|
||||
trip = Trip.from_linked_landmarks(linked_tour, cache_client)
|
||||
|
||||
return trip
|
||||
# Endpoint for putting together a trip, fetching landmarks by UUID and updating trip times. Three routes
|
||||
# Call with "/trip/{trip_uuid}" for getting trip by UUID.
|
||||
# Call with "/landmark/{landmark_uuid}" for getting landmark by UUID.
|
||||
# Call with "/trip//trip/recompute-time/{trip_uuid}/{removed_landmark_uuid}" for updating trip times.
|
||||
app.include_router(trips_router)
|
||||
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
import logging
|
||||
import time
|
||||
import yaml
|
||||
from fastapi import HTTPException, APIRouter, BackgroundTasks
|
||||
from fastapi import HTTPException, APIRouter, BackgroundTasks, Body
|
||||
|
||||
from .optimizer import Optimizer
|
||||
from .refiner import Refiner
|
||||
from ..supabase.supabase import SupabaseClient
|
||||
from ..structs.landmark import Landmark
|
||||
from ..structs.preferences import Preferences
|
||||
from ..structs.linked_landmarks import LinkedLandmarks
|
||||
@@ -20,6 +21,7 @@ from ..constants import OPTIMIZER_PARAMETERS_PATH
|
||||
logger = logging.getLogger(__name__)
|
||||
optimizer = Optimizer()
|
||||
refiner = Refiner(optimizer=optimizer)
|
||||
supabase = SupabaseClient()
|
||||
|
||||
|
||||
# Initialize the API router
|
||||
@@ -28,10 +30,11 @@ router = APIRouter()
|
||||
|
||||
@router.post("/optimize/trip")
|
||||
def optimize_trip(
|
||||
preferences: Preferences,
|
||||
landmarks: list[Landmark],
|
||||
start: tuple[float, float],
|
||||
end: tuple[float, float] | None = None,
|
||||
user_id: str = Body(...),
|
||||
preferences: Preferences = Body(...),
|
||||
landmarks: list[Landmark] = Body(...),
|
||||
start: tuple[float, float] = Body(...),
|
||||
end: tuple[float, float] | None = Body(None),
|
||||
background_tasks: BackgroundTasks = None
|
||||
) -> Trip:
|
||||
"""
|
||||
@@ -45,6 +48,22 @@ def optimize_trip(
|
||||
Returns:
|
||||
(uuid) : The uuid of the first landmark in the optimized route
|
||||
"""
|
||||
# Check for valid user balance
|
||||
try:
|
||||
if not supabase.check_balance(user_id=user_id):
|
||||
logger.warning('Insufficient credits to perform this action.')
|
||||
raise HTTPException(status_code=418, detail='Insufficient credits')
|
||||
except SyntaxError as se :
|
||||
logger.error(f'SyntaxError: {se}')
|
||||
raise HTTPException(status_code=400, detail=str(se)) from se
|
||||
except ValueError as ve :
|
||||
logger.error(f'SyntaxError: {ve}')
|
||||
raise HTTPException(status_code=406, detail=str(ve)) from ve
|
||||
except Exception as exc:
|
||||
logger.error(f'SyntaxError: {exc}')
|
||||
raise HTTPException(status_code=500, detail=f"Internal Server Error: {str(exc)}") from exc
|
||||
|
||||
# Check for invalid input
|
||||
if preferences is None:
|
||||
raise HTTPException(status_code=406, detail="Preferences not provided or incomplete.")
|
||||
if len(landmarks) == 0 :
|
||||
@@ -135,7 +154,11 @@ def optimize_trip(
|
||||
logger.info(f'Optimized a trip of {trip.total_time} minutes with {len(refined_tour)} landmarks in {round(t_first_stage + t_second_stage,3)} seconds.')
|
||||
logger.info('Detailed trip :\n\t' + '\n\t'.join(f'{landmark}' for landmark in refined_tour))
|
||||
|
||||
# Add the cache fill as background task
|
||||
background_tasks.add_task(fill_cache)
|
||||
|
||||
# Finally, decrement the user balance
|
||||
supabase.decrement_credit_balance(user_id=user_id)
|
||||
|
||||
return trip
|
||||
|
||||
|
||||
0
backend/src/payments/__init__.py
Normal file
0
backend/src/payments/__init__.py
Normal file
328
backend/src/payments/payment_handler.py
Normal file
328
backend/src/payments/payment_handler.py
Normal file
@@ -0,0 +1,328 @@
|
||||
import json
|
||||
import logging
|
||||
from typing import Literal
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import requests
|
||||
from pydantic import BaseModel, Field
|
||||
from fastapi.responses import RedirectResponse
|
||||
|
||||
from ..supabase.supabase import SupabaseClient
|
||||
from ..structs.shop import Item, BasketItem
|
||||
from ..configuration.environment import Environment
|
||||
from ..cache import CreditCache, make_credit_cache_key
|
||||
|
||||
|
||||
# Intialize the logger
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Define the base URL, might move that to toml file
|
||||
BASE_URL_PROD = 'https://api-m.paypal.com'
|
||||
BASE_URL_SANDBOX = 'https://api-m.sandbox.paypal.com'
|
||||
|
||||
|
||||
|
||||
class OrderRequest(BaseModel):
|
||||
"""
|
||||
Represents an order request from the frontend.
|
||||
|
||||
Attributes:
|
||||
user_id (str): The ID of the user placing the order.
|
||||
basket (list[BasketItem]): List of basket items.
|
||||
currency (str): The currency code for the order.
|
||||
created_at (datetime): Timestamp when the order was created.
|
||||
updated_at (datetime): Timestamp when the order was last updated.
|
||||
items (list[Item]): List of item details loaded from the database.
|
||||
total_price (float): Total price of the order.
|
||||
"""
|
||||
user_id: str
|
||||
basket: list[BasketItem]
|
||||
currency: Literal['CHF', 'EUR', 'USD']
|
||||
created_at: datetime = Field(default_factory=datetime.now)
|
||||
updated_at: datetime = Field(default_factory=datetime.now)
|
||||
items: list[Item] = Field(default_factory=list)
|
||||
total_price: float = None
|
||||
total_credits: int = None
|
||||
|
||||
|
||||
# @field_validator('basket')
|
||||
def validate_basket(cls, v):
|
||||
"""Validates the basket items.
|
||||
|
||||
Args:
|
||||
v (list): List of basket items.
|
||||
|
||||
Raises:
|
||||
|
remoll marked this conversation as resolved
Outdated
remoll
commented
Pretty sure that won't work. It should definitely not be hardcoded since the callback will change depending on prod or staging. Pretty sure that won't work. It should definitely not be hardcoded since the callback will change depending on prod or staging.
|
||||
ValueError: If basket does not contain valid BasketItem objects.
|
||||
|
||||
Returns:
|
||||
list: The validated basket.
|
||||
"""
|
||||
if not v:
|
||||
raise ValueError("Basket cannot be empty")
|
||||
|
||||
# Pydantic already converts dict -> BasketItem, so isinstance works
|
||||
if not all(isinstance(i, BasketItem) for i in v):
|
||||
raise ValueError("Basket must contain BasketItem objects")
|
||||
|
||||
return v
|
||||
|
||||
|
||||
def load_items_and_price(self, supabase: SupabaseClient):
|
||||
# This should be automatic upon initialization of the class
|
||||
"""
|
||||
Loads item details from database and calculates the total price as well as the total credits to be granted.
|
||||
"""
|
||||
self.items = []
|
||||
self.total_price = 0
|
||||
self.total_credits = 0
|
||||
for basket_item in self.basket:
|
||||
item = supabase.get_item(basket_item.item_id, self.currency)
|
||||
self.items.append(item)
|
||||
self.total_price += item.unit_price * basket_item.quantity # increment price
|
||||
self.total_credits += item.unit_credits * basket_item.quantity # increment credit balance
|
||||
|
||||
|
||||
def to_paypal_items(self):
|
||||
"""
|
||||
Converts items to the PayPal API item format.
|
||||
|
||||
Returns:
|
||||
list: List of items formatted for PayPal API.
|
||||
"""
|
||||
item_list = []
|
||||
|
||||
for basket_item, item in zip(self.basket, self.items):
|
||||
item_list.append({
|
||||
'id': item.item_id,
|
||||
'name': item.name,
|
||||
'description': item.description,
|
||||
'quantity': str(basket_item.quantity),
|
||||
'unit_amount': {
|
||||
'currency_code': self.currency,
|
||||
'value': str(item.unit_price)
|
||||
}
|
||||
})
|
||||
return item_list
|
||||
|
||||
|
||||
# Payment handler class for managing PayPal payments
|
||||
class PaypalClient:
|
||||
"""
|
||||
Handles PayPal payment operations.
|
||||
|
||||
Attributes:
|
||||
sandbox (bool): Whether to use the sandbox environment.
|
||||
id (str): PayPal client ID.
|
||||
key (str): PayPal client secret.
|
||||
base_url (str): Base URL for PayPal API.
|
||||
_token_cache (dict): Cache for the PayPal OAuth access token.
|
||||
"""
|
||||
|
||||
_token_cache = {
|
||||
"access_token": None,
|
||||
"expires_at": 0
|
||||
}
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
sandbox_mode: bool = False
|
||||
):
|
||||
"""
|
||||
Initializes the handler.
|
||||
|
||||
Args:
|
||||
sandbox_mode (bool): Whether to use sandbox credentials.
|
||||
"""
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.sandbox = sandbox_mode
|
||||
|
||||
# PayPal keys
|
||||
if sandbox_mode :
|
||||
self.id = Environment.paypal_id_sandbox
|
||||
self.key = Environment.paypal_key_sandbox
|
||||
self.base_url = BASE_URL_SANDBOX
|
||||
else :
|
||||
self.id = Environment.paypal_id_prod
|
||||
self.key = Environment.paypal_key_prod
|
||||
self.base_url = BASE_URL_PROD
|
||||
|
||||
def _get_access_token(self) -> str | None:
|
||||
"""
|
||||
Gets (and caches) a PayPal access token.
|
||||
|
||||
Returns:
|
||||
str | None: The access token if successful, None otherwise.
|
||||
"""
|
||||
now = datetime.now()
|
||||
# Check if token is still valid
|
||||
if (
|
||||
self._token_cache["access_token"] is not None
|
||||
and self._token_cache["expires_at"] > now
|
||||
):
|
||||
self.logger.info('Returning (cached) access token.')
|
||||
return self._token_cache["access_token"]
|
||||
|
||||
# Request new token
|
||||
validation_data = {'grant_type': 'client_credentials'}
|
||||
|
||||
try:
|
||||
# pass the request
|
||||
validation_response = requests.post(
|
||||
url = f'{self.base_url}/v1/oauth2/token',
|
||||
data = validation_data,
|
||||
auth =(self.id, self.key)
|
||||
)
|
||||
|
||||
except Exception as exc:
|
||||
self.logger.error(f'Error while requesting access token: {exc}')
|
||||
return None
|
||||
|
||||
data = validation_response.json()
|
||||
access_token = data.get("access_token")
|
||||
expires_in = int(data.get("expires_in", 3600)) # seconds, default 1 hour
|
||||
|
||||
# Cache the token and its expiry
|
||||
self._token_cache["access_token"] = access_token
|
||||
self._token_cache["expires_at"] = now + timedelta(seconds=expires_in - 60) # buffer 1 min
|
||||
|
||||
self.logger.info('Returning (new) access token.')
|
||||
return access_token
|
||||
|
||||
|
||||
def order(
|
||||
self,
|
||||
order_request: OrderRequest,
|
||||
supabase_client: SupabaseClient,
|
||||
return_url_success: str,
|
||||
return_url_failure: str
|
||||
):
|
||||
"""
|
||||
Creates a new PayPal order.
|
||||
|
||||
Args:
|
||||
order_request (OrderRequest): The order request.
|
||||
|
||||
Returns:
|
||||
dict | None: PayPal order response JSON, or None if failed.
|
||||
"""
|
||||
|
||||
# Fetch details of order from mart database and compute total credits and price
|
||||
order_request.load_items_and_price(supabase=supabase_client)
|
||||
|
||||
# Prepare payload for post request to paypal API
|
||||
order_data = {
|
||||
'intent': 'CAPTURE',
|
||||
'purchase_units': [
|
||||
{
|
||||
'items': order_request.to_paypal_items(),
|
||||
'amount': {
|
||||
'currency_code': order_request.currency,
|
||||
'value': str(order_request.total_price),
|
||||
'breakdown': {
|
||||
'item_total': {
|
||||
'currency_code': order_request.currency,
|
||||
'value': str(order_request.total_price)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
# No redirect from paypal
|
||||
'application_context': {
|
||||
# 'return_url': f'https://anydev.info/orders/{json.loads(order_response.text)["id"]}/{order_request.user_id}capture', # This returns to backend capture-payment URL
|
||||
# 'cancel_url': return_url_failure
|
||||
'return_url': 'https://anydev.info/api/paypal/capture',
|
||||
'cancel_url': return_url_failure
|
||||
}
|
||||
}
|
||||
|
||||
# Get the access_token:
|
||||
access_token = self._get_access_token()
|
||||
|
||||
try:
|
||||
order_response = requests.post(
|
||||
url = f'{self.base_url}/v2/checkout/orders',
|
||||
headers = {'Authorization': f'Bearer {access_token}'},
|
||||
json = order_data,
|
||||
)
|
||||
|
||||
# Raise HTTP Exception if request was unsuccessful.
|
||||
except Exception as exc:
|
||||
self.logger.error(f'Error creating PayPal order: {exc}')
|
||||
return None
|
||||
|
||||
try:
|
||||
order_response.raise_for_status()
|
||||
except:
|
||||
return RedirectResponse(url=return_url_failure)
|
||||
|
||||
user_id = order_request.user_id
|
||||
order_id = json.loads(order_response.text)["id"]
|
||||
|
||||
# TODO Now that we have the order ID, we can inscribe the details in sql database using the order id given by paypal
|
||||
# DB for storing the transaction records:
|
||||
|
||||
# order_id (key): json.loads(order_response.text)["id"]
|
||||
# user_id : order_request.user_id
|
||||
# created_at : order_request.created_at
|
||||
# status : PENDING
|
||||
# basket (json) : OrderDetails.jsonify()
|
||||
# total_price : order_request.total_price
|
||||
# currency : order_request.currency
|
||||
# updated_at : order_request.created_at
|
||||
|
||||
# Create a cache item for credits to be granted to user
|
||||
CreditCache.set_credits(
|
||||
user_id = user_id,
|
||||
order_id = order_id,
|
||||
credits_to_grant = order_request.total_credits)
|
||||
|
||||
|
||||
# return order_response.json()
|
||||
return RedirectResponse(url=f'https://anydev.info/orders/{order_id}/{user_id}capture')
|
||||
|
||||
|
||||
# Standalone function to capture a payment
|
||||
def capture(self, user_id: str, order_id: str):
|
||||
"""
|
||||
Captures payment for a PayPal order.
|
||||
|
||||
Args:
|
||||
order_id (str): The PayPal order ID.
|
||||
|
||||
Returns:
|
||||
dict | None: PayPal capture response JSON, or None if failed.
|
||||
"""
|
||||
# Get the access_token:
|
||||
access_token = self._get_access_token()
|
||||
|
||||
try:
|
||||
capture_response = requests.post(
|
||||
url = f'{self.base_url}/v2/checkout/orders/{order_id}/capture',
|
||||
headers = {'Authorization': f'Bearer {access_token}'},
|
||||
json = {},
|
||||
)
|
||||
except Exception as exc:
|
||||
logger.error(f'Error while requesting access token: {exc}')
|
||||
return None
|
||||
|
||||
# Raise exception if API call failed
|
||||
capture_response.raise_for_status()
|
||||
|
||||
|
||||
|
||||
# print(capture_response.text)
|
||||
|
||||
# TODO: update status to PAID in sql database
|
||||
|
||||
# where order_id (key) = order_id
|
||||
# status : 'PAID'
|
||||
# updated_at : datetime.now()
|
||||
|
||||
|
||||
# Not sure yet if/how to implement that
|
||||
def cancel(self):
|
||||
|
||||
pass
|
||||
169
backend/src/payments/payment_router.py
Normal file
169
backend/src/payments/payment_router.py
Normal file
@@ -0,0 +1,169 @@
|
||||
import logging
|
||||
|
||||
from fastapi import APIRouter, Query, Body
|
||||
from fastapi.responses import RedirectResponse
|
||||
|
||||
from .payment_handler import PaypalClient, OrderRequest
|
||||
from ..supabase.supabase import SupabaseClient
|
||||
from ..structs.shop import BasketItem
|
||||
from ..cache import CreditCache, make_credit_cache_key
|
||||
|
||||
|
||||
# Create a PayPal & Supabase client
|
||||
paypal_client = PaypalClient(sandbox_mode=False)
|
||||
supabase = SupabaseClient()
|
||||
|
||||
# Initialize the API router
|
||||
router = APIRouter()
|
||||
|
||||
# Initialize the logger
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# TODO: add the return url in the API payload to redirect the user to the app.
|
||||
@router.post("/orders/new")
|
||||
def create_order(
|
||||
user_id: str = Query(...),
|
||||
currency: str = Query(...),
|
||||
return_url_success: str = Query('https://anydev.info/orders/success'),
|
||||
return_url_failure: str = Query('https://anydev.info/orders/failed'),
|
||||
basket: list[BasketItem] = Body(...),
|
||||
):
|
||||
"""
|
||||
Creates a new PayPal order.
|
||||
|
||||
Args:
|
||||
user_id (str): The ID of the user placing the order.
|
||||
basket (list): The basket items.
|
||||
currency (str): The currency code.
|
||||
|
||||
Returns:
|
||||
dict: The PayPal order details.
|
||||
"""
|
||||
|
||||
# Create order :
|
||||
order = OrderRequest(
|
||||
user_id = user_id,
|
||||
basket=basket,
|
||||
currency=currency,
|
||||
supabase_client=supabase
|
||||
)
|
||||
|
||||
# Process the order and return the details
|
||||
return paypal_client.order(
|
||||
order_request=order,
|
||||
return_url_success=return_url_success,
|
||||
return_url_failure=return_url_failure)
|
||||
|
||||
|
||||
|
||||
@router.post("/orders/{order_id}/{user_id}capture")
|
||||
def capture_order(order_id: str, user_id: str):
|
||||
"""
|
||||
Captures payment for an existing PayPal order.
|
||||
|
||||
Args:
|
||||
order_id (str): The PayPal order ID.
|
||||
|
||||
Returns:
|
||||
dict: The PayPal capture response.
|
||||
"""
|
||||
# Capture the payment
|
||||
result = paypal_client.capture(order_id)
|
||||
|
||||
# Grant the user the correct amount of credits:
|
||||
credits = CreditCache.get_credits(user_id, order_id)
|
||||
if credits:
|
||||
supabase.increment_credit_balance(
|
||||
user_id=user_id,
|
||||
amount=credits
|
||||
)
|
||||
logger.info(f'Payment capture succeeded: incrementing balance of user {user_id} by {credits}.')
|
||||
return RedirectResponse(url='https://anydev.info/orders/success')
|
||||
|
||||
logger.error(f'Capture payment failed. Could not find cache key for user {user_id} and order {order_id}')
|
||||
|
||||
return RedirectResponse(url='https://anydev.info/orders/failed')
|
||||
|
||||
|
||||
|
||||
|
||||
# import logging
|
||||
# import paypalrestsdk
|
||||
# from fastapi import HTTPException, APIRouter
|
||||
|
||||
# from ..supabase.supabase import SupabaseClient
|
||||
# from .payment_handler import PaymentRequest, PaymentHandler
|
||||
|
||||
# # Set up logging and supabase
|
||||
# logger = logging.getLogger(__name__)
|
||||
# supabase = SupabaseClient()
|
||||
|
||||
# # Configure PayPal SDK
|
||||
# paypalrestsdk.configure({
|
||||
# "mode": "sandbox", # Use 'live' for production
|
||||
# "client_id": "YOUR_PAYPAL_CLIENT_ID",
|
||||
# "client_secret": "YOUR_PAYPAL_SECRET"
|
||||
# })
|
||||
|
||||
|
||||
# # Define the API router
|
||||
# router = APIRouter()
|
||||
|
||||
# @router.post("/purchase/credits")
|
||||
# def purchase_credits(payment_request: PaymentRequest):
|
||||
# """
|
||||
# Handles token purchases. Calculates the number of tokens based on the amount paid,
|
||||
# updates the user's balance, and processes PayPal payment.
|
||||
# """
|
||||
# payment_handler = PaymentHandler(payment_request)
|
||||
|
||||
# # Create PayPal payment and get the approval URL
|
||||
# approval_url = payment_handler.create_paypal_payment()
|
||||
|
||||
# return {
|
||||
# "message": "Purchase initiated successfully",
|
||||
# "payment_id": payment_handler.payment_id,
|
||||
# "credits": payment_request.credit_amount,
|
||||
# "approval_url": approval_url,
|
||||
# }
|
||||
|
||||
|
||||
# @router.get("/payment/success")
|
||||
# def payment_success(paymentId: str, PayerID: str):
|
||||
# """
|
||||
# Handles successful PayPal payment.
|
||||
# """
|
||||
# payment = paypalrestsdk.Payment.find(paymentId)
|
||||
|
||||
# if payment.execute({"payer_id": PayerID}):
|
||||
# logger.info("Payment executed successfully")
|
||||
|
||||
# # Retrieve transaction details from the database
|
||||
# result = supabase.table("pending_payments").select("*").eq("payment_id", paymentId).single().execute()
|
||||
# if not result.data:
|
||||
# raise HTTPException(status_code=404, detail="Transaction not found")
|
||||
|
||||
# # Extract the necessary information
|
||||
# user_id = result.data["user_id"]
|
||||
# credit_amount = result.data["credit_amount"]
|
||||
|
||||
# # Update the user's balance
|
||||
# supabase.increment_credit_balance(user_id, amount=credit_amount)
|
||||
|
||||
# # Optionally, delete the pending payment entry since the transaction is completed
|
||||
# supabase.table("pending_payments").delete().eq("payment_id", paymentId).execute()
|
||||
|
||||
# return {"message": "Payment completed successfully"}
|
||||
# else:
|
||||
# logger.error(f"Payment execution failed: {payment.error}")
|
||||
# raise HTTPException(status_code=500, detail="Payment execution failed")
|
||||
|
||||
|
||||
# @router.get("/payment/cancel")
|
||||
# def payment_cancel():
|
||||
# """
|
||||
# Handles PayPal payment cancellation.
|
||||
# """
|
||||
# return {"message": "Payment was cancelled"}
|
||||
|
||||
111
backend/src/payments/test.py
Normal file
111
backend/src/payments/test.py
Normal file
@@ -0,0 +1,111 @@
|
||||
#%%
|
||||
import requests
|
||||
import json
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# username and password
|
||||
load_dotenv(override=True)
|
||||
username = os.environ['PAYPAL_ID_SANDBOX']
|
||||
password = os.environ['PAYPAL_KEY_SANDBOX']
|
||||
|
||||
|
||||
# DOCUMENTATION AT : https://developer.paypal.com/api/rest/requests/
|
||||
|
||||
|
||||
#%%
|
||||
######## STEP 1: Validation ########
|
||||
# url for validation post request
|
||||
validation_url = "https://api-m.sandbox.paypal.com/v1/oauth2/token"
|
||||
validation_url_prod = "https://api-m.paypal.com/v1/oauth2/token"
|
||||
|
||||
# payload for the post request
|
||||
validation_data = {'grant_type': 'client_credentials'}
|
||||
|
||||
# pass the request
|
||||
validation_response = requests.post(
|
||||
url=validation_url,
|
||||
data=validation_data,
|
||||
auth=(username, password)
|
||||
)
|
||||
|
||||
# todo check status code + try except. Status code 201 ?
|
||||
print(f'Reponse status code: {validation_response.status_code}')
|
||||
print(f'Access token: {json.loads(validation_response.text)["access_token"]}')
|
||||
access_token = json.loads(validation_response.text)["access_token"]
|
||||
|
||||
|
||||
#%%
|
||||
######## STEP 2: Create Order ########
|
||||
# url for post request
|
||||
order_url = "https://api-m.sandbox.paypal.com/v2/checkout/orders"
|
||||
order_url_prod = "https://api-m.paypal.com/v2/checkout/orders"
|
||||
|
||||
# payload for the request
|
||||
order_data = {
|
||||
"intent": "CAPTURE",
|
||||
"purchase_units": [
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"name": "AnyWay Credits",
|
||||
"description": "50 pack of credits",
|
||||
"quantity": 1,
|
||||
"unit_amount": {
|
||||
"currency_code": "CHF",
|
||||
"value": "1.50"
|
||||
}
|
||||
|
||||
}
|
||||
],
|
||||
"amount": {
|
||||
"currency_code": "CHF",
|
||||
"value": "1.50",
|
||||
"breakdown": {
|
||||
"item_total": {
|
||||
"currency_code": "CHF",
|
||||
"value": "1.50"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"application_context": {
|
||||
"return_url": "https://anydev.info",
|
||||
"cancel_url": "https://anydev.info"
|
||||
}
|
||||
}
|
||||
|
||||
order_response = requests.post(
|
||||
url=order_url,
|
||||
headers={"Authorization": f"Bearer {access_token}"}, ## need access token here?
|
||||
json=order_data,
|
||||
auth=(username, password)
|
||||
)
|
||||
|
||||
# Send the redirect link to the user
|
||||
# print(order_response.json())
|
||||
for link_obj in order_response.json()['links']:
|
||||
if link_obj['rel'] == 'approve':
|
||||
forward_to_user_link = link_obj['href']
|
||||
print(f'Reponse status code: {order_response.status_code}')
|
||||
print(f'Follow this link to proceed to payment: {forward_to_user_link}')
|
||||
order_id = json.loads(order_response.text)["id"]
|
||||
|
||||
|
||||
#%%
|
||||
######## STEP 3: capture payment
|
||||
# url for post request
|
||||
capture_url = f"https://api-m.sandbox.paypal.com/v2/checkout/orders/{order_id}/capture"
|
||||
# capture_url_prod = f"https://api-m.paypal.com/v2/checkout/orders/{order_id}/capture"
|
||||
|
||||
capture_response = requests.post(
|
||||
url=capture_url,
|
||||
json={},
|
||||
auth=(username, password)
|
||||
)
|
||||
|
||||
# todo check status code + try except
|
||||
print(f'Reponse status code: {capture_response.status_code}')
|
||||
print(capture_response.text)
|
||||
# order_id = json.loads(response.text)["id"]
|
||||
@@ -39,3 +39,16 @@ class Preferences(BaseModel) :
|
||||
|
||||
max_time_minute: Optional[int] = 3*60
|
||||
detour_tolerance_minute: Optional[int] = 0
|
||||
|
||||
|
||||
def model_post_init(self, __context):
|
||||
"""
|
||||
Method to validate proper initialization of individual Preferences.
|
||||
Raises ValueError if the Preference type does not match with the field name.
|
||||
"""
|
||||
if self.sightseeing.type != 'sightseeing':
|
||||
raise ValueError(f'The sightseeing preference cannot be {self.sightseeing.type}.')
|
||||
if self.nature.type != 'nature':
|
||||
raise ValueError(f'The nature preference cannot be {self.nature.type}.')
|
||||
if self.shopping.type != 'shopping':
|
||||
raise ValueError(f'The shopping preference cannot be {self.shopping.type}.')
|
||||
32
backend/src/structs/shop.py
Normal file
32
backend/src/structs/shop.py
Normal file
@@ -0,0 +1,32 @@
|
||||
"""Module to handle classes related to online shop"""
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class BasketItem(BaseModel):
|
||||
"""
|
||||
Represents a single item in the user's basket.
|
||||
|
||||
Attributes:
|
||||
item_id (int): The unique identifier for the item.
|
||||
quantity (int): The number of units of the item.
|
||||
"""
|
||||
item_id: int
|
||||
quantity: int
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
"""
|
||||
Represents an item available in the shop.
|
||||
|
||||
Attributes:
|
||||
item_id (int): The unique identifier for the item.
|
||||
name (str): The name of the item.
|
||||
description (str): The description of the item.
|
||||
unit_price (float): The unit price of the item.
|
||||
"""
|
||||
item_id: int
|
||||
name: str
|
||||
description: str
|
||||
unit_price: float
|
||||
unit_credits: int
|
||||
currency: str
|
||||
0
backend/src/supabase/__init__.py
Normal file
0
backend/src/supabase/__init__.py
Normal file
248
backend/src/supabase/supabase.py
Normal file
248
backend/src/supabase/supabase.py
Normal file
@@ -0,0 +1,248 @@
|
||||
import logging
|
||||
|
||||
from fastapi import HTTPException, status
|
||||
from supabase import create_client, Client, ClientOptions
|
||||
|
||||
from ..structs.shop import Item
|
||||
from ..configuration.environment import Environment
|
||||
|
||||
# Silence the supabase logger
|
||||
logging.getLogger("httpx").setLevel(logging.CRITICAL)
|
||||
logging.getLogger("hpack").setLevel(logging.CRITICAL)
|
||||
logging.getLogger("httpcore").setLevel(logging.CRITICAL)
|
||||
|
||||
|
||||
class SupabaseClient:
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def __init__(self):
|
||||
|
||||
self.SUPABASE_URL = Environment.supabase_url
|
||||
self.SUPABASE_ADMIN_KEY = Environment.supabase_admin_key
|
||||
self.SUPABASE_TEST_USER_ID = Environment.supabase_test_user_id
|
||||
|
||||
self.supabase = create_client(
|
||||
self.SUPABASE_URL,
|
||||
self.SUPABASE_ADMIN_KEY,
|
||||
options=ClientOptions(schema='public')
|
||||
)
|
||||
self.logger.info('Supabase client initialized.')
|
||||
|
||||
|
||||
def check_balance(self, user_id: str) -> bool:
|
||||
"""
|
||||
Checks if the user has enough 'credit' for generating a new trip.
|
||||
|
||||
Args:
|
||||
user_id (str): The ID of the current user.
|
||||
|
||||
Returns:
|
||||
bool: True if the balance is positive, False otherwise.
|
||||
"""
|
||||
try:
|
||||
# Query the public.credits table to get the user's credits
|
||||
response = (
|
||||
self.supabase.table("credits")
|
||||
.select('*')
|
||||
.eq('id', user_id)
|
||||
.single()
|
||||
.execute()
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
if e.code == '22P02' :
|
||||
self.logger.error(f"Failed querying credits : {str(e)}")
|
||||
raise SyntaxError(f"Failed querying credits : {str(e)}") from e
|
||||
if e.code == 'PGRST116' :
|
||||
self.logger.error(f"User not found : {str(e)}")
|
||||
raise ValueError(f"User not found : {str(e)}") from e
|
||||
else :
|
||||
self.logger.error(f"An unexpected error occured while checking user balance : {str(e)}")
|
||||
raise Exception(f"An unexpected error occured while checking user balance : {str(e)}") from e
|
||||
|
||||
# Proceed to check the user's credit balance
|
||||
credits = response.data['credit_amount']
|
||||
self.logger.debug(f'Credits of user {user_id}: {credits}')
|
||||
|
||||
if credits > 0:
|
||||
self.logger.info(f'Credit balance is positive for user {user_id}. Proceeding with trip generation.')
|
||||
return True
|
||||
|
||||
self.logger.warning(f'Insufficient balance for user {user_id}. Trip generation cannot proceed.')
|
||||
return False
|
||||
|
||||
|
||||
def decrement_credit_balance(self, user_id: str, amount: int=1) -> bool:
|
||||
"""
|
||||
Decrements the user's credit balance by 1.
|
||||
|
||||
Args:
|
||||
user_id (str): The ID of the current user.
|
||||
"""
|
||||
try:
|
||||
# Query the public.credits table to get the user's current credits
|
||||
response = (
|
||||
self.supabase.table("credits")
|
||||
.select('*')
|
||||
.eq('id', user_id)
|
||||
.single()
|
||||
.execute()
|
||||
)
|
||||
except Exception as e:
|
||||
if e.code == '22P02' :
|
||||
self.logger.error(f"Failed decrementing credits : {str(e)}")
|
||||
raise SyntaxError(f"Failed decrementing credits : {str(e)}") from e
|
||||
if e.code == 'PGRST116' :
|
||||
self.logger.error(f"User not found : {str(e)}")
|
||||
raise ValueError(f"User not found : {str(e)}") from e
|
||||
else :
|
||||
self.logger.error(f"An unexpected error occured while decrementing user balance : {str(e)}")
|
||||
raise Exception(f"An unexpected error occured while decrementing user balance : {str(e)}") from e
|
||||
|
||||
|
||||
current_credits = response.data['credit_amount']
|
||||
updated_credits = current_credits - amount
|
||||
|
||||
# Update the user's credits in the table
|
||||
update_response = (
|
||||
self.supabase.table('credits')
|
||||
.update({'credit_amount': updated_credits})
|
||||
.eq('id', user_id)
|
||||
.execute()
|
||||
)
|
||||
|
||||
# Check if the update was successful
|
||||
if update_response.data:
|
||||
self.logger.debug(f'Credit balance successfully decremented.')
|
||||
return True
|
||||
else:
|
||||
raise Exception("Error decrementing credit balance.")
|
||||
|
||||
|
||||
def increment_credit_balance(self, user_id: str, amount: int=1) -> bool:
|
||||
"""
|
||||
Increments the user's credit balance by 1.
|
||||
|
||||
Args:
|
||||
user_id (str): The ID of the current user.
|
||||
"""
|
||||
try:
|
||||
# Query the public.credits table to get the user's current credits
|
||||
response = (
|
||||
self.supabase.table("credits")
|
||||
.select('*')
|
||||
.eq('id', user_id)
|
||||
.single()
|
||||
.execute()
|
||||
)
|
||||
except Exception as e:
|
||||
if e.code == '22P02' :
|
||||
self.logger.error(f"Failed incrementing credits : {str(e)}")
|
||||
raise SyntaxError(f"Failed incrementing credits : {str(e)}") from e
|
||||
if e.code == 'PGRST116' :
|
||||
self.logger.error(f"User not found : {str(e)}")
|
||||
raise ValueError(f"User not found : {str(e)}") from e
|
||||
else :
|
||||
self.logger.error(f"An unexpected error occured while incrementing user balance : {str(e)}")
|
||||
raise Exception(f"An unexpected error occured while incrementing user balance : {str(e)}") from e
|
||||
|
||||
|
||||
current_credits = response.data['credit_amount']
|
||||
updated_credits = current_credits + amount
|
||||
|
||||
# Update the user's credits in the table
|
||||
update_response = (
|
||||
self.supabase.table('credits')
|
||||
.update({'credit_amount': updated_credits})
|
||||
.eq('id', user_id)
|
||||
.execute()
|
||||
)
|
||||
|
||||
# Check if the update was successful
|
||||
if update_response.data:
|
||||
self.logger.debug(f'Credit balance successfully incremented.')
|
||||
return True
|
||||
else:
|
||||
raise Exception("Error incrementing credit balance.")
|
||||
|
||||
|
||||
def get_item(self, item_id: int, currency: str) -> Item | None:
|
||||
"""
|
||||
Fetch full item info (name, description) and price/credits for a given currency.
|
||||
Returns an Item pydantic model.
|
||||
"""
|
||||
# First, validate the currency
|
||||
self.validate_currency(currency=currency)
|
||||
|
||||
try:
|
||||
# Fetch from items table
|
||||
base_item = (
|
||||
self.supabase
|
||||
.table("items")
|
||||
.select("*")
|
||||
.eq("item_id", item_id)
|
||||
.single()
|
||||
.execute()
|
||||
).data
|
||||
except Exception as e:
|
||||
self.logger.error(f'Failed to fetch item {item_id}: {e}')
|
||||
raise ValueError(f"Failed to fetch item {item_id}: {e}")
|
||||
|
||||
try:
|
||||
# Fetch price for this currency and item_id
|
||||
price = (
|
||||
self.supabase
|
||||
.table("item_prices")
|
||||
.select("*")
|
||||
.eq("item_id", item_id)
|
||||
.eq("currency", currency.upper())
|
||||
.single()
|
||||
.execute()
|
||||
).data
|
||||
except Exception as e:
|
||||
self.logger.error(f'Failed to fetch price for {item_id} in {currency}: {e}')
|
||||
raise ValueError(f"Failed to fetch price for {item_id} in {currency}: {e}")
|
||||
|
||||
# Return Item model
|
||||
return Item(
|
||||
item_id=base_item["item_id"],
|
||||
name=base_item["name"],
|
||||
description=base_item["description"],
|
||||
unit_price=price["unit_price"],
|
||||
unit_credits=price["unit_credits"],
|
||||
currency=price["currency"]
|
||||
)
|
||||
|
||||
|
||||
def validate_currency(self, currency: str) -> bool:
|
||||
"""
|
||||
Validates that a currency exists in the available_currencies table
|
||||
and is active.
|
||||
|
||||
Args:
|
||||
currency (str): Currency code (e.g. 'EUR', 'USD', 'CHF').
|
||||
|
||||
Returns:
|
||||
dict: The currency row.
|
||||
|
||||
Raises:
|
||||
ValueError: If currency does not exist or is inactive.
|
||||
"""
|
||||
try:
|
||||
result = (
|
||||
self.supabase
|
||||
.table("available_currencies")
|
||||
.select("*")
|
||||
.eq("currency", currency.upper())
|
||||
.single()
|
||||
.execute()
|
||||
)
|
||||
except Exception as exc:
|
||||
self.logger.error(f'Unable to validate currency {currency}, most likely not supported yet: {exc}')
|
||||
raise ValueError(f"Could not validate '{currency}', most likely not supported yet: {exc}")
|
||||
|
||||
if result.data['active'] is not True:
|
||||
raise ValueError(f"Currency '{currency}' is currently not supported.")
|
||||
|
||||
return True
|
||||
53
backend/src/tests/test_payment.py
Normal file
53
backend/src/tests/test_payment.py
Normal file
@@ -0,0 +1,53 @@
|
||||
"""Collection of tests to ensure correct implementation and track progress of paypal payments."""
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
import pytest
|
||||
|
||||
from ..main import app
|
||||
from ..supabase.supabase import SupabaseClient
|
||||
|
||||
|
||||
# Create a supabase client
|
||||
supabase = SupabaseClient()
|
||||
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def client():
|
||||
"""Client used to call the app."""
|
||||
return TestClient(app)
|
||||
|
||||
|
||||
def test_nearby(client): # pylint: disable=redefined-outer-name
|
||||
"""
|
||||
Test n°1 : Verify handling of invalid input.
|
||||
|
||||
Args:
|
||||
client:
|
||||
request:
|
||||
"""
|
||||
response = client.post(
|
||||
url=f"/orders/new/",
|
||||
json={
|
||||
'user_id': supabase.SUPABASE_TEST_USER_ID,
|
||||
'basket': {
|
||||
{
|
||||
'id': '1873672819',
|
||||
'quantity': 1982
|
||||
},
|
||||
{
|
||||
'id': '9876789',
|
||||
'quantity': 1982
|
||||
}
|
||||
},
|
||||
'currency': 'CHF',
|
||||
'return_url_success': 'https://anydev.info',
|
||||
'return_url_failure': 'https://anydev.info'
|
||||
}
|
||||
)
|
||||
suggestions = response.json()
|
||||
|
||||
# checks :
|
||||
assert response.status_code == 200 # check for successful planning
|
||||
assert isinstance(suggestions, list) # check that the return type is a list
|
||||
assert len(suggestions) > 0
|
||||
@@ -4,10 +4,15 @@ from fastapi.testclient import TestClient
|
||||
import pytest
|
||||
|
||||
from .test_utils import load_trip_landmarks, log_trip_details
|
||||
from ..supabase.supabase import SupabaseClient
|
||||
from ..structs.preferences import Preferences, Preference
|
||||
from ..main import app
|
||||
|
||||
|
||||
# Create a supabase client
|
||||
supabase = SupabaseClient()
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def client():
|
||||
"""Client used to call the app."""
|
||||
@@ -51,21 +56,34 @@ def test_trip(client, request, sightseeing, shopping, nature, max_time_minute, s
|
||||
"preferences": prefs.model_dump(),
|
||||
"start": start_coords,
|
||||
"end": end_coords,
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
landmarks = response.json()
|
||||
|
||||
# Step 2: Feed the landmarks to the optimizer to compute the trip
|
||||
response = client.post(
|
||||
"/optimize/trip",
|
||||
json={
|
||||
"user_id": supabase.SUPABASE_TEST_USER_ID,
|
||||
"preferences": prefs.model_dump(),
|
||||
"landmarks": landmarks,
|
||||
"start": start,
|
||||
"end": end,
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
# Increment the user balance again
|
||||
supabase.increment_credit_balance(
|
||||
supabase.SUPABASE_TEST_USER_ID,
|
||||
amount=1
|
||||
)
|
||||
|
||||
# Parse the response
|
||||
result = response.json()
|
||||
# print(result)
|
||||
landmarks = load_trip_landmarks(client, result['first_landmark_uuid'])
|
||||
|
||||
# Get computation time
|
||||
@@ -75,7 +93,6 @@ def test_trip(client, request, sightseeing, shopping, nature, max_time_minute, s
|
||||
log_trip_details(request, landmarks, result['total_time'], prefs.max_time_minute)
|
||||
|
||||
# checks :
|
||||
assert response.status_code == 200 # check for successful planning
|
||||
assert comp_time < 30, f"Computation time exceeded 30 seconds: {comp_time:.2f} seconds"
|
||||
assert prefs.max_time_minute*0.8 < result['total_time'], f"Trip too short: {result['total_time']} instead of {prefs.max_time_minute}"
|
||||
assert prefs.max_time_minute*1.2 > result['total_time'], f"Trip too long: {result['total_time']} instead of {prefs.max_time_minute}"
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
"""Helper methods for testing."""
|
||||
import time
|
||||
import logging
|
||||
from functools import wraps
|
||||
from fastapi import HTTPException
|
||||
|
||||
from ..cache import client as cache_client
|
||||
from ..structs.landmark import Landmark
|
||||
from ..structs.preferences import Preferences, Preference
|
||||
|
||||
|
||||
def landmarks_to_osmid(landmarks: list[Landmark]) -> list[int] :
|
||||
@@ -94,34 +91,3 @@ def log_trip_details(request, landmarks: list[Landmark], duration: int, target_d
|
||||
request.node.trip_details = trip_string
|
||||
request.node.trip_duration = str(duration) # result['total_time']
|
||||
request.node.target_duration = str(target_duration)
|
||||
|
||||
|
||||
|
||||
|
||||
def trip_params(
|
||||
sightseeing: int,
|
||||
shopping: int,
|
||||
nature: int,
|
||||
max_time_minute: int,
|
||||
start_coords: tuple[float, float] = None,
|
||||
end_coords: tuple[float, float] = None,
|
||||
):
|
||||
def decorator(test_func):
|
||||
@wraps(test_func)
|
||||
def wrapper(client, request):
|
||||
prefs = Preferences(
|
||||
sightseeing=Preference(type='sightseeing', score=sightseeing),
|
||||
shopping=Preference(type='shopping', score=shopping),
|
||||
nature=Preference(type='nature', score=nature),
|
||||
max_time_minute=max_time_minute,
|
||||
detour_tolerance_minute=0,
|
||||
)
|
||||
|
||||
start = start_coords
|
||||
end = end_coords
|
||||
|
||||
# Inject into test function
|
||||
return test_func(client, request, prefs, start, end)
|
||||
|
||||
return wrapper
|
||||
return decorator
|
||||
0
backend/src/trips/__init__.py
Normal file
0
backend/src/trips/__init__.py
Normal file
104
backend/src/trips/trips_router.py
Normal file
104
backend/src/trips/trips_router.py
Normal file
@@ -0,0 +1,104 @@
|
||||
import logging
|
||||
from fastapi import HTTPException, APIRouter
|
||||
|
||||
from ..structs.landmark import Landmark
|
||||
from ..structs.linked_landmarks import LinkedLandmarks
|
||||
from ..structs.trip import Trip
|
||||
from ..landmarks.landmarks_manager import LandmarkManager
|
||||
from ..optimization.optimizer import Optimizer
|
||||
from ..optimization.refiner import Refiner
|
||||
from ..cache import client as cache_client
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
manager = LandmarkManager()
|
||||
optimizer = Optimizer()
|
||||
refiner = Refiner(optimizer=optimizer)
|
||||
|
||||
|
||||
# Initialize the API router
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
#### For already existing trips/landmarks
|
||||
@router.get("/trip/{trip_uuid}")
|
||||
def get_trip(trip_uuid: str) -> Trip:
|
||||
"""
|
||||
Look-up the cache for a trip that has been previously generated using its identifier.
|
||||
|
||||
Args:
|
||||
trip_uuid (str) : unique identifier for a trip.
|
||||
|
||||
Returns:
|
||||
(Trip) : the corresponding trip.
|
||||
"""
|
||||
try:
|
||||
trip = cache_client.get(f"trip_{trip_uuid}")
|
||||
return trip
|
||||
except KeyError as exc:
|
||||
logger.error(f"Failed to fetch trip with UUID {trip_uuid}: {str(exc)}")
|
||||
raise HTTPException(status_code=404, detail="Trip not found") from exc
|
||||
|
||||
|
||||
# Fetch a landmark from memcached by its uuid
|
||||
@router.get("/landmark/{landmark_uuid}")
|
||||
def get_landmark(landmark_uuid: str) -> Landmark:
|
||||
"""
|
||||
Returns a Landmark from its unique identifier.
|
||||
|
||||
Args:
|
||||
landmark_uuid (str) : unique identifier for a Landmark.
|
||||
|
||||
Returns:
|
||||
(Landmark) : the corresponding Landmark.
|
||||
"""
|
||||
try:
|
||||
landmark = cache_client.get(f"landmark_{landmark_uuid}")
|
||||
return landmark
|
||||
except KeyError as exc:
|
||||
logger.error(f"Failed to fetch landmark with UUID {landmark_uuid}: {str(exc)}")
|
||||
raise HTTPException(status_code=404, detail="Landmark not found") from exc
|
||||
|
||||
|
||||
# Update the times between landmarks when removing an item from the list
|
||||
@router.post("/trip/recompute-time/{trip_uuid}/{removed_landmark_uuid}")
|
||||
def update_trip_time(trip_uuid: str, removed_landmark_uuid: str) -> Trip:
|
||||
"""
|
||||
Updates the reaching times of a given trip when removing a landmark.
|
||||
|
||||
Args:
|
||||
landmark_uuid (str) : unique identifier for a Landmark.
|
||||
|
||||
Returns:
|
||||
(Landmark) : the corresponding Landmark.
|
||||
"""
|
||||
# First, fetch the trip in the cache.
|
||||
try:
|
||||
trip = cache_client.get(f'trip_{trip_uuid}')
|
||||
except KeyError as exc:
|
||||
logger.error(f"Failed to update trip with UUID {trip_uuid} (trip not found): {str(exc)}")
|
||||
raise HTTPException(status_code=404, detail='Trip not found') from exc
|
||||
|
||||
landmarks = []
|
||||
next_uuid = trip.first_landmark_uuid
|
||||
|
||||
# Extract landmarks
|
||||
try :
|
||||
while next_uuid is not None:
|
||||
landmark = cache_client.get(f'landmark_{next_uuid}')
|
||||
# Filter out the removed landmark.
|
||||
if next_uuid != removed_landmark_uuid :
|
||||
landmarks.append(landmark)
|
||||
next_uuid = landmark.next_uuid # Prepare for the next iteration
|
||||
except KeyError as exc:
|
||||
logger.error(f"Failed to update trip with UUID {trip_uuid} : {str(exc)}")
|
||||
raise HTTPException(status_code=404, detail=f'landmark {next_uuid} not found') from exc
|
||||
|
||||
# Re-link every thing and compute times again
|
||||
linked_tour = LinkedLandmarks(landmarks)
|
||||
trip = Trip.from_linked_landmarks(linked_tour, cache_client)
|
||||
|
||||
return trip
|
||||
|
||||
561
backend/uv.lock
generated
561
backend/uv.lock
generated
@@ -1,7 +1,80 @@
|
||||
version = 1
|
||||
revision = 2
|
||||
revision = 3
|
||||
requires-python = ">=3.12"
|
||||
|
||||
[[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.12.14"
|
||||
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/e6/0b/e39ad954107ebf213a2325038a3e7a506be3d98e1435e1f82086eec4cde2/aiohttp-3.12.14.tar.gz", hash = "sha256:6e06e120e34d93100de448fd941522e11dafa78ef1a893c179901b7d66aa29f2", size = 7822921, upload-time = "2025-07-10T13:05:33.968Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c3/0d/29026524e9336e33d9767a1e593ae2b24c2b8b09af7c2bd8193762f76b3e/aiohttp-3.12.14-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a0ecbb32fc3e69bc25efcda7d28d38e987d007096cbbeed04f14a6662d0eee22", size = 701055, upload-time = "2025-07-10T13:03:45.59Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0a/b8/a5e8e583e6c8c1056f4b012b50a03c77a669c2e9bf012b7cf33d6bc4b141/aiohttp-3.12.14-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0400f0ca9bb3e0b02f6466421f253797f6384e9845820c8b05e976398ac1d81a", size = 475670, upload-time = "2025-07-10T13:03:47.249Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/29/e8/5202890c9e81a4ec2c2808dd90ffe024952e72c061729e1d49917677952f/aiohttp-3.12.14-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a56809fed4c8a830b5cae18454b7464e1529dbf66f71c4772e3cfa9cbec0a1ff", size = 468513, upload-time = "2025-07-10T13:03:49.377Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/23/e5/d11db8c23d8923d3484a27468a40737d50f05b05eebbb6288bafcb467356/aiohttp-3.12.14-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27f2e373276e4755691a963e5d11756d093e346119f0627c2d6518208483fb6d", size = 1715309, upload-time = "2025-07-10T13:03:51.556Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/53/44/af6879ca0eff7a16b1b650b7ea4a827301737a350a464239e58aa7c387ef/aiohttp-3.12.14-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ca39e433630e9a16281125ef57ece6817afd1d54c9f1bf32e901f38f16035869", size = 1697961, upload-time = "2025-07-10T13:03:53.511Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bb/94/18457f043399e1ec0e59ad8674c0372f925363059c276a45a1459e17f423/aiohttp-3.12.14-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9c748b3f8b14c77720132b2510a7d9907a03c20ba80f469e58d5dfd90c079a1c", size = 1753055, upload-time = "2025-07-10T13:03:55.368Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/26/d9/1d3744dc588fafb50ff8a6226d58f484a2242b5dd93d8038882f55474d41/aiohttp-3.12.14-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0a568abe1b15ce69d4cc37e23020720423f0728e3cb1f9bcd3f53420ec3bfe7", size = 1799211, upload-time = "2025-07-10T13:03:57.216Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/73/12/2530fb2b08773f717ab2d249ca7a982ac66e32187c62d49e2c86c9bba9b4/aiohttp-3.12.14-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9888e60c2c54eaf56704b17feb558c7ed6b7439bca1e07d4818ab878f2083660", size = 1718649, upload-time = "2025-07-10T13:03:59.469Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b9/34/8d6015a729f6571341a311061b578e8b8072ea3656b3d72329fa0faa2c7c/aiohttp-3.12.14-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3006a1dc579b9156de01e7916d38c63dc1ea0679b14627a37edf6151bc530088", size = 1634452, upload-time = "2025-07-10T13:04:01.698Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ff/4b/08b83ea02595a582447aeb0c1986792d0de35fe7a22fb2125d65091cbaf3/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:aa8ec5c15ab80e5501a26719eb48a55f3c567da45c6ea5bb78c52c036b2655c7", size = 1695511, upload-time = "2025-07-10T13:04:04.165Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b5/66/9c7c31037a063eec13ecf1976185c65d1394ded4a5120dd5965e3473cb21/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:39b94e50959aa07844c7fe2206b9f75d63cc3ad1c648aaa755aa257f6f2498a9", size = 1716967, upload-time = "2025-07-10T13:04:06.132Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/02/84406e0ad1acb0fb61fd617651ab6de760b2d6a31700904bc0b33bd0894d/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:04c11907492f416dad9885d503fbfc5dcb6768d90cad8639a771922d584609d3", size = 1657620, upload-time = "2025-07-10T13:04:07.944Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/07/53/da018f4013a7a179017b9a274b46b9a12cbeb387570f116964f498a6f211/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:88167bd9ab69bb46cee91bd9761db6dfd45b6e76a0438c7e884c3f8160ff21eb", size = 1737179, upload-time = "2025-07-10T13:04:10.182Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/49/e8/ca01c5ccfeaafb026d85fa4f43ceb23eb80ea9c1385688db0ef322c751e9/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:791504763f25e8f9f251e4688195e8b455f8820274320204f7eafc467e609425", size = 1765156, upload-time = "2025-07-10T13:04:12.029Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/22/32/5501ab525a47ba23c20613e568174d6c63aa09e2caa22cded5c6ea8e3ada/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2785b112346e435dd3a1a67f67713a3fe692d288542f1347ad255683f066d8e0", size = 1724766, upload-time = "2025-07-10T13:04:13.961Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/af/28e24574801fcf1657945347ee10df3892311c2829b41232be6089e461e7/aiohttp-3.12.14-cp312-cp312-win32.whl", hash = "sha256:15f5f4792c9c999a31d8decf444e79fcfd98497bf98e94284bf390a7bb8c1729", size = 422641, upload-time = "2025-07-10T13:04:16.018Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/98/d5/7ac2464aebd2eecac38dbe96148c9eb487679c512449ba5215d233755582/aiohttp-3.12.14-cp312-cp312-win_amd64.whl", hash = "sha256:3b66e1a182879f579b105a80d5c4bd448b91a57e8933564bf41665064796a338", size = 449316, upload-time = "2025-07-10T13:04:18.289Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/48/e0d2fa8ac778008071e7b79b93ab31ef14ab88804d7ba71b5c964a7c844e/aiohttp-3.12.14-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:3143a7893d94dc82bc409f7308bc10d60285a3cd831a68faf1aa0836c5c3c767", size = 695471, upload-time = "2025-07-10T13:04:20.124Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8d/e7/f73206afa33100804f790b71092888f47df65fd9a4cd0e6800d7c6826441/aiohttp-3.12.14-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3d62ac3d506cef54b355bd34c2a7c230eb693880001dfcda0bf88b38f5d7af7e", size = 473128, upload-time = "2025-07-10T13:04:21.928Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/df/e2/4dd00180be551a6e7ee979c20fc7c32727f4889ee3fd5b0586e0d47f30e1/aiohttp-3.12.14-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:48e43e075c6a438937c4de48ec30fa8ad8e6dfef122a038847456bfe7b947b63", size = 465426, upload-time = "2025-07-10T13:04:24.071Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/de/dd/525ed198a0bb674a323e93e4d928443a680860802c44fa7922d39436b48b/aiohttp-3.12.14-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:077b4488411a9724cecc436cbc8c133e0d61e694995b8de51aaf351c7578949d", size = 1704252, upload-time = "2025-07-10T13:04:26.049Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d8/b1/01e542aed560a968f692ab4fc4323286e8bc4daae83348cd63588e4f33e3/aiohttp-3.12.14-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d8c35632575653f297dcbc9546305b2c1133391089ab925a6a3706dfa775ccab", size = 1685514, upload-time = "2025-07-10T13:04:28.186Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/06/93669694dc5fdabdc01338791e70452d60ce21ea0946a878715688d5a191/aiohttp-3.12.14-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b8ce87963f0035c6834b28f061df90cf525ff7c9b6283a8ac23acee6502afd4", size = 1737586, upload-time = "2025-07-10T13:04:30.195Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a5/3a/18991048ffc1407ca51efb49ba8bcc1645961f97f563a6c480cdf0286310/aiohttp-3.12.14-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0a2cf66e32a2563bb0766eb24eae7e9a269ac0dc48db0aae90b575dc9583026", size = 1786958, upload-time = "2025-07-10T13:04:32.482Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/a8/81e237f89a32029f9b4a805af6dffc378f8459c7b9942712c809ff9e76e5/aiohttp-3.12.14-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdea089caf6d5cde975084a884c72d901e36ef9c2fd972c9f51efbbc64e96fbd", size = 1709287, upload-time = "2025-07-10T13:04:34.493Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8c/e3/bd67a11b0fe7fc12c6030473afd9e44223d456f500f7cf526dbaa259ae46/aiohttp-3.12.14-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8a7865f27db67d49e81d463da64a59365ebd6b826e0e4847aa111056dcb9dc88", size = 1622990, upload-time = "2025-07-10T13:04:36.433Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/83/ba/e0cc8e0f0d9ce0904e3cf2d6fa41904e379e718a013c721b781d53dcbcca/aiohttp-3.12.14-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0ab5b38a6a39781d77713ad930cb5e7feea6f253de656a5f9f281a8f5931b086", size = 1676015, upload-time = "2025-07-10T13:04:38.958Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d8/b3/1e6c960520bda094c48b56de29a3d978254637ace7168dd97ddc273d0d6c/aiohttp-3.12.14-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:9b3b15acee5c17e8848d90a4ebc27853f37077ba6aec4d8cb4dbbea56d156933", size = 1707678, upload-time = "2025-07-10T13:04:41.275Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0a/19/929a3eb8c35b7f9f076a462eaa9830b32c7f27d3395397665caa5e975614/aiohttp-3.12.14-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e4c972b0bdaac167c1e53e16a16101b17c6d0ed7eac178e653a07b9f7fad7151", size = 1650274, upload-time = "2025-07-10T13:04:43.483Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/22/e5/81682a6f20dd1b18ce3d747de8eba11cbef9b270f567426ff7880b096b48/aiohttp-3.12.14-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7442488b0039257a3bdbc55f7209587911f143fca11df9869578db6c26feeeb8", size = 1726408, upload-time = "2025-07-10T13:04:45.577Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8c/17/884938dffaa4048302985483f77dfce5ac18339aad9b04ad4aaa5e32b028/aiohttp-3.12.14-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f68d3067eecb64c5e9bab4a26aa11bd676f4c70eea9ef6536b0a4e490639add3", size = 1759879, upload-time = "2025-07-10T13:04:47.663Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/95/78/53b081980f50b5cf874359bde707a6eacd6c4be3f5f5c93937e48c9d0025/aiohttp-3.12.14-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f88d3704c8b3d598a08ad17d06006cb1ca52a1182291f04979e305c8be6c9758", size = 1708770, upload-time = "2025-07-10T13:04:49.944Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ed/91/228eeddb008ecbe3ffa6c77b440597fdf640307162f0c6488e72c5a2d112/aiohttp-3.12.14-cp313-cp313-win32.whl", hash = "sha256:a3c99ab19c7bf375c4ae3debd91ca5d394b98b6089a03231d4c580ef3c2ae4c5", size = 421688, upload-time = "2025-07-10T13:04:51.993Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/66/5f/8427618903343402fdafe2850738f735fd1d9409d2a8f9bcaae5e630d3ba/aiohttp-3.12.14-cp313-cp313-win_amd64.whl", hash = "sha256:3f8aad695e12edc9d571f878c62bedc91adf30c760c8632f09663e5f564f4baa", size = 448098, upload-time = "2025-07-10T13:04:53.999Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aiosignal"
|
||||
version = "1.4.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "frozenlist" },
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||
]
|
||||
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]]
|
||||
name = "annotated-types"
|
||||
version = "0.7.0"
|
||||
@@ -43,6 +116,15 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2", size = 26918, upload-time = "2024-11-30T04:30:10.946Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "attrs"
|
||||
version = "25.3.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backend"
|
||||
version = "0.1.0"
|
||||
@@ -53,6 +135,7 @@ dependencies = [
|
||||
{ name = "certifi" },
|
||||
{ name = "charset-normalizer" },
|
||||
{ name = "click" },
|
||||
{ name = "dotenv" },
|
||||
{ name = "fastapi" },
|
||||
{ name = "fastapi-cli" },
|
||||
{ name = "h11" },
|
||||
@@ -63,6 +146,7 @@ dependencies = [
|
||||
{ name = "markdown-it-py" },
|
||||
{ name = "mdurl" },
|
||||
{ name = "numpy" },
|
||||
{ name = "paypalrestsdk" },
|
||||
{ name = "pulp" },
|
||||
{ name = "pydantic" },
|
||||
{ name = "pydantic-core" },
|
||||
@@ -79,6 +163,7 @@ dependencies = [
|
||||
{ name = "shellingham" },
|
||||
{ name = "sniffio" },
|
||||
{ name = "starlette" },
|
||||
{ name = "supabase" },
|
||||
{ name = "threadpoolctl" },
|
||||
{ name = "typer" },
|
||||
{ name = "typing-extensions" },
|
||||
@@ -104,6 +189,7 @@ requires-dist = [
|
||||
{ name = "certifi", marker = "python_full_version >= '3.6'", specifier = "==2024.12.14" },
|
||||
{ name = "charset-normalizer", marker = "python_full_version >= '3.7'", specifier = "==3.4.1" },
|
||||
{ name = "click", marker = "python_full_version >= '3.7'", specifier = "==8.1.8" },
|
||||
{ name = "dotenv", specifier = ">=0.9.9" },
|
||||
{ name = "fastapi", marker = "python_full_version >= '3.8'", specifier = "==0.115.7" },
|
||||
{ name = "fastapi-cli", marker = "python_full_version >= '3.8'", specifier = "==0.0.7" },
|
||||
{ name = "h11", marker = "python_full_version >= '3.7'", specifier = "==0.14.0" },
|
||||
@@ -114,6 +200,7 @@ requires-dist = [
|
||||
{ name = "markdown-it-py", marker = "python_full_version >= '3.8'", specifier = "==3.0.0" },
|
||||
{ name = "mdurl", marker = "python_full_version >= '3.7'", specifier = "==0.1.2" },
|
||||
{ name = "numpy", marker = "python_full_version >= '3.10'", specifier = "==2.2.2" },
|
||||
{ name = "paypalrestsdk", specifier = ">=1.13.3" },
|
||||
{ name = "pulp", marker = "python_full_version >= '3.7'", specifier = "==2.9.0" },
|
||||
{ name = "pydantic", marker = "python_full_version >= '3.8'", specifier = "==2.10.6" },
|
||||
{ name = "pydantic-core", marker = "python_full_version >= '3.8'", specifier = "==2.27.2" },
|
||||
@@ -130,6 +217,7 @@ requires-dist = [
|
||||
{ name = "shellingham", marker = "python_full_version >= '3.7'", specifier = "==1.5.4" },
|
||||
{ name = "sniffio", marker = "python_full_version >= '3.7'", specifier = "==1.3.1" },
|
||||
{ name = "starlette", marker = "python_full_version >= '3.9'", specifier = "==0.45.3" },
|
||||
{ name = "supabase", specifier = ">=2.16.0" },
|
||||
{ name = "threadpoolctl", marker = "python_full_version >= '3.8'", specifier = "==3.5.0" },
|
||||
{ name = "typer", marker = "python_full_version >= '3.7'", specifier = "==0.15.1" },
|
||||
{ name = "typing-extensions", marker = "python_full_version >= '3.8'", specifier = "==4.12.2" },
|
||||
@@ -255,6 +343,41 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417", size = 7294, upload-time = "2025-07-25T14:02:02.896Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cryptography"
|
||||
version = "45.0.5"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/95/1e/49527ac611af559665f71cbb8f92b332b5ec9c6fbc4e88b0f8e92f5e85df/cryptography-45.0.5.tar.gz", hash = "sha256:72e76caa004ab63accdf26023fccd1d087f6d90ec6048ff33ad0445abf7f605a", size = 744903, upload-time = "2025-07-02T13:06:25.941Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f0/fb/09e28bc0c46d2c547085e60897fea96310574c70fb21cd58a730a45f3403/cryptography-45.0.5-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:101ee65078f6dd3e5a028d4f19c07ffa4dd22cce6a20eaa160f8b5219911e7d8", size = 7043092, upload-time = "2025-07-02T13:05:01.514Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b1/05/2194432935e29b91fb649f6149c1a4f9e6d3d9fc880919f4ad1bcc22641e/cryptography-45.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3a264aae5f7fbb089dbc01e0242d3b67dffe3e6292e1f5182122bdf58e65215d", size = 4205926, upload-time = "2025-07-02T13:05:04.741Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/07/8b/9ef5da82350175e32de245646b1884fc01124f53eb31164c77f95a08d682/cryptography-45.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e74d30ec9c7cb2f404af331d5b4099a9b322a8a6b25c4632755c8757345baac5", size = 4429235, upload-time = "2025-07-02T13:05:07.084Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/e1/c809f398adde1994ee53438912192d92a1d0fc0f2d7582659d9ef4c28b0c/cryptography-45.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:3af26738f2db354aafe492fb3869e955b12b2ef2e16908c8b9cb928128d42c57", size = 4209785, upload-time = "2025-07-02T13:05:09.321Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/8b/07eb6bd5acff58406c5e806eff34a124936f41a4fb52909ffa4d00815f8c/cryptography-45.0.5-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e6c00130ed423201c5bc5544c23359141660b07999ad82e34e7bb8f882bb78e0", size = 3893050, upload-time = "2025-07-02T13:05:11.069Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/ef/3333295ed58d900a13c92806b67e62f27876845a9a908c939f040887cca9/cryptography-45.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:dd420e577921c8c2d31289536c386aaa30140b473835e97f83bc71ea9d2baf2d", size = 4457379, upload-time = "2025-07-02T13:05:13.32Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d9/9d/44080674dee514dbb82b21d6fa5d1055368f208304e2ab1828d85c9de8f4/cryptography-45.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:d05a38884db2ba215218745f0781775806bde4f32e07b135348355fe8e4991d9", size = 4209355, upload-time = "2025-07-02T13:05:15.017Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c9/d8/0749f7d39f53f8258e5c18a93131919ac465ee1f9dccaf1b3f420235e0b5/cryptography-45.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:ad0caded895a00261a5b4aa9af828baede54638754b51955a0ac75576b831b27", size = 4456087, upload-time = "2025-07-02T13:05:16.945Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/09/d7/92acac187387bf08902b0bf0699816f08553927bdd6ba3654da0010289b4/cryptography-45.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9024beb59aca9d31d36fcdc1604dd9bbeed0a55bface9f1908df19178e2f116e", size = 4332873, upload-time = "2025-07-02T13:05:18.743Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/03/c2/840e0710da5106a7c3d4153c7215b2736151bba60bf4491bdb421df5056d/cryptography-45.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:91098f02ca81579c85f66df8a588c78f331ca19089763d733e34ad359f474174", size = 4564651, upload-time = "2025-07-02T13:05:21.382Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2e/92/cc723dd6d71e9747a887b94eb3827825c6c24b9e6ce2bb33b847d31d5eaa/cryptography-45.0.5-cp311-abi3-win32.whl", hash = "sha256:926c3ea71a6043921050eaa639137e13dbe7b4ab25800932a8498364fc1abec9", size = 2929050, upload-time = "2025-07-02T13:05:23.39Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1f/10/197da38a5911a48dd5389c043de4aec4b3c94cb836299b01253940788d78/cryptography-45.0.5-cp311-abi3-win_amd64.whl", hash = "sha256:b85980d1e345fe769cfc57c57db2b59cff5464ee0c045d52c0df087e926fbe63", size = 3403224, upload-time = "2025-07-02T13:05:25.202Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fe/2b/160ce8c2765e7a481ce57d55eba1546148583e7b6f85514472b1d151711d/cryptography-45.0.5-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:f3562c2f23c612f2e4a6964a61d942f891d29ee320edb62ff48ffb99f3de9ae8", size = 7017143, upload-time = "2025-07-02T13:05:27.229Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c2/e7/2187be2f871c0221a81f55ee3105d3cf3e273c0a0853651d7011eada0d7e/cryptography-45.0.5-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3fcfbefc4a7f332dece7272a88e410f611e79458fab97b5efe14e54fe476f4fd", size = 4197780, upload-time = "2025-07-02T13:05:29.299Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b9/cf/84210c447c06104e6be9122661159ad4ce7a8190011669afceeaea150524/cryptography-45.0.5-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:460f8c39ba66af7db0545a8c6f2eabcbc5a5528fc1cf6c3fa9a1e44cec33385e", size = 4420091, upload-time = "2025-07-02T13:05:31.221Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3e/6a/cb8b5c8bb82fafffa23aeff8d3a39822593cee6e2f16c5ca5c2ecca344f7/cryptography-45.0.5-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:9b4cf6318915dccfe218e69bbec417fdd7c7185aa7aab139a2c0beb7468c89f0", size = 4198711, upload-time = "2025-07-02T13:05:33.062Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/04/f7/36d2d69df69c94cbb2473871926daf0f01ad8e00fe3986ac3c1e8c4ca4b3/cryptography-45.0.5-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2089cc8f70a6e454601525e5bf2779e665d7865af002a5dec8d14e561002e135", size = 3883299, upload-time = "2025-07-02T13:05:34.94Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/82/c7/f0ea40f016de72f81288e9fe8d1f6748036cb5ba6118774317a3ffc6022d/cryptography-45.0.5-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0027d566d65a38497bc37e0dd7c2f8ceda73597d2ac9ba93810204f56f52ebc7", size = 4450558, upload-time = "2025-07-02T13:05:37.288Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/ae/94b504dc1a3cdf642d710407c62e86296f7da9e66f27ab12a1ee6fdf005b/cryptography-45.0.5-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:be97d3a19c16a9be00edf79dca949c8fa7eff621763666a145f9f9535a5d7f42", size = 4198020, upload-time = "2025-07-02T13:05:39.102Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/05/2b/aaf0adb845d5dabb43480f18f7ca72e94f92c280aa983ddbd0bcd6ecd037/cryptography-45.0.5-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:7760c1c2e1a7084153a0f68fab76e754083b126a47d0117c9ed15e69e2103492", size = 4449759, upload-time = "2025-07-02T13:05:41.398Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/91/e4/f17e02066de63e0100a3a01b56f8f1016973a1d67551beaf585157a86b3f/cryptography-45.0.5-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6ff8728d8d890b3dda5765276d1bc6fb099252915a2cd3aff960c4c195745dd0", size = 4319991, upload-time = "2025-07-02T13:05:43.64Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f2/2e/e2dbd629481b499b14516eed933f3276eb3239f7cee2dcfa4ee6b44d4711/cryptography-45.0.5-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7259038202a47fdecee7e62e0fd0b0738b6daa335354396c6ddebdbe1206af2a", size = 4554189, upload-time = "2025-07-02T13:05:46.045Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f8/ea/a78a0c38f4c8736287b71c2ea3799d173d5ce778c7d6e3c163a95a05ad2a/cryptography-45.0.5-cp37-abi3-win32.whl", hash = "sha256:1e1da5accc0c750056c556a93c3e9cb828970206c68867712ca5805e46dc806f", size = 2911769, upload-time = "2025-07-02T13:05:48.329Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/79/b3/28ac139109d9005ad3f6b6f8976ffede6706a6478e21c889ce36c840918e/cryptography-45.0.5-cp37-abi3-win_amd64.whl", hash = "sha256:90cb0a7bb35959f37e23303b7eed0a32280510030daba3f7fdfbb65defde6a97", size = 3390016, upload-time = "2025-07-02T13:05:50.811Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "debugpy"
|
||||
version = "1.8.15"
|
||||
@@ -281,6 +404,29 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deprecation"
|
||||
version = "2.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "packaging" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5a/d3/8ae2869247df154b64c1884d7346d412fed0c49df84db635aab2d1c40e62/deprecation-2.1.0.tar.gz", hash = "sha256:72b3bde64e5d778694b0cf68178aed03d15e15477116add3fb773e581f9518ff", size = 173788, upload-time = "2020-04-20T14:23:38.738Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/02/c3/253a89ee03fc9b9682f1541728eb66db7db22148cd94f89ab22528cd1e1b/deprecation-2.1.0-py2.py3-none-any.whl", hash = "sha256:a10811591210e1fb0e768a8c25517cabeabcba6f0bf96564f8ff45189f90b14a", size = 11178, upload-time = "2020-04-20T14:23:36.581Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dotenv"
|
||||
version = "0.9.9"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "python-dotenv" },
|
||||
]
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b2/b7/545d2c10c1fc15e48653c91efde329a790f2eecfbbf2bd16003b5db2bab0/dotenv-0.9.9-py2.py3-none-any.whl", hash = "sha256:29cf74a087b31dafdb5a446b6d7e11cbce8ed2741540e2339c69fbef92c94ce9", size = 1892, upload-time = "2025-02-19T22:15:01.647Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "executing"
|
||||
version = "2.2.0"
|
||||
@@ -318,6 +464,80 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a1/e6/5daefc851b514ce2287d8f5d358ae4341089185f78f3217a69d0ce3a390c/fastapi_cli-0.0.7-py3-none-any.whl", hash = "sha256:d549368ff584b2804336c61f192d86ddea080c11255f375959627911944804f4", size = 10705, upload-time = "2024-12-15T14:28:06.18Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "frozenlist"
|
||||
version = "1.7.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/79/b1/b64018016eeb087db503b038296fd782586432b9c077fc5c7839e9cb6ef6/frozenlist-1.7.0.tar.gz", hash = "sha256:2e310d81923c2437ea8670467121cc3e9b0f76d3043cc1d2331d56c7fb7a3a8f", size = 45078, upload-time = "2025-06-09T23:02:35.538Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ef/a2/c8131383f1e66adad5f6ecfcce383d584ca94055a34d683bbb24ac5f2f1c/frozenlist-1.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3dbf9952c4bb0e90e98aec1bd992b3318685005702656bc6f67c1a32b76787f2", size = 81424, upload-time = "2025-06-09T23:00:42.24Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4c/9d/02754159955088cb52567337d1113f945b9e444c4960771ea90eb73de8db/frozenlist-1.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1f5906d3359300b8a9bb194239491122e6cf1444c2efb88865426f170c262cdb", size = 47952, upload-time = "2025-06-09T23:00:43.481Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/01/7a/0046ef1bd6699b40acd2067ed6d6670b4db2f425c56980fa21c982c2a9db/frozenlist-1.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3dabd5a8f84573c8d10d8859a50ea2dec01eea372031929871368c09fa103478", size = 46688, upload-time = "2025-06-09T23:00:44.793Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/a2/a910bafe29c86997363fb4c02069df4ff0b5bc39d33c5198b4e9dd42d8f8/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa57daa5917f1738064f302bf2626281a1cb01920c32f711fbc7bc36111058a8", size = 243084, upload-time = "2025-06-09T23:00:46.125Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/64/3e/5036af9d5031374c64c387469bfcc3af537fc0f5b1187d83a1cf6fab1639/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c193dda2b6d49f4c4398962810fa7d7c78f032bf45572b3e04dd5249dff27e08", size = 233524, upload-time = "2025-06-09T23:00:47.73Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/39/6a17b7c107a2887e781a48ecf20ad20f1c39d94b2a548c83615b5b879f28/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe2b675cf0aaa6d61bf8fbffd3c274b3c9b7b1623beb3809df8a81399a4a9c4", size = 248493, upload-time = "2025-06-09T23:00:49.742Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/be/00/711d1337c7327d88c44d91dd0f556a1c47fb99afc060ae0ef66b4d24793d/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8fc5d5cda37f62b262405cf9652cf0856839c4be8ee41be0afe8858f17f4c94b", size = 244116, upload-time = "2025-06-09T23:00:51.352Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/fe/74e6ec0639c115df13d5850e75722750adabdc7de24e37e05a40527ca539/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0d5ce521d1dd7d620198829b87ea002956e4319002ef0bc8d3e6d045cb4646e", size = 224557, upload-time = "2025-06-09T23:00:52.855Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8d/db/48421f62a6f77c553575201e89048e97198046b793f4a089c79a6e3268bd/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:488d0a7d6a0008ca0db273c542098a0fa9e7dfaa7e57f70acef43f32b3f69dca", size = 241820, upload-time = "2025-06-09T23:00:54.43Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1d/fa/cb4a76bea23047c8462976ea7b7a2bf53997a0ca171302deae9d6dd12096/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:15a7eaba63983d22c54d255b854e8108e7e5f3e89f647fc854bd77a237e767df", size = 236542, upload-time = "2025-06-09T23:00:56.409Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5d/32/476a4b5cfaa0ec94d3f808f193301debff2ea42288a099afe60757ef6282/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1eaa7e9c6d15df825bf255649e05bd8a74b04a4d2baa1ae46d9c2d00b2ca2cb5", size = 249350, upload-time = "2025-06-09T23:00:58.468Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8d/ba/9a28042f84a6bf8ea5dbc81cfff8eaef18d78b2a1ad9d51c7bc5b029ad16/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e4389e06714cfa9d47ab87f784a7c5be91d3934cd6e9a7b85beef808297cc025", size = 225093, upload-time = "2025-06-09T23:01:00.015Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bc/29/3a32959e68f9cf000b04e79ba574527c17e8842e38c91d68214a37455786/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:73bd45e1488c40b63fe5a7df892baf9e2a4d4bb6409a2b3b78ac1c6236178e01", size = 245482, upload-time = "2025-06-09T23:01:01.474Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/80/e8/edf2f9e00da553f07f5fa165325cfc302dead715cab6ac8336a5f3d0adc2/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99886d98e1643269760e5fe0df31e5ae7050788dd288947f7f007209b8c33f08", size = 249590, upload-time = "2025-06-09T23:01:02.961Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1c/80/9a0eb48b944050f94cc51ee1c413eb14a39543cc4f760ed12657a5a3c45a/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:290a172aae5a4c278c6da8a96222e6337744cd9c77313efe33d5670b9f65fc43", size = 237785, upload-time = "2025-06-09T23:01:05.095Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/74/87601e0fb0369b7a2baf404ea921769c53b7ae00dee7dcfe5162c8c6dbf0/frozenlist-1.7.0-cp312-cp312-win32.whl", hash = "sha256:426c7bc70e07cfebc178bc4c2bf2d861d720c4fff172181eeb4a4c41d4ca2ad3", size = 39487, upload-time = "2025-06-09T23:01:06.54Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/15/c026e9a9fc17585a9d461f65d8593d281fedf55fbf7eb53f16c6df2392f9/frozenlist-1.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:563b72efe5da92e02eb68c59cb37205457c977aa7a449ed1b37e6939e5c47c6a", size = 43874, upload-time = "2025-06-09T23:01:07.752Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/90/6b2cebdabdbd50367273c20ff6b57a3dfa89bd0762de02c3a1eb42cb6462/frozenlist-1.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee80eeda5e2a4e660651370ebffd1286542b67e268aa1ac8d6dbe973120ef7ee", size = 79791, upload-time = "2025-06-09T23:01:09.368Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/83/2e/5b70b6a3325363293fe5fc3ae74cdcbc3e996c2a11dde2fd9f1fb0776d19/frozenlist-1.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d1a81c85417b914139e3a9b995d4a1c84559afc839a93cf2cb7f15e6e5f6ed2d", size = 47165, upload-time = "2025-06-09T23:01:10.653Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/25/a0895c99270ca6966110f4ad98e87e5662eab416a17e7fd53c364bf8b954/frozenlist-1.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cbb65198a9132ebc334f237d7b0df163e4de83fb4f2bdfe46c1e654bdb0c5d43", size = 45881, upload-time = "2025-06-09T23:01:12.296Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/19/7c/71bb0bbe0832793c601fff68cd0cf6143753d0c667f9aec93d3c323f4b55/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dab46c723eeb2c255a64f9dc05b8dd601fde66d6b19cdb82b2e09cc6ff8d8b5d", size = 232409, upload-time = "2025-06-09T23:01:13.641Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c0/45/ed2798718910fe6eb3ba574082aaceff4528e6323f9a8570be0f7028d8e9/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6aeac207a759d0dedd2e40745575ae32ab30926ff4fa49b1635def65806fddee", size = 225132, upload-time = "2025-06-09T23:01:15.264Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/e2/8417ae0f8eacb1d071d4950f32f229aa6bf68ab69aab797b72a07ea68d4f/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bd8c4e58ad14b4fa7802b8be49d47993182fdd4023393899632c88fd8cd994eb", size = 237638, upload-time = "2025-06-09T23:01:16.752Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f8/b7/2ace5450ce85f2af05a871b8c8719b341294775a0a6c5585d5e6170f2ce7/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04fb24d104f425da3540ed83cbfc31388a586a7696142004c577fa61c6298c3f", size = 233539, upload-time = "2025-06-09T23:01:18.202Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/46/b9/6989292c5539553dba63f3c83dc4598186ab2888f67c0dc1d917e6887db6/frozenlist-1.7.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a5c505156368e4ea6b53b5ac23c92d7edc864537ff911d2fb24c140bb175e60", size = 215646, upload-time = "2025-06-09T23:01:19.649Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/72/31/bc8c5c99c7818293458fe745dab4fd5730ff49697ccc82b554eb69f16a24/frozenlist-1.7.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bd7eb96a675f18aa5c553eb7ddc24a43c8c18f22e1f9925528128c052cdbe00", size = 232233, upload-time = "2025-06-09T23:01:21.175Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/59/52/460db4d7ba0811b9ccb85af996019f5d70831f2f5f255f7cc61f86199795/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:05579bf020096fe05a764f1f84cd104a12f78eaab68842d036772dc6d4870b4b", size = 227996, upload-time = "2025-06-09T23:01:23.098Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/c9/f4b39e904c03927b7ecf891804fd3b4df3db29b9e487c6418e37988d6e9d/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:376b6222d114e97eeec13d46c486facd41d4f43bab626b7c3f6a8b4e81a5192c", size = 242280, upload-time = "2025-06-09T23:01:24.808Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/33/3f8d6ced42f162d743e3517781566b8481322be321b486d9d262adf70bfb/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0aa7e176ebe115379b5b1c95b4096fb1c17cce0847402e227e712c27bdb5a949", size = 217717, upload-time = "2025-06-09T23:01:26.28Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3e/e8/ad683e75da6ccef50d0ab0c2b2324b32f84fc88ceee778ed79b8e2d2fe2e/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3fbba20e662b9c2130dc771e332a99eff5da078b2b2648153a40669a6d0e36ca", size = 236644, upload-time = "2025-06-09T23:01:27.887Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b2/14/8d19ccdd3799310722195a72ac94ddc677541fb4bef4091d8e7775752360/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f3f4410a0a601d349dd406b5713fec59b4cee7e71678d5b17edda7f4655a940b", size = 238879, upload-time = "2025-06-09T23:01:29.524Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ce/13/c12bf657494c2fd1079a48b2db49fa4196325909249a52d8f09bc9123fd7/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e2cdfaaec6a2f9327bf43c933c0319a7c429058e8537c508964a133dffee412e", size = 232502, upload-time = "2025-06-09T23:01:31.287Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d7/8b/e7f9dfde869825489382bc0d512c15e96d3964180c9499efcec72e85db7e/frozenlist-1.7.0-cp313-cp313-win32.whl", hash = "sha256:5fc4df05a6591c7768459caba1b342d9ec23fa16195e744939ba5914596ae3e1", size = 39169, upload-time = "2025-06-09T23:01:35.503Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/35/89/a487a98d94205d85745080a37860ff5744b9820a2c9acbcdd9440bfddf98/frozenlist-1.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:52109052b9791a3e6b5d1b65f4b909703984b770694d3eb64fad124c835d7cba", size = 43219, upload-time = "2025-06-09T23:01:36.784Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/56/d5/5c4cf2319a49eddd9dd7145e66c4866bdc6f3dbc67ca3d59685149c11e0d/frozenlist-1.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a6f86e4193bb0e235ef6ce3dde5cbabed887e0b11f516ce8a0f4d3b33078ec2d", size = 84345, upload-time = "2025-06-09T23:01:38.295Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a4/7d/ec2c1e1dc16b85bc9d526009961953df9cec8481b6886debb36ec9107799/frozenlist-1.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:82d664628865abeb32d90ae497fb93df398a69bb3434463d172b80fc25b0dd7d", size = 48880, upload-time = "2025-06-09T23:01:39.887Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/69/86/f9596807b03de126e11e7d42ac91e3d0b19a6599c714a1989a4e85eeefc4/frozenlist-1.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:912a7e8375a1c9a68325a902f3953191b7b292aa3c3fb0d71a216221deca460b", size = 48498, upload-time = "2025-06-09T23:01:41.318Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5e/cb/df6de220f5036001005f2d726b789b2c0b65f2363b104bbc16f5be8084f8/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9537c2777167488d539bc5de2ad262efc44388230e5118868e172dd4a552b146", size = 292296, upload-time = "2025-06-09T23:01:42.685Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/83/1f/de84c642f17c8f851a2905cee2dae401e5e0daca9b5ef121e120e19aa825/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f34560fb1b4c3e30ba35fa9a13894ba39e5acfc5f60f57d8accde65f46cc5e74", size = 273103, upload-time = "2025-06-09T23:01:44.166Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/3c/c840bfa474ba3fa13c772b93070893c6e9d5c0350885760376cbe3b6c1b3/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:acd03d224b0175f5a850edc104ac19040d35419eddad04e7cf2d5986d98427f1", size = 292869, upload-time = "2025-06-09T23:01:45.681Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/1c/3efa6e7d5a39a1d5ef0abeb51c48fb657765794a46cf124e5aca2c7a592c/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2038310bc582f3d6a09b3816ab01737d60bf7b1ec70f5356b09e84fb7408ab1", size = 291467, upload-time = "2025-06-09T23:01:47.234Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4f/00/d5c5e09d4922c395e2f2f6b79b9a20dab4b67daaf78ab92e7729341f61f6/frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8c05e4c8e5f36e5e088caa1bf78a687528f83c043706640a92cb76cd6999384", size = 266028, upload-time = "2025-06-09T23:01:48.819Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4e/27/72765be905619dfde25a7f33813ac0341eb6b076abede17a2e3fbfade0cb/frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:765bb588c86e47d0b68f23c1bee323d4b703218037765dcf3f25c838c6fecceb", size = 284294, upload-time = "2025-06-09T23:01:50.394Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/67/c94103a23001b17808eb7dd1200c156bb69fb68e63fcf0693dde4cd6228c/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:32dc2e08c67d86d0969714dd484fd60ff08ff81d1a1e40a77dd34a387e6ebc0c", size = 281898, upload-time = "2025-06-09T23:01:52.234Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/42/34/a3e2c00c00f9e2a9db5653bca3fec306349e71aff14ae45ecc6d0951dd24/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:c0303e597eb5a5321b4de9c68e9845ac8f290d2ab3f3e2c864437d3c5a30cd65", size = 290465, upload-time = "2025-06-09T23:01:53.788Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bb/73/f89b7fbce8b0b0c095d82b008afd0590f71ccb3dee6eee41791cf8cd25fd/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:a47f2abb4e29b3a8d0b530f7c3598badc6b134562b1a5caee867f7c62fee51e3", size = 266385, upload-time = "2025-06-09T23:01:55.769Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cd/45/e365fdb554159462ca12df54bc59bfa7a9a273ecc21e99e72e597564d1ae/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:3d688126c242a6fabbd92e02633414d40f50bb6002fa4cf995a1d18051525657", size = 288771, upload-time = "2025-06-09T23:01:57.4Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/00/11/47b6117002a0e904f004d70ec5194fe9144f117c33c851e3d51c765962d0/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:4e7e9652b3d367c7bd449a727dc79d5043f48b88d0cbfd4f9f1060cf2b414104", size = 288206, upload-time = "2025-06-09T23:01:58.936Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/40/37/5f9f3c3fd7f7746082ec67bcdc204db72dad081f4f83a503d33220a92973/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1a85e345b4c43db8b842cab1feb41be5cc0b10a1830e6295b69d7310f99becaf", size = 282620, upload-time = "2025-06-09T23:02:00.493Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/31/8fbc5af2d183bff20f21aa743b4088eac4445d2bb1cdece449ae80e4e2d1/frozenlist-1.7.0-cp313-cp313t-win32.whl", hash = "sha256:3a14027124ddb70dfcee5148979998066897e79f89f64b13328595c4bdf77c81", size = 43059, upload-time = "2025-06-09T23:02:02.072Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bb/ed/41956f52105b8dbc26e457c5705340c67c8cc2b79f394b79bffc09d0e938/frozenlist-1.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3bf8010d71d4507775f658e9823210b7427be36625b387221642725b515dcf3e", size = 47516, upload-time = "2025-06-09T23:02:03.779Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ee/45/b82e3c16be2182bff01179db177fe144d58b5dc787a7d4492c6ed8b9317f/frozenlist-1.7.0-py3-none-any.whl", hash = "sha256:9a5af342e34f7e97caf8c995864c7a396418ae2859cc6fdf1b1073020d516a7e", size = 13106, upload-time = "2025-06-09T23:02:34.204Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gotrue"
|
||||
version = "2.12.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "httpx", extra = ["http2"] },
|
||||
{ name = "pydantic" },
|
||||
{ name = "pyjwt" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/fe/67/ae47f68daae1bbb56a9fbf960dfb7d08b3dec52a6ad1e96f69c2ba5b3116/gotrue-2.12.3.tar.gz", hash = "sha256:f874cf9d0b2f0335bfbd0d6e29e3f7aff79998cd1c14d2ad814db8c06cee3852", size = 38323, upload-time = "2025-07-04T06:50:03.941Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/42/fa/4165d298ef89254c9f742faa3f99a61fe6fd3552b4ba44df6924f8d307d7/gotrue-2.12.3-py3-none-any.whl", hash = "sha256:b1a3c6a5fe3f92e854a026c4c19de58706a96fd5fbdcc3d620b2802f6a46a26b", size = 44022, upload-time = "2025-07-04T06:50:02.591Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h11"
|
||||
version = "0.14.0"
|
||||
@@ -327,6 +547,28 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259, upload-time = "2022-09-25T15:39:59.68Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "4.2.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "hpack" },
|
||||
{ name = "hyperframe" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1b/38/d7f80fd13e6582fb8e0df8c9a653dcc02b03ca34f4d72f34869298c5baf8/h2-4.2.0.tar.gz", hash = "sha256:c8a52129695e88b1a0578d8d2cc6842bbd79128ac685463b887ee278126ad01f", size = 2150682, upload-time = "2025-02-02T07:43:51.815Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/9e/984486f2d0a0bd2b024bf4bc1c62688fcafa9e61991f041fb0e2def4a982/h2-4.2.0-py3-none-any.whl", hash = "sha256:479a53ad425bb29af087f3458a61d30780bc818e4ebcf01f0b536ba916462ed0", size = 60957, upload-time = "2025-02-01T11:02:26.481Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hpack"
|
||||
version = "4.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/2c/48/71de9ed269fdae9c8057e5a4c0aa7402e8bb16f2c6e90b3aa53327b113f8/hpack-4.1.0.tar.gz", hash = "sha256:ec5eca154f7056aa06f196a557655c5b009b382873ac8d1e66e79e87535f1dca", size = 51276, upload-time = "2025-01-22T21:44:58.347Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/07/c6/80c95b1b2b94682a72cbdbfb85b81ae2daffa4291fbfa1b1464502ede10d/hpack-4.1.0-py3-none-any.whl", hash = "sha256:157ac792668d995c657d93111f46b4535ed114f0c9c8d672271bbec7eae1b496", size = 34357, upload-time = "2025-01-22T21:44:56.92Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httpcore"
|
||||
version = "1.0.8"
|
||||
@@ -377,6 +619,20 @@ 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.optional-dependencies]
|
||||
http2 = [
|
||||
{ name = "h2" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyperframe"
|
||||
version = "6.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/02/e7/94f8232d4a74cc99514c13a9f995811485a6903d48e5d952771ef6322e30/hyperframe-6.1.0.tar.gz", hash = "sha256:f630908a00854a7adeabd6382b43923a4c4cd4b821fcb527e6ab9e15382a3b08", size = 26566, upload-time = "2025-01-22T21:41:49.302Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl", hash = "sha256:b03380493a519fce58ea5af42e4a42317bf9bd425596f7a0835ffce80f1a42e5", size = 13007, upload-time = "2025-01-22T21:41:47.295Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "3.10"
|
||||
@@ -595,6 +851,69 @@ 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" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "multidict"
|
||||
version = "6.6.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/3d/2c/5dad12e82fbdf7470f29bff2171484bf07cb3b16ada60a6589af8f376440/multidict-6.6.3.tar.gz", hash = "sha256:798a9eb12dab0a6c2e29c1de6f3468af5cb2da6053a20dfa3344907eed0937cc", size = 101006, upload-time = "2025-06-30T15:53:46.929Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/0e/a0/6b57988ea102da0623ea814160ed78d45a2645e4bbb499c2896d12833a70/multidict-6.6.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:056bebbeda16b2e38642d75e9e5310c484b7c24e3841dc0fb943206a72ec89d6", size = 76514, upload-time = "2025-06-30T15:51:48.728Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/07/7a/d1e92665b0850c6c0508f101f9cf0410c1afa24973e1115fe9c6a185ebf7/multidict-6.6.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e5f481cccb3c5c5e5de5d00b5141dc589c1047e60d07e85bbd7dea3d4580d63f", size = 45394, upload-time = "2025-06-30T15:51:49.986Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/6f/dd104490e01be6ef8bf9573705d8572f8c2d2c561f06e3826b081d9e6591/multidict-6.6.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:10bea2ee839a759ee368b5a6e47787f399b41e70cf0c20d90dfaf4158dfb4e55", size = 43590, upload-time = "2025-06-30T15:51:51.331Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/fe/06e0e01b1b0611e6581b7fd5a85b43dacc08b6cea3034f902f383b0873e5/multidict-6.6.3-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:2334cfb0fa9549d6ce2c21af2bfbcd3ac4ec3646b1b1581c88e3e2b1779ec92b", size = 237292, upload-time = "2025-06-30T15:51:52.584Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ce/71/4f0e558fb77696b89c233c1ee2d92f3e1d5459070a0e89153c9e9e804186/multidict-6.6.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8fee016722550a2276ca2cb5bb624480e0ed2bd49125b2b73b7010b9090e888", size = 258385, upload-time = "2025-06-30T15:51:53.913Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e3/25/cca0e68228addad24903801ed1ab42e21307a1b4b6dd2cf63da5d3ae082a/multidict-6.6.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5511cb35f5c50a2db21047c875eb42f308c5583edf96bd8ebf7d770a9d68f6d", size = 242328, upload-time = "2025-06-30T15:51:55.672Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6e/a3/46f2d420d86bbcb8fe660b26a10a219871a0fbf4d43cb846a4031533f3e0/multidict-6.6.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:712b348f7f449948e0a6c4564a21c7db965af900973a67db432d724619b3c680", size = 268057, upload-time = "2025-06-30T15:51:57.037Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9e/73/1c743542fe00794a2ec7466abd3f312ccb8fad8dff9f36d42e18fb1ec33e/multidict-6.6.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e4e15d2138ee2694e038e33b7c3da70e6b0ad8868b9f8094a72e1414aeda9c1a", size = 269341, upload-time = "2025-06-30T15:51:59.111Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a4/11/6ec9dcbe2264b92778eeb85407d1df18812248bf3506a5a1754bc035db0c/multidict-6.6.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8df25594989aebff8a130f7899fa03cbfcc5d2b5f4a461cf2518236fe6f15961", size = 256081, upload-time = "2025-06-30T15:52:00.533Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9b/2b/631b1e2afeb5f1696846d747d36cda075bfdc0bc7245d6ba5c319278d6c4/multidict-6.6.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:159ca68bfd284a8860f8d8112cf0521113bffd9c17568579e4d13d1f1dc76b65", size = 253581, upload-time = "2025-06-30T15:52:02.43Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bf/0e/7e3b93f79efeb6111d3bf9a1a69e555ba1d07ad1c11bceb56b7310d0d7ee/multidict-6.6.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e098c17856a8c9ade81b4810888c5ad1914099657226283cab3062c0540b0643", size = 250750, upload-time = "2025-06-30T15:52:04.26Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ad/9e/086846c1d6601948e7de556ee464a2d4c85e33883e749f46b9547d7b0704/multidict-6.6.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:67c92ed673049dec52d7ed39f8cf9ebbadf5032c774058b4406d18c8f8fe7063", size = 251548, upload-time = "2025-06-30T15:52:06.002Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8c/7b/86ec260118e522f1a31550e87b23542294880c97cfbf6fb18cc67b044c66/multidict-6.6.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:bd0578596e3a835ef451784053cfd327d607fc39ea1a14812139339a18a0dbc3", size = 262718, upload-time = "2025-06-30T15:52:07.707Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8c/bd/22ce8f47abb0be04692c9fc4638508b8340987b18691aa7775d927b73f72/multidict-6.6.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:346055630a2df2115cd23ae271910b4cae40f4e336773550dca4889b12916e75", size = 259603, upload-time = "2025-06-30T15:52:09.58Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/07/9c/91b7ac1691be95cd1f4a26e36a74b97cda6aa9820632d31aab4410f46ebd/multidict-6.6.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:555ff55a359302b79de97e0468e9ee80637b0de1fce77721639f7cd9440b3a10", size = 251351, upload-time = "2025-06-30T15:52:10.947Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6f/5c/4d7adc739884f7a9fbe00d1eac8c034023ef8bad71f2ebe12823ca2e3649/multidict-6.6.3-cp312-cp312-win32.whl", hash = "sha256:73ab034fb8d58ff85c2bcbadc470efc3fafeea8affcf8722855fb94557f14cc5", size = 41860, upload-time = "2025-06-30T15:52:12.334Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/a3/0fbc7afdf7cb1aa12a086b02959307848eb6bcc8f66fcb66c0cb57e2a2c1/multidict-6.6.3-cp312-cp312-win_amd64.whl", hash = "sha256:04cbcce84f63b9af41bad04a54d4cc4e60e90c35b9e6ccb130be2d75b71f8c17", size = 45982, upload-time = "2025-06-30T15:52:13.6Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/95/8c825bd70ff9b02462dc18d1295dd08d3e9e4eb66856d292ffa62cfe1920/multidict-6.6.3-cp312-cp312-win_arm64.whl", hash = "sha256:0f1130b896ecb52d2a1e615260f3ea2af55fa7dc3d7c3003ba0c3121a759b18b", size = 43210, upload-time = "2025-06-30T15:52:14.893Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/1d/0bebcbbb4f000751fbd09957257903d6e002943fc668d841a4cf2fb7f872/multidict-6.6.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:540d3c06d48507357a7d57721e5094b4f7093399a0106c211f33540fdc374d55", size = 75843, upload-time = "2025-06-30T15:52:16.155Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/07/8f/cbe241b0434cfe257f65c2b1bcf9e8d5fb52bc708c5061fb29b0fed22bdf/multidict-6.6.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9c19cea2a690f04247d43f366d03e4eb110a0dc4cd1bbeee4d445435428ed35b", size = 45053, upload-time = "2025-06-30T15:52:17.429Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/32/d2/0b3b23f9dbad5b270b22a3ac3ea73ed0a50ef2d9a390447061178ed6bdb8/multidict-6.6.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7af039820cfd00effec86bda5d8debef711a3e86a1d3772e85bea0f243a4bd65", size = 43273, upload-time = "2025-06-30T15:52:19.346Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fd/fe/6eb68927e823999e3683bc49678eb20374ba9615097d085298fd5b386564/multidict-6.6.3-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:500b84f51654fdc3944e936f2922114349bf8fdcac77c3092b03449f0e5bc2b3", size = 237124, upload-time = "2025-06-30T15:52:20.773Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e7/ab/320d8507e7726c460cb77117848b3834ea0d59e769f36fdae495f7669929/multidict-6.6.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3fc723ab8a5c5ed6c50418e9bfcd8e6dceba6c271cee6728a10a4ed8561520c", size = 256892, upload-time = "2025-06-30T15:52:22.242Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/76/60/38ee422db515ac69834e60142a1a69111ac96026e76e8e9aa347fd2e4591/multidict-6.6.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:94c47ea3ade005b5976789baaed66d4de4480d0a0bf31cef6edaa41c1e7b56a6", size = 240547, upload-time = "2025-06-30T15:52:23.736Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/27/fb/905224fde2dff042b030c27ad95a7ae744325cf54b890b443d30a789b80e/multidict-6.6.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dbc7cf464cc6d67e83e136c9f55726da3a30176f020a36ead246eceed87f1cd8", size = 266223, upload-time = "2025-06-30T15:52:25.185Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/76/35/dc38ab361051beae08d1a53965e3e1a418752fc5be4d3fb983c5582d8784/multidict-6.6.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:900eb9f9da25ada070f8ee4a23f884e0ee66fe4e1a38c3af644256a508ad81ca", size = 267262, upload-time = "2025-06-30T15:52:26.969Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1f/a3/0a485b7f36e422421b17e2bbb5a81c1af10eac1d4476f2ff92927c730479/multidict-6.6.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7c6df517cf177da5d47ab15407143a89cd1a23f8b335f3a28d57e8b0a3dbb884", size = 254345, upload-time = "2025-06-30T15:52:28.467Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b4/59/bcdd52c1dab7c0e0d75ff19cac751fbd5f850d1fc39172ce809a74aa9ea4/multidict-6.6.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4ef421045f13879e21c994b36e728d8e7d126c91a64b9185810ab51d474f27e7", size = 252248, upload-time = "2025-06-30T15:52:29.938Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bb/a4/2d96aaa6eae8067ce108d4acee6f45ced5728beda55c0f02ae1072c730d1/multidict-6.6.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:6c1e61bb4f80895c081790b6b09fa49e13566df8fbff817da3f85b3a8192e36b", size = 250115, upload-time = "2025-06-30T15:52:31.416Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/25/d2/ed9f847fa5c7d0677d4f02ea2c163d5e48573de3f57bacf5670e43a5ffaa/multidict-6.6.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e5e8523bb12d7623cd8300dbd91b9e439a46a028cd078ca695eb66ba31adee3c", size = 249649, upload-time = "2025-06-30T15:52:32.996Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1f/af/9155850372563fc550803d3f25373308aa70f59b52cff25854086ecb4a79/multidict-6.6.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:ef58340cc896219e4e653dade08fea5c55c6df41bcc68122e3be3e9d873d9a7b", size = 261203, upload-time = "2025-06-30T15:52:34.521Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/36/2f/c6a728f699896252cf309769089568a33c6439626648843f78743660709d/multidict-6.6.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fc9dc435ec8699e7b602b94fe0cd4703e69273a01cbc34409af29e7820f777f1", size = 258051, upload-time = "2025-06-30T15:52:35.999Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/60/689880776d6b18fa2b70f6cc74ff87dd6c6b9b47bd9cf74c16fecfaa6ad9/multidict-6.6.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9e864486ef4ab07db5e9cb997bad2b681514158d6954dd1958dfb163b83d53e6", size = 249601, upload-time = "2025-06-30T15:52:37.473Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/75/5e/325b11f2222a549019cf2ef879c1f81f94a0d40ace3ef55cf529915ba6cc/multidict-6.6.3-cp313-cp313-win32.whl", hash = "sha256:5633a82fba8e841bc5c5c06b16e21529573cd654f67fd833650a215520a6210e", size = 41683, upload-time = "2025-06-30T15:52:38.927Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b1/ad/cf46e73f5d6e3c775cabd2a05976547f3f18b39bee06260369a42501f053/multidict-6.6.3-cp313-cp313-win_amd64.whl", hash = "sha256:e93089c1570a4ad54c3714a12c2cef549dc9d58e97bcded193d928649cab78e9", size = 45811, upload-time = "2025-06-30T15:52:40.207Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c5/c9/2e3fe950db28fb7c62e1a5f46e1e38759b072e2089209bc033c2798bb5ec/multidict-6.6.3-cp313-cp313-win_arm64.whl", hash = "sha256:c60b401f192e79caec61f166da9c924e9f8bc65548d4246842df91651e83d600", size = 43056, upload-time = "2025-06-30T15:52:41.575Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3a/58/aaf8114cf34966e084a8cc9517771288adb53465188843d5a19862cb6dc3/multidict-6.6.3-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:02fd8f32d403a6ff13864b0851f1f523d4c988051eea0471d4f1fd8010f11134", size = 82811, upload-time = "2025-06-30T15:52:43.281Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/71/af/5402e7b58a1f5b987a07ad98f2501fdba2a4f4b4c30cf114e3ce8db64c87/multidict-6.6.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:f3aa090106b1543f3f87b2041eef3c156c8da2aed90c63a2fbed62d875c49c37", size = 48304, upload-time = "2025-06-30T15:52:45.026Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/39/65/ab3c8cafe21adb45b24a50266fd747147dec7847425bc2a0f6934b3ae9ce/multidict-6.6.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e924fb978615a5e33ff644cc42e6aa241effcf4f3322c09d4f8cebde95aff5f8", size = 46775, upload-time = "2025-06-30T15:52:46.459Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/49/ba/9fcc1b332f67cc0c0c8079e263bfab6660f87fe4e28a35921771ff3eea0d/multidict-6.6.3-cp313-cp313t-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:b9fe5a0e57c6dbd0e2ce81ca66272282c32cd11d31658ee9553849d91289e1c1", size = 229773, upload-time = "2025-06-30T15:52:47.88Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a4/14/0145a251f555f7c754ce2dcbcd012939bbd1f34f066fa5d28a50e722a054/multidict-6.6.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b24576f208793ebae00280c59927c3b7c2a3b1655e443a25f753c4611bc1c373", size = 250083, upload-time = "2025-06-30T15:52:49.366Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9e/d4/d5c0bd2bbb173b586c249a151a26d2fb3ec7d53c96e42091c9fef4e1f10c/multidict-6.6.3-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:135631cb6c58eac37d7ac0df380294fecdc026b28837fa07c02e459c7fb9c54e", size = 228980, upload-time = "2025-06-30T15:52:50.903Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/21/32/c9a2d8444a50ec48c4733ccc67254100c10e1c8ae8e40c7a2d2183b59b97/multidict-6.6.3-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:274d416b0df887aef98f19f21578653982cfb8a05b4e187d4a17103322eeaf8f", size = 257776, upload-time = "2025-06-30T15:52:52.764Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/68/d0/14fa1699f4ef629eae08ad6201c6b476098f5efb051b296f4c26be7a9fdf/multidict-6.6.3-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e252017a817fad7ce05cafbe5711ed40faeb580e63b16755a3a24e66fa1d87c0", size = 256882, upload-time = "2025-06-30T15:52:54.596Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/da/88/84a27570fbe303c65607d517a5f147cd2fc046c2d1da02b84b17b9bdc2aa/multidict-6.6.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e4cc8d848cd4fe1cdee28c13ea79ab0ed37fc2e89dd77bac86a2e7959a8c3bc", size = 247816, upload-time = "2025-06-30T15:52:56.175Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1c/60/dca352a0c999ce96a5d8b8ee0b2b9f729dcad2e0b0c195f8286269a2074c/multidict-6.6.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9e236a7094b9c4c1b7585f6b9cca34b9d833cf079f7e4c49e6a4a6ec9bfdc68f", size = 245341, upload-time = "2025-06-30T15:52:57.752Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/50/ef/433fa3ed06028f03946f3993223dada70fb700f763f70c00079533c34578/multidict-6.6.3-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:e0cb0ab69915c55627c933f0b555a943d98ba71b4d1c57bc0d0a66e2567c7471", size = 235854, upload-time = "2025-06-30T15:52:59.74Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1b/1f/487612ab56fbe35715320905215a57fede20de7db40a261759690dc80471/multidict-6.6.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:81ef2f64593aba09c5212a3d0f8c906a0d38d710a011f2f42759704d4557d3f2", size = 243432, upload-time = "2025-06-30T15:53:01.602Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/da/6f/ce8b79de16cd885c6f9052c96a3671373d00c59b3ee635ea93e6e81b8ccf/multidict-6.6.3-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:b9cbc60010de3562545fa198bfc6d3825df430ea96d2cc509c39bd71e2e7d648", size = 252731, upload-time = "2025-06-30T15:53:03.517Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bb/fe/a2514a6aba78e5abefa1624ca85ae18f542d95ac5cde2e3815a9fbf369aa/multidict-6.6.3-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:70d974eaaa37211390cd02ef93b7e938de564bbffa866f0b08d07e5e65da783d", size = 247086, upload-time = "2025-06-30T15:53:05.48Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8c/22/b788718d63bb3cce752d107a57c85fcd1a212c6c778628567c9713f9345a/multidict-6.6.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:3713303e4a6663c6d01d648a68f2848701001f3390a030edaaf3fc949c90bf7c", size = 243338, upload-time = "2025-06-30T15:53:07.522Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/22/d6/fdb3d0670819f2228f3f7d9af613d5e652c15d170c83e5f1c94fbc55a25b/multidict-6.6.3-cp313-cp313t-win32.whl", hash = "sha256:639ecc9fe7cd73f2495f62c213e964843826f44505a3e5d82805aa85cac6f89e", size = 47812, upload-time = "2025-06-30T15:53:09.263Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/d6/a9d2c808f2c489ad199723197419207ecbfbc1776f6e155e1ecea9c883aa/multidict-6.6.3-cp313-cp313t-win_amd64.whl", hash = "sha256:9f97e181f344a0ef3881b573d31de8542cc0dbc559ec68c8f8b5ce2c2e91646d", size = 53011, upload-time = "2025-06-30T15:53:11.038Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f2/40/b68001cba8188dd267590a111f9661b6256debc327137667e832bf5d66e8/multidict-6.6.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ce8b7693da41a3c4fde5871c738a81490cea5496c671d74374c8ab889e1834fb", size = 45254, upload-time = "2025-06-30T15:53:12.421Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d8/30/9aec301e9772b098c1f5c0ca0279237c9766d94b97802e9888010c64b0ed/multidict-6.6.3-py3-none-any.whl", hash = "sha256:8db10f29c7541fc5da4defd8cd697e1ca429db743fa716325f236079b96f775a", size = 12313, upload-time = "2025-06-30T15:53:45.437Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nest-asyncio"
|
||||
version = "1.6.0"
|
||||
@@ -660,6 +979,20 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", size = 103650, upload-time = "2024-04-05T09:43:53.299Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paypalrestsdk"
|
||||
version = "1.13.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "pyopenssl" },
|
||||
{ name = "requests" },
|
||||
{ name = "six" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/af/f9/5e585f31a1c6caeec1af093edc3c6046a46af330ab9d9f91bbf86b019b59/paypalrestsdk-1.13.3.tar.gz", hash = "sha256:dac236492a9ac1260a760014a2e56ab38b09d8143295b5e896545359b61fedd6", size = 23865, upload-time = "2023-11-01T20:50:00.725Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/10/e0/ce62183f4ca1d9cab773a086a5d49e934f3a782960558ff971adc9fc9d05/paypalrestsdk-1.13.3-py3-none-any.whl", hash = "sha256:a3f51616ee8f6d975a5a5a8c2049db63653c843479c8fdd71c9d588a31e14560", size = 23681, upload-time = "2023-11-01T20:49:57.307Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pexpect"
|
||||
version = "4.9.0"
|
||||
@@ -690,6 +1023,20 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "postgrest"
|
||||
version = "1.1.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "deprecation" },
|
||||
{ name = "httpx", extra = ["http2"] },
|
||||
{ name = "pydantic" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/6e/3e/1b50568e1f5db0bdced4a82c7887e37326585faef7ca43ead86849cb4861/postgrest-1.1.1.tar.gz", hash = "sha256:f3bb3e8c4602775c75c844a31f565f5f3dd584df4d36d683f0b67d01a86be322", size = 15431, upload-time = "2025-06-23T19:21:34.742Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a4/71/188a50ea64c17f73ff4df5196ec1553a8f1723421eb2d1069c73bab47d78/postgrest-1.1.1-py3-none-any.whl", hash = "sha256:98a6035ee1d14288484bfe36235942c5fb2d26af6d8120dfe3efbe007859251a", size = 22366, upload-time = "2025-06-23T19:21:33.637Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prompt-toolkit"
|
||||
version = "3.0.51"
|
||||
@@ -702,6 +1049,63 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ce/4f/5249960887b1fbe561d9ff265496d170b55a735b76724f10ef19f9e40716/prompt_toolkit-3.0.51-py3-none-any.whl", hash = "sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07", size = 387810, upload-time = "2025-04-15T09:18:44.753Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "propcache"
|
||||
version = "0.3.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a6/16/43264e4a779dd8588c21a70f0709665ee8f611211bdd2c87d952cfa7c776/propcache-0.3.2.tar.gz", hash = "sha256:20d7d62e4e7ef05f221e0db2856b979540686342e7dd9973b815599c7057e168", size = 44139, upload-time = "2025-06-09T22:56:06.081Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a8/42/9ca01b0a6f48e81615dca4765a8f1dd2c057e0540f6116a27dc5ee01dfb6/propcache-0.3.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8de106b6c84506b31c27168582cd3cb3000a6412c16df14a8628e5871ff83c10", size = 73674, upload-time = "2025-06-09T22:54:30.551Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/af/6e/21293133beb550f9c901bbece755d582bfaf2176bee4774000bd4dd41884/propcache-0.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:28710b0d3975117239c76600ea351934ac7b5ff56e60953474342608dbbb6154", size = 43570, upload-time = "2025-06-09T22:54:32.296Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/c8/0393a0a3a2b8760eb3bde3c147f62b20044f0ddac81e9d6ed7318ec0d852/propcache-0.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce26862344bdf836650ed2487c3d724b00fbfec4233a1013f597b78c1cb73615", size = 43094, upload-time = "2025-06-09T22:54:33.929Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/37/2c/489afe311a690399d04a3e03b069225670c1d489eb7b044a566511c1c498/propcache-0.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bca54bd347a253af2cf4544bbec232ab982f4868de0dd684246b67a51bc6b1db", size = 226958, upload-time = "2025-06-09T22:54:35.186Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9d/ca/63b520d2f3d418c968bf596839ae26cf7f87bead026b6192d4da6a08c467/propcache-0.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55780d5e9a2ddc59711d727226bb1ba83a22dd32f64ee15594b9392b1f544eb1", size = 234894, upload-time = "2025-06-09T22:54:36.708Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/11/60/1d0ed6fff455a028d678df30cc28dcee7af77fa2b0e6962ce1df95c9a2a9/propcache-0.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:035e631be25d6975ed87ab23153db6a73426a48db688070d925aa27e996fe93c", size = 233672, upload-time = "2025-06-09T22:54:38.062Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/37/7c/54fd5301ef38505ab235d98827207176a5c9b2aa61939b10a460ca53e123/propcache-0.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee6f22b6eaa39297c751d0e80c0d3a454f112f5c6481214fcf4c092074cecd67", size = 224395, upload-time = "2025-06-09T22:54:39.634Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ee/1a/89a40e0846f5de05fdc6779883bf46ba980e6df4d2ff8fb02643de126592/propcache-0.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ca3aee1aa955438c4dba34fc20a9f390e4c79967257d830f137bd5a8a32ed3b", size = 212510, upload-time = "2025-06-09T22:54:41.565Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5e/33/ca98368586c9566a6b8d5ef66e30484f8da84c0aac3f2d9aec6d31a11bd5/propcache-0.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7a4f30862869fa2b68380d677cc1c5fcf1e0f2b9ea0cf665812895c75d0ca3b8", size = 222949, upload-time = "2025-06-09T22:54:43.038Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/11/ace870d0aafe443b33b2f0b7efdb872b7c3abd505bfb4890716ad7865e9d/propcache-0.3.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b77ec3c257d7816d9f3700013639db7491a434644c906a2578a11daf13176251", size = 217258, upload-time = "2025-06-09T22:54:44.376Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5b/d2/86fd6f7adffcfc74b42c10a6b7db721d1d9ca1055c45d39a1a8f2a740a21/propcache-0.3.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cab90ac9d3f14b2d5050928483d3d3b8fb6b4018893fc75710e6aa361ecb2474", size = 213036, upload-time = "2025-06-09T22:54:46.243Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/07/94/2d7d1e328f45ff34a0a284cf5a2847013701e24c2a53117e7c280a4316b3/propcache-0.3.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0b504d29f3c47cf6b9e936c1852246c83d450e8e063d50562115a6be6d3a2535", size = 227684, upload-time = "2025-06-09T22:54:47.63Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b7/05/37ae63a0087677e90b1d14710e532ff104d44bc1efa3b3970fff99b891dc/propcache-0.3.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:ce2ac2675a6aa41ddb2a0c9cbff53780a617ac3d43e620f8fd77ba1c84dcfc06", size = 234562, upload-time = "2025-06-09T22:54:48.982Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a4/7c/3f539fcae630408d0bd8bf3208b9a647ccad10976eda62402a80adf8fc34/propcache-0.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:62b4239611205294cc433845b914131b2a1f03500ff3c1ed093ed216b82621e1", size = 222142, upload-time = "2025-06-09T22:54:50.424Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/d2/34b9eac8c35f79f8a962546b3e97e9d4b990c420ee66ac8255d5d9611648/propcache-0.3.2-cp312-cp312-win32.whl", hash = "sha256:df4a81b9b53449ebc90cc4deefb052c1dd934ba85012aa912c7ea7b7e38b60c1", size = 37711, upload-time = "2025-06-09T22:54:52.072Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/19/61/d582be5d226cf79071681d1b46b848d6cb03d7b70af7063e33a2787eaa03/propcache-0.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:7046e79b989d7fe457bb755844019e10f693752d169076138abf17f31380800c", size = 41479, upload-time = "2025-06-09T22:54:53.234Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/dc/d1/8c747fafa558c603c4ca19d8e20b288aa0c7cda74e9402f50f31eb65267e/propcache-0.3.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ca592ed634a73ca002967458187109265e980422116c0a107cf93d81f95af945", size = 71286, upload-time = "2025-06-09T22:54:54.369Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/61/99/d606cb7986b60d89c36de8a85d58764323b3a5ff07770a99d8e993b3fa73/propcache-0.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9ecb0aad4020e275652ba3975740f241bd12a61f1a784df044cf7477a02bc252", size = 42425, upload-time = "2025-06-09T22:54:55.642Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8c/96/ef98f91bbb42b79e9bb82bdd348b255eb9d65f14dbbe3b1594644c4073f7/propcache-0.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7f08f1cc28bd2eade7a8a3d2954ccc673bb02062e3e7da09bc75d843386b342f", size = 41846, upload-time = "2025-06-09T22:54:57.246Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5b/ad/3f0f9a705fb630d175146cd7b1d2bf5555c9beaed54e94132b21aac098a6/propcache-0.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1a342c834734edb4be5ecb1e9fb48cb64b1e2320fccbd8c54bf8da8f2a84c33", size = 208871, upload-time = "2025-06-09T22:54:58.975Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3a/38/2085cda93d2c8b6ec3e92af2c89489a36a5886b712a34ab25de9fbca7992/propcache-0.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a544caaae1ac73f1fecfae70ded3e93728831affebd017d53449e3ac052ac1e", size = 215720, upload-time = "2025-06-09T22:55:00.471Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/61/c1/d72ea2dc83ac7f2c8e182786ab0fc2c7bd123a1ff9b7975bee671866fe5f/propcache-0.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:310d11aa44635298397db47a3ebce7db99a4cc4b9bbdfcf6c98a60c8d5261cf1", size = 215203, upload-time = "2025-06-09T22:55:01.834Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/af/81/b324c44ae60c56ef12007105f1460d5c304b0626ab0cc6b07c8f2a9aa0b8/propcache-0.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1396592321ac83157ac03a2023aa6cc4a3cc3cfdecb71090054c09e5a7cce3", size = 206365, upload-time = "2025-06-09T22:55:03.199Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/09/73/88549128bb89e66d2aff242488f62869014ae092db63ccea53c1cc75a81d/propcache-0.3.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cabf5b5902272565e78197edb682017d21cf3b550ba0460ee473753f28d23c1", size = 196016, upload-time = "2025-06-09T22:55:04.518Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b9/3f/3bdd14e737d145114a5eb83cb172903afba7242f67c5877f9909a20d948d/propcache-0.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0a2f2235ac46a7aa25bdeb03a9e7060f6ecbd213b1f9101c43b3090ffb971ef6", size = 205596, upload-time = "2025-06-09T22:55:05.942Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/ca/2f4aa819c357d3107c3763d7ef42c03980f9ed5c48c82e01e25945d437c1/propcache-0.3.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:92b69e12e34869a6970fd2f3da91669899994b47c98f5d430b781c26f1d9f387", size = 200977, upload-time = "2025-06-09T22:55:07.792Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cd/4a/e65276c7477533c59085251ae88505caf6831c0e85ff8b2e31ebcbb949b1/propcache-0.3.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:54e02207c79968ebbdffc169591009f4474dde3b4679e16634d34c9363ff56b4", size = 197220, upload-time = "2025-06-09T22:55:09.173Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/54/fc7152e517cf5578278b242396ce4d4b36795423988ef39bb8cd5bf274c8/propcache-0.3.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4adfb44cb588001f68c5466579d3f1157ca07f7504fc91ec87862e2b8e556b88", size = 210642, upload-time = "2025-06-09T22:55:10.62Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b9/80/abeb4a896d2767bf5f1ea7b92eb7be6a5330645bd7fb844049c0e4045d9d/propcache-0.3.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fd3e6019dc1261cd0291ee8919dd91fbab7b169bb76aeef6c716833a3f65d206", size = 212789, upload-time = "2025-06-09T22:55:12.029Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/db/ea12a49aa7b2b6d68a5da8293dcf50068d48d088100ac016ad92a6a780e6/propcache-0.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4c181cad81158d71c41a2bce88edce078458e2dd5ffee7eddd6b05da85079f43", size = 205880, upload-time = "2025-06-09T22:55:13.45Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/e5/9076a0bbbfb65d1198007059c65639dfd56266cf8e477a9707e4b1999ff4/propcache-0.3.2-cp313-cp313-win32.whl", hash = "sha256:8a08154613f2249519e549de2330cf8e2071c2887309a7b07fb56098f5170a02", size = 37220, upload-time = "2025-06-09T22:55:15.284Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d3/f5/b369e026b09a26cd77aa88d8fffd69141d2ae00a2abaaf5380d2603f4b7f/propcache-0.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e41671f1594fc4ab0a6dec1351864713cb3a279910ae8b58f884a88a0a632c05", size = 40678, upload-time = "2025-06-09T22:55:16.445Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a4/3a/6ece377b55544941a08d03581c7bc400a3c8cd3c2865900a68d5de79e21f/propcache-0.3.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:9a3cf035bbaf035f109987d9d55dc90e4b0e36e04bbbb95af3055ef17194057b", size = 76560, upload-time = "2025-06-09T22:55:17.598Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/da/64a2bb16418740fa634b0e9c3d29edff1db07f56d3546ca2d86ddf0305e1/propcache-0.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:156c03d07dc1323d8dacaa221fbe028c5c70d16709cdd63502778e6c3ccca1b0", size = 44676, upload-time = "2025-06-09T22:55:18.922Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/36/7b/f025e06ea51cb72c52fb87e9b395cced02786610b60a3ed51da8af017170/propcache-0.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74413c0ba02ba86f55cf60d18daab219f7e531620c15f1e23d95563f505efe7e", size = 44701, upload-time = "2025-06-09T22:55:20.106Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a4/00/faa1b1b7c3b74fc277f8642f32a4c72ba1d7b2de36d7cdfb676db7f4303e/propcache-0.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f066b437bb3fa39c58ff97ab2ca351db465157d68ed0440abecb21715eb24b28", size = 276934, upload-time = "2025-06-09T22:55:21.5Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/74/ab/935beb6f1756e0476a4d5938ff44bf0d13a055fed880caf93859b4f1baf4/propcache-0.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1304b085c83067914721e7e9d9917d41ad87696bf70f0bc7dee450e9c71ad0a", size = 278316, upload-time = "2025-06-09T22:55:22.918Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f8/9d/994a5c1ce4389610838d1caec74bdf0e98b306c70314d46dbe4fcf21a3e2/propcache-0.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab50cef01b372763a13333b4e54021bdcb291fc9a8e2ccb9c2df98be51bcde6c", size = 282619, upload-time = "2025-06-09T22:55:24.651Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2b/00/a10afce3d1ed0287cef2e09506d3be9822513f2c1e96457ee369adb9a6cd/propcache-0.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fad3b2a085ec259ad2c2842666b2a0a49dea8463579c606426128925af1ed725", size = 265896, upload-time = "2025-06-09T22:55:26.049Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2e/a8/2aa6716ffa566ca57c749edb909ad27884680887d68517e4be41b02299f3/propcache-0.3.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:261fa020c1c14deafd54c76b014956e2f86991af198c51139faf41c4d5e83892", size = 252111, upload-time = "2025-06-09T22:55:27.381Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/36/4f/345ca9183b85ac29c8694b0941f7484bf419c7f0fea2d1e386b4f7893eed/propcache-0.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:46d7f8aa79c927e5f987ee3a80205c987717d3659f035c85cf0c3680526bdb44", size = 268334, upload-time = "2025-06-09T22:55:28.747Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3e/ca/fcd54f78b59e3f97b3b9715501e3147f5340167733d27db423aa321e7148/propcache-0.3.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:6d8f3f0eebf73e3c0ff0e7853f68be638b4043c65a70517bb575eff54edd8dbe", size = 255026, upload-time = "2025-06-09T22:55:30.184Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8b/95/8e6a6bbbd78ac89c30c225210a5c687790e532ba4088afb8c0445b77ef37/propcache-0.3.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:03c89c1b14a5452cf15403e291c0ccd7751d5b9736ecb2c5bab977ad6c5bcd81", size = 250724, upload-time = "2025-06-09T22:55:31.646Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ee/b0/0dd03616142baba28e8b2d14ce5df6631b4673850a3d4f9c0f9dd714a404/propcache-0.3.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:0cc17efde71e12bbaad086d679ce575268d70bc123a5a71ea7ad76f70ba30bba", size = 268868, upload-time = "2025-06-09T22:55:33.209Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c5/98/2c12407a7e4fbacd94ddd32f3b1e3d5231e77c30ef7162b12a60e2dd5ce3/propcache-0.3.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:acdf05d00696bc0447e278bb53cb04ca72354e562cf88ea6f9107df8e7fd9770", size = 271322, upload-time = "2025-06-09T22:55:35.065Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/35/91/9cb56efbb428b006bb85db28591e40b7736847b8331d43fe335acf95f6c8/propcache-0.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4445542398bd0b5d32df908031cb1b30d43ac848e20470a878b770ec2dcc6330", size = 265778, upload-time = "2025-06-09T22:55:36.45Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/4c/b0fe775a2bdd01e176b14b574be679d84fc83958335790f7c9a686c1f468/propcache-0.3.2-cp313-cp313t-win32.whl", hash = "sha256:f86e5d7cd03afb3a1db8e9f9f6eff15794e79e791350ac48a8c924e6f439f394", size = 41175, upload-time = "2025-06-09T22:55:38.436Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a4/ff/47f08595e3d9b5e149c150f88d9714574f1a7cbd89fe2817158a952674bf/propcache-0.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9704bedf6e7cbe3c65eca4379a9b53ee6a83749f047808cbb5044d40d7d72198", size = 44857, upload-time = "2025-06-09T22:55:39.687Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/35/cc0aaecf278bb4575b8555f2b137de5ab821595ddae9da9d3cd1da4072c7/propcache-0.3.2-py3-none-any.whl", hash = "sha256:98f1ec44fb675f5052cccc8e609c46ed23a35a1cfd18545ad4e29002d858a43f", size = 12663, upload-time = "2025-06-09T22:56:04.484Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "psutil"
|
||||
version = "7.0.0"
|
||||
@@ -815,6 +1219,15 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293, upload-time = "2025-01-06T17:26:25.553Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyjwt"
|
||||
version = "2.10.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e7/46/bd74733ff231675599650d3e47f361794b22ef3e3770998dda30d3b63726/pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", size = 87785, upload-time = "2024-11-28T03:43:29.933Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/61/ad/689f02752eeec26aed679477e80e632ef1b682313be70793d798c1d5fc8f/PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb", size = 22997, upload-time = "2024-11-28T03:43:27.893Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pymemcache"
|
||||
version = "4.0.0"
|
||||
@@ -824,6 +1237,19 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/41/ba/2f7b22d8135b51c4fefb041461f8431e1908778e6539ff5af6eeaaee367a/pymemcache-4.0.0-py2.py3-none-any.whl", hash = "sha256:f507bc20e0dc8d562f8df9d872107a278df049fa496805c1431b926f3ddd0eab", size = 60772, upload-time = "2022-10-17T16:53:04.388Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyopenssl"
|
||||
version = "25.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "cryptography" },
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/04/8c/cd89ad05804f8e3c17dea8f178c3f40eeab5694c30e0c9f5bcd49f576fc3/pyopenssl-25.1.0.tar.gz", hash = "sha256:8d031884482e0c67ee92bf9a4d8cceb08d92aba7136432ffb0703c5280fc205b", size = 179937, upload-time = "2025-05-17T16:28:31.31Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/80/28/2659c02301b9500751f8d42f9a6632e1508aa5120de5e43042b8b30f8d5d/pyopenssl-25.1.0-py3-none-any.whl", hash = "sha256:2b11f239acc47ac2e5aca04fd7fa829800aeee22a2eb30d744572a157bd8a1ab", size = 56771, upload-time = "2025-05-17T16:28:29.197Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "8.4.1"
|
||||
@@ -959,6 +1385,21 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/eb/bc/1709dc55f0970cf4cb8259e435e6773f9946f41a045c2cb90e870b7072da/pyzmq-27.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:d8229f2efece6a660ee211d74d91dbc2a76b95544d46c74c615e491900dc107f", size = 639933, upload-time = "2025-06-13T14:08:00.777Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "realtime"
|
||||
version = "2.4.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "aiohttp" },
|
||||
{ name = "python-dateutil" },
|
||||
{ name = "typing-extensions" },
|
||||
{ name = "websockets" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1e/1e/c5f47928789cd5abb96e527929dea088213968f785983a231b3dfe08cc4f/realtime-2.4.2.tar.gz", hash = "sha256:760308d5310533f65a9098e0b482a518f6ad2f3c0f2723e83cf5856865bafc5d", size = 18802, upload-time = "2025-03-26T17:39:11.26Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/1d/b7/1b7651f353e14543c60cdfe40e3ea4dea412cfb2e93ab6384e72be813f05/realtime-2.4.2-py3-none-any.whl", hash = "sha256:0cc1b4a097acf9c0bd3a2f1998170de47744574c606617285113ddb3021e54ca", size = 22025, upload-time = "2025-03-26T17:39:10.031Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "requests"
|
||||
version = "2.32.3"
|
||||
@@ -1139,6 +1580,59 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d9/61/f2b52e107b1fc8944b33ef56bf6ac4ebbe16d91b94d2b87ce013bf63fb84/starlette-0.45.3-py3-none-any.whl", hash = "sha256:dfb6d332576f136ec740296c7e8bb8c8a7125044e7c6da30744718880cdd059d", size = 71507, upload-time = "2025-01-24T11:17:34.182Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "storage3"
|
||||
version = "0.12.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "deprecation" },
|
||||
{ name = "httpx", extra = ["http2"] },
|
||||
{ name = "python-dateutil" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c5/86/9eae84e8ad4ba73f575f3eaf5536d949f2fd7d6adc85829f9af04bce97e2/storage3-0.12.0.tar.gz", hash = "sha256:94243f20922d57738bf42e96b9f5582b4d166e8bf209eccf20b146909f3f71b0", size = 10024, upload-time = "2025-06-19T17:50:51.763Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b0/7e/693d6d603db142eb5e6f3cb76eb6e9c439582b7539e2695e175e2de3ac44/storage3-0.12.0-py3-none-any.whl", hash = "sha256:1c4585693ca42243ded1512b58e54c697111e91a20916cd14783eebc37e7c87d", size = 18422, upload-time = "2025-06-19T17:50:50.294Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strenum"
|
||||
version = "0.4.15"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/85/ad/430fb60d90e1d112a62ff57bdd1f286ec73a2a0331272febfddd21f330e1/StrEnum-0.4.15.tar.gz", hash = "sha256:878fb5ab705442070e4dd1929bb5e2249511c0bcf2b0eeacf3bcd80875c82eff", size = 23384, upload-time = "2023-06-29T22:02:58.399Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/81/69/297302c5f5f59c862faa31e6cb9a4cd74721cd1e052b38e464c5b402df8b/StrEnum-0.4.15-py3-none-any.whl", hash = "sha256:a30cda4af7cc6b5bf52c8055bc4bf4b2b6b14a93b574626da33df53cf7740659", size = 8851, upload-time = "2023-06-29T22:02:56.947Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "supabase"
|
||||
version = "2.16.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "gotrue" },
|
||||
{ name = "httpx" },
|
||||
{ name = "postgrest" },
|
||||
{ name = "realtime" },
|
||||
{ name = "storage3" },
|
||||
{ name = "supafunc" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c6/93/335b91e8d09a95a337f051f84e85495f7732400f10c1bcb698a7571f8f1c/supabase-2.16.0.tar.gz", hash = "sha256:98f3810158012d4ec0e3083f2e5515f5e10b32bd71e7d458662140e963c1d164", size = 14595, upload-time = "2025-06-23T16:09:29.504Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/75/2ab71e6605d20a740ff041c6176a328cfaa3fcee0dd0db885e081d98df06/supabase-2.16.0-py3-none-any.whl", hash = "sha256:99065caab3d90a56650bf39fbd0e49740995da3738ab28706c61bd7f2401db55", size = 17713, upload-time = "2025-06-23T16:09:28.299Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "supafunc"
|
||||
version = "0.10.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "httpx", extra = ["http2"] },
|
||||
{ name = "strenum" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e8/4b/16f94bcae8a49f5e09544a4fb0e6ad1c2288038036cefdeedb72fcffd92c/supafunc-0.10.1.tar.gz", hash = "sha256:a5b33c8baecb6b5297d25da29a2503e2ec67ee6986f3d44c137e651b8a59a17d", size = 5036, upload-time = "2025-06-23T18:26:50.327Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/76/4a/9cbea12d86a741d4e73a6e278c2b1d6479fb03d1002efb00e8e71aea76db/supafunc-0.10.1-py3-none-any.whl", hash = "sha256:26df9bd25ff2ef56cb5bfb8962de98f43331f7f8ff69572bac3ed9c3a9672040", size = 8028, upload-time = "2025-06-23T18:26:49.176Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "threadpoolctl"
|
||||
version = "3.5.0"
|
||||
@@ -1328,3 +1822,68 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/14/13/8b7fc4cb551b9cfd9890f0fd66e53c18a06240319915533b033a56a3d520/websockets-14.2-cp313-cp313-win_amd64.whl", hash = "sha256:b439ea828c4ba99bb3176dc8d9b933392a2413c0f6b149fdcba48393f573377f", size = 164420, upload-time = "2025-01-19T21:00:10.182Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/c8/d529f8a32ce40d98309f4470780631e971a5a842b60aec864833b3615786/websockets-14.2-py3-none-any.whl", hash = "sha256:7a6ceec4ea84469f15cf15807a747e9efe57e369c384fa86e022b3bea679b79b", size = 157416, upload-time = "2025-01-19T21:00:54.843Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yarl"
|
||||
version = "1.20.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "idna" },
|
||||
{ name = "multidict" },
|
||||
{ name = "propcache" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/3c/fb/efaa23fa4e45537b827620f04cf8f3cd658b76642205162e072703a5b963/yarl-1.20.1.tar.gz", hash = "sha256:d017a4997ee50c91fd5466cef416231bb82177b93b029906cefc542ce14c35ac", size = 186428, upload-time = "2025-06-10T00:46:09.923Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/5f/9a/cb7fad7d73c69f296eda6815e4a2c7ed53fc70c2f136479a91c8e5fbdb6d/yarl-1.20.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdcc4cd244e58593a4379fe60fdee5ac0331f8eb70320a24d591a3be197b94a9", size = 133667, upload-time = "2025-06-10T00:43:44.369Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/67/38/688577a1cb1e656e3971fb66a3492501c5a5df56d99722e57c98249e5b8a/yarl-1.20.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b29a2c385a5f5b9c7d9347e5812b6f7ab267193c62d282a540b4fc528c8a9d2a", size = 91025, upload-time = "2025-06-10T00:43:46.295Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/50/ec/72991ae51febeb11a42813fc259f0d4c8e0507f2b74b5514618d8b640365/yarl-1.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1112ae8154186dfe2de4732197f59c05a83dc814849a5ced892b708033f40dc2", size = 89709, upload-time = "2025-06-10T00:43:48.22Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/da/4d798025490e89426e9f976702e5f9482005c548c579bdae792a4c37769e/yarl-1.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90bbd29c4fe234233f7fa2b9b121fb63c321830e5d05b45153a2ca68f7d310ee", size = 352287, upload-time = "2025-06-10T00:43:49.924Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1a/26/54a15c6a567aac1c61b18aa0f4b8aa2e285a52d547d1be8bf48abe2b3991/yarl-1.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:680e19c7ce3710ac4cd964e90dad99bf9b5029372ba0c7cbfcd55e54d90ea819", size = 345429, upload-time = "2025-06-10T00:43:51.7Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/95/9dcf2386cb875b234353b93ec43e40219e14900e046bf6ac118f94b1e353/yarl-1.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a979218c1fdb4246a05efc2cc23859d47c89af463a90b99b7c56094daf25a16", size = 365429, upload-time = "2025-06-10T00:43:53.494Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/91/b2/33a8750f6a4bc224242a635f5f2cff6d6ad5ba651f6edcccf721992c21a0/yarl-1.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255b468adf57b4a7b65d8aad5b5138dce6a0752c139965711bdcb81bc370e1b6", size = 363862, upload-time = "2025-06-10T00:43:55.766Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/98/28/3ab7acc5b51f4434b181b0cee8f1f4b77a65919700a355fb3617f9488874/yarl-1.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a97d67108e79cfe22e2b430d80d7571ae57d19f17cda8bb967057ca8a7bf5bfd", size = 355616, upload-time = "2025-06-10T00:43:58.056Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/36/a3/f666894aa947a371724ec7cd2e5daa78ee8a777b21509b4252dd7bd15e29/yarl-1.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8570d998db4ddbfb9a590b185a0a33dbf8aafb831d07a5257b4ec9948df9cb0a", size = 339954, upload-time = "2025-06-10T00:43:59.773Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f1/81/5f466427e09773c04219d3450d7a1256138a010b6c9f0af2d48565e9ad13/yarl-1.20.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:97c75596019baae7c71ccf1d8cc4738bc08134060d0adfcbe5642f778d1dca38", size = 365575, upload-time = "2025-06-10T00:44:02.051Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2e/e3/e4b0ad8403e97e6c9972dd587388940a032f030ebec196ab81a3b8e94d31/yarl-1.20.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1c48912653e63aef91ff988c5432832692ac5a1d8f0fb8a33091520b5bbe19ef", size = 365061, upload-time = "2025-06-10T00:44:04.196Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ac/99/b8a142e79eb86c926f9f06452eb13ecb1bb5713bd01dc0038faf5452e544/yarl-1.20.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4c3ae28f3ae1563c50f3d37f064ddb1511ecc1d5584e88c6b7c63cf7702a6d5f", size = 364142, upload-time = "2025-06-10T00:44:06.527Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/34/f2/08ed34a4a506d82a1a3e5bab99ccd930a040f9b6449e9fd050320e45845c/yarl-1.20.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c5e9642f27036283550f5f57dc6156c51084b458570b9d0d96100c8bebb186a8", size = 381894, upload-time = "2025-06-10T00:44:08.379Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/92/f8/9a3fbf0968eac704f681726eff595dce9b49c8a25cd92bf83df209668285/yarl-1.20.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2c26b0c49220d5799f7b22c6838409ee9bc58ee5c95361a4d7831f03cc225b5a", size = 383378, upload-time = "2025-06-10T00:44:10.51Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/af/85/9363f77bdfa1e4d690957cd39d192c4cacd1c58965df0470a4905253b54f/yarl-1.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:564ab3d517e3d01c408c67f2e5247aad4019dcf1969982aba3974b4093279004", size = 374069, upload-time = "2025-06-10T00:44:12.834Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/35/99/9918c8739ba271dcd935400cff8b32e3cd319eaf02fcd023d5dcd487a7c8/yarl-1.20.1-cp312-cp312-win32.whl", hash = "sha256:daea0d313868da1cf2fac6b2d3a25c6e3a9e879483244be38c8e6a41f1d876a5", size = 81249, upload-time = "2025-06-10T00:44:14.731Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/eb/83/5d9092950565481b413b31a23e75dd3418ff0a277d6e0abf3729d4d1ce25/yarl-1.20.1-cp312-cp312-win_amd64.whl", hash = "sha256:48ea7d7f9be0487339828a4de0360d7ce0efc06524a48e1810f945c45b813698", size = 86710, upload-time = "2025-06-10T00:44:16.716Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8a/e1/2411b6d7f769a07687acee88a062af5833cf1966b7266f3d8dfb3d3dc7d3/yarl-1.20.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:0b5ff0fbb7c9f1b1b5ab53330acbfc5247893069e7716840c8e7d5bb7355038a", size = 131811, upload-time = "2025-06-10T00:44:18.933Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b2/27/584394e1cb76fb771371770eccad35de400e7b434ce3142c2dd27392c968/yarl-1.20.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:14f326acd845c2b2e2eb38fb1346c94f7f3b01a4f5c788f8144f9b630bfff9a3", size = 90078, upload-time = "2025-06-10T00:44:20.635Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bf/9a/3246ae92d4049099f52d9b0fe3486e3b500e29b7ea872d0f152966fc209d/yarl-1.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f60e4ad5db23f0b96e49c018596707c3ae89f5d0bd97f0ad3684bcbad899f1e7", size = 88748, upload-time = "2025-06-10T00:44:22.34Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a3/25/35afe384e31115a1a801fbcf84012d7a066d89035befae7c5d4284df1e03/yarl-1.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49bdd1b8e00ce57e68ba51916e4bb04461746e794e7c4d4bbc42ba2f18297691", size = 349595, upload-time = "2025-06-10T00:44:24.314Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/28/2d/8aca6cb2cabc8f12efcb82749b9cefecbccfc7b0384e56cd71058ccee433/yarl-1.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:66252d780b45189975abfed839616e8fd2dbacbdc262105ad7742c6ae58f3e31", size = 342616, upload-time = "2025-06-10T00:44:26.167Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/e9/1312633d16b31acf0098d30440ca855e3492d66623dafb8e25b03d00c3da/yarl-1.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59174e7332f5d153d8f7452a102b103e2e74035ad085f404df2e40e663a22b28", size = 361324, upload-time = "2025-06-10T00:44:27.915Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bc/a0/688cc99463f12f7669eec7c8acc71ef56a1521b99eab7cd3abb75af887b0/yarl-1.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3968ec7d92a0c0f9ac34d5ecfd03869ec0cab0697c91a45db3fbbd95fe1b653", size = 359676, upload-time = "2025-06-10T00:44:30.041Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/af/44/46407d7f7a56e9a85a4c207724c9f2c545c060380718eea9088f222ba697/yarl-1.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1a4fbb50e14396ba3d375f68bfe02215d8e7bc3ec49da8341fe3157f59d2ff5", size = 352614, upload-time = "2025-06-10T00:44:32.171Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b1/91/31163295e82b8d5485d31d9cf7754d973d41915cadce070491778d9c9825/yarl-1.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11a62c839c3a8eac2410e951301309426f368388ff2f33799052787035793b02", size = 336766, upload-time = "2025-06-10T00:44:34.494Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b4/8e/c41a5bc482121f51c083c4c2bcd16b9e01e1cf8729e380273a952513a21f/yarl-1.20.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:041eaa14f73ff5a8986b4388ac6bb43a77f2ea09bf1913df7a35d4646db69e53", size = 364615, upload-time = "2025-06-10T00:44:36.856Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e3/5b/61a3b054238d33d70ea06ebba7e58597891b71c699e247df35cc984ab393/yarl-1.20.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:377fae2fef158e8fd9d60b4c8751387b8d1fb121d3d0b8e9b0be07d1b41e83dc", size = 360982, upload-time = "2025-06-10T00:44:39.141Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/df/a3/6a72fb83f8d478cb201d14927bc8040af901811a88e0ff2da7842dd0ed19/yarl-1.20.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1c92f4390e407513f619d49319023664643d3339bd5e5a56a3bebe01bc67ec04", size = 369792, upload-time = "2025-06-10T00:44:40.934Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/af/4cc3c36dfc7c077f8dedb561eb21f69e1e9f2456b91b593882b0b18c19dc/yarl-1.20.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d25ddcf954df1754ab0f86bb696af765c5bfaba39b74095f27eececa049ef9a4", size = 382049, upload-time = "2025-06-10T00:44:42.854Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/19/3a/e54e2c4752160115183a66dc9ee75a153f81f3ab2ba4bf79c3c53b33de34/yarl-1.20.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:909313577e9619dcff8c31a0ea2aa0a2a828341d92673015456b3ae492e7317b", size = 384774, upload-time = "2025-06-10T00:44:45.275Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9c/20/200ae86dabfca89060ec6447649f219b4cbd94531e425e50d57e5f5ac330/yarl-1.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:793fd0580cb9664548c6b83c63b43c477212c0260891ddf86809e1c06c8b08f1", size = 374252, upload-time = "2025-06-10T00:44:47.31Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/83/75/11ee332f2f516b3d094e89448da73d557687f7d137d5a0f48c40ff211487/yarl-1.20.1-cp313-cp313-win32.whl", hash = "sha256:468f6e40285de5a5b3c44981ca3a319a4b208ccc07d526b20b12aeedcfa654b7", size = 81198, upload-time = "2025-06-10T00:44:49.164Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/ba/39b1ecbf51620b40ab402b0fc817f0ff750f6d92712b44689c2c215be89d/yarl-1.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:495b4ef2fea40596bfc0affe3837411d6aa3371abcf31aac0ccc4bdd64d4ef5c", size = 86346, upload-time = "2025-06-10T00:44:51.182Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/43/c7/669c52519dca4c95153c8ad96dd123c79f354a376346b198f438e56ffeb4/yarl-1.20.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:f60233b98423aab21d249a30eb27c389c14929f47be8430efa7dbd91493a729d", size = 138826, upload-time = "2025-06-10T00:44:52.883Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/42/fc0053719b44f6ad04a75d7f05e0e9674d45ef62f2d9ad2c1163e5c05827/yarl-1.20.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6f3eff4cc3f03d650d8755c6eefc844edde99d641d0dcf4da3ab27141a5f8ddf", size = 93217, upload-time = "2025-06-10T00:44:54.658Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4f/7f/fa59c4c27e2a076bba0d959386e26eba77eb52ea4a0aac48e3515c186b4c/yarl-1.20.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:69ff8439d8ba832d6bed88af2c2b3445977eba9a4588b787b32945871c2444e3", size = 92700, upload-time = "2025-06-10T00:44:56.784Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2f/d4/062b2f48e7c93481e88eff97a6312dca15ea200e959f23e96d8ab898c5b8/yarl-1.20.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cf34efa60eb81dd2645a2e13e00bb98b76c35ab5061a3989c7a70f78c85006d", size = 347644, upload-time = "2025-06-10T00:44:59.071Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/47/78b7f40d13c8f62b499cc702fdf69e090455518ae544c00a3bf4afc9fc77/yarl-1.20.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8e0fe9364ad0fddab2688ce72cb7a8e61ea42eff3c7caeeb83874a5d479c896c", size = 323452, upload-time = "2025-06-10T00:45:01.605Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/eb/2b/490d3b2dc66f52987d4ee0d3090a147ea67732ce6b4d61e362c1846d0d32/yarl-1.20.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f64fbf81878ba914562c672024089e3401974a39767747691c65080a67b18c1", size = 346378, upload-time = "2025-06-10T00:45:03.946Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/66/ad/775da9c8a94ce925d1537f939a4f17d782efef1f973039d821cbe4bcc211/yarl-1.20.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6342d643bf9a1de97e512e45e4b9560a043347e779a173250824f8b254bd5ce", size = 353261, upload-time = "2025-06-10T00:45:05.992Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4b/23/0ed0922b47a4f5c6eb9065d5ff1e459747226ddce5c6a4c111e728c9f701/yarl-1.20.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56dac5f452ed25eef0f6e3c6a066c6ab68971d96a9fb441791cad0efba6140d3", size = 335987, upload-time = "2025-06-10T00:45:08.227Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3e/49/bc728a7fe7d0e9336e2b78f0958a2d6b288ba89f25a1762407a222bf53c3/yarl-1.20.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7d7f497126d65e2cad8dc5f97d34c27b19199b6414a40cb36b52f41b79014be", size = 329361, upload-time = "2025-06-10T00:45:10.11Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/93/8f/b811b9d1f617c83c907e7082a76e2b92b655400e61730cd61a1f67178393/yarl-1.20.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:67e708dfb8e78d8a19169818eeb5c7a80717562de9051bf2413aca8e3696bf16", size = 346460, upload-time = "2025-06-10T00:45:12.055Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/70/fd/af94f04f275f95da2c3b8b5e1d49e3e79f1ed8b6ceb0f1664cbd902773ff/yarl-1.20.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:595c07bc79af2494365cc96ddeb772f76272364ef7c80fb892ef9d0649586513", size = 334486, upload-time = "2025-06-10T00:45:13.995Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/84/65/04c62e82704e7dd0a9b3f61dbaa8447f8507655fd16c51da0637b39b2910/yarl-1.20.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7bdd2f80f4a7df852ab9ab49484a4dee8030023aa536df41f2d922fd57bf023f", size = 342219, upload-time = "2025-06-10T00:45:16.479Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/91/95/459ca62eb958381b342d94ab9a4b6aec1ddec1f7057c487e926f03c06d30/yarl-1.20.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c03bfebc4ae8d862f853a9757199677ab74ec25424d0ebd68a0027e9c639a390", size = 350693, upload-time = "2025-06-10T00:45:18.399Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/00/d393e82dd955ad20617abc546a8f1aee40534d599ff555ea053d0ec9bf03/yarl-1.20.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:344d1103e9c1523f32a5ed704d576172d2cabed3122ea90b1d4e11fe17c66458", size = 355803, upload-time = "2025-06-10T00:45:20.677Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9e/ed/c5fb04869b99b717985e244fd93029c7a8e8febdfcffa06093e32d7d44e7/yarl-1.20.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:88cab98aa4e13e1ade8c141daeedd300a4603b7132819c484841bb7af3edce9e", size = 341709, upload-time = "2025-06-10T00:45:23.221Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/fd/725b8e73ac2a50e78a4534ac43c6addf5c1c2d65380dd48a9169cc6739a9/yarl-1.20.1-cp313-cp313t-win32.whl", hash = "sha256:b121ff6a7cbd4abc28985b6028235491941b9fe8fe226e6fdc539c977ea1739d", size = 86591, upload-time = "2025-06-10T00:45:25.793Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/94/c3/b2e9f38bc3e11191981d57ea08cab2166e74ea770024a646617c9cddd9f6/yarl-1.20.1-cp313-cp313t-win_amd64.whl", hash = "sha256:541d050a355bbbc27e55d906bc91cb6fe42f96c01413dd0f4ed5a5240513874f", size = 93003, upload-time = "2025-06-10T00:45:27.752Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b4/2d/2345fce04cfd4bee161bf1e7d9cdc702e3e16109021035dbb24db654a622/yarl-1.20.1-py3-none-any.whl", hash = "sha256:83b8eb083fe4683c6115795d9fc1cfaf2cbbefb19b3a1cb68f6527460f483a77", size = 46542, upload-time = "2025-06-10T00:46:07.521Z" },
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user
Is this the way they do it at stadler? 😀
I prefer a different approach:
-alpineis enoughuvdocker container - the package is already built there. No need to run the installer, no curl dependencies, etc...The result looks something like:
What do you think?
Good idea. Changes implemented in commit fe1b42fff9