diff --git a/.containerignore b/.containerignore deleted file mode 100644 index 15697f7..0000000 --- a/.containerignore +++ /dev/null @@ -1,4 +0,0 @@ -.venv -dist -.pytest_cache -.forgejo diff --git a/.forgejo/workflows/test.yaml b/.forgejo/workflows/test.yaml new file mode 100644 index 0000000..66c7174 --- /dev/null +++ b/.forgejo/workflows/test.yaml @@ -0,0 +1,19 @@ +on: [push] +jobs: + install: + runs-on: container + container: + image: tiptop:5000/treetrail-backend-ci-base + volumes: + - "/root/.cache/uv:uv_cache" + services: + treetrail-database: + image: treetrail-database + steps: + - uses: actions/checkout@v4 + - name: Create venv + run: uv venv + - name: Install dependencies + run: uv sync + - name: Run basic test (bootstrap) + run: .venv/bin/pytest -s tests/basic.py diff --git a/.woodpecker/build.yaml b/.woodpecker/build.yaml deleted file mode 100644 index fd4d9cd..0000000 --- a/.woodpecker/build.yaml +++ /dev/null @@ -1,70 +0,0 @@ -when: - - event: manual - - event: tag - -depends_on: - - test - -steps: - python_sync: - image: code.philo.ydns.eu/philorg/uv - volumes: - - uv-cache:/uv-cache - environment: - UV_CACHE_DIR: /uv-cache - UV_LINK_MODE: copy - commands: - - uv sync - - python_build: - image: code.philo.ydns.eu/philorg/uv - volumes: - - uv-cache:/uv-cache - environment: - UV_CACHE_DIR: /uv-cache - UV_LINK_MODE: copy - commands: - - uv build --wheel - - uv cache prune --ci - - python_publish: - image: code.philo.ydns.eu/philorg/uv - volumes: - - uv-cache:/uv-cache - environment: - UV_CACHE_DIR: /uv-cache - UV_LINK_MODE: copy - environment: - OWNER: philorg - REGISTRY_URL: https://code.philo.ydns.eu - REGISTRY_TOKEN: - from_secret: registry_token - commands: - - uv publish --publish-url $REGISTRY_URL/api/packages/$OWNER/pypi --token $REGISTRY_TOKEN dist/*.whl - failure: ignore - - container_build_publish: - image: quay.io/podman/stable:latest - # Caution: This image is built daily. It might fill up your image store quickly. - #pull: true - volumes: - - containers:/var/lib/containers - - uv-cache:/uv-cache - # Fill in the trusted checkbox in Woodpecker's settings as well - privileged: true - environment: - UV_CACHE_DIR: /uv-cache - UV_LINK_MODE: copy - registry: code.philo.ydns.eu - org: philorg - container_name: treetrail-backend - registry_token: - from_secret: registry_token - commands: - # Login at the registry - - podman login -u __token__ --password $registry_token $registry - # Build the container image - - podman build --volume=/var/lib/containers:/var/lib/containers --tag $registry/$org/$container_name:latest --tag $registry/$org/$container_name:$CI_COMMIT_TAG . - # Push the image - - podman push $registry/$org/$container_name:latest - - podman push $registry/$org/$container_name:$CI_COMMIT_TAG diff --git a/.woodpecker/test.yaml b/.woodpecker/test.yaml deleted file mode 100644 index d8816b2..0000000 --- a/.woodpecker/test.yaml +++ /dev/null @@ -1,21 +0,0 @@ -when: - - event: push - branch: main - - event: manual - - event: tag - -steps: - sync: - image: code.philo.ydns.eu/philorg/uv - volumes: - - uv-cache:/uv-cache - environment: - UV_CACHE_DIR: /uv-cache - UV_LINK_MODE: copy - commands: - - uv sync - - test: - image: code.philo.ydns.eu/philorg/uv - commands: - - .venv/bin/pytest -s tests/basic.py diff --git a/Containerfile b/Containerfile index ff60531..167d1d3 100644 --- a/Containerfile +++ b/Containerfile @@ -1,17 +1,12 @@ -FROM docker.io/library/python:latest +FROM localhost/trixie_python +WORKDIR /usr/src/treetrail +ENV PATH="/usr/src/treetrail/.venv/bin:$PATH" +ENV PYTHONPATH="/usr/src" +COPY --from=localhost/treetrail_backend_deps /usr/src/treetrail/.venv/ /usr/src/treetrail/.venv +COPY --from=localhost/treetrail_backend_deps /usr/local/treetrail/ /usr/local/treetrail +COPY ./treetrail ./pyproject.toml ./README.md . -COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /usr/local/bin/ +# Instances should override the prod.yaml file +COPY ./prod.yaml /etc/treetrail/prod.yaml -COPY . /app - -# Sync the project into a new environment, using the frozen lockfile -WORKDIR /app - -RUN uv pip install --system . - -CMD [ \ - "uvicorn", "treetrail.application:app", \ - "--port", "8081", \ - #"--log-config", "/app/config/logging.yaml", \ - "--host", "0.0.0.0" \ - ] +CMD ["uvicorn", "treetrail.application:app", "--port", "8081", "--log-config", "logging.yaml", "--host", "0.0.0.0"] diff --git a/Containerfile.backend_ci_base b/Containerfile.backend_ci_base new file mode 100644 index 0000000..0010a3e --- /dev/null +++ b/Containerfile.backend_ci_base @@ -0,0 +1,7 @@ +FROM debian:trixie-slim +MAINTAINER philo email phil.dev@philome.mooo.com + +RUN apt update +RUN apt install --no-install-recommends -y python-is-python3 python3-pip python3-venv nodejs git +RUN pip install --break-system-packages uv +RUN apt-get clean && rm -rf /var/lib/apt/lists/* && rm -rf /root/.cache diff --git a/Containerfile.backend_deps b/Containerfile.backend_deps new file mode 100644 index 0000000..ec562a6 --- /dev/null +++ b/Containerfile.backend_deps @@ -0,0 +1,36 @@ +FROM localhost/trixie_python +MAINTAINER philo email phil.dev@philome.mooo.com + +#ENV PROJ_DIR=/usr +ENV PYTHONDONTWRITEBYTECODE 1 +ENV PDM_CHECK_UPDATE=false +#RUN apk add --no-cache make cmake clang gdal-dev geos-dev proj-dev proj-util gcc musl-dev bash +#RUN apk add --no-cache gdal-dev geos-dev proj-dev proj-util gcc musl-dev bash + +WORKDIR /usr/src/treetrail +COPY ./pyproject.toml ./README.md ./pdm.lock . +# Cheating pdm with the app version to allow install of dependencies +RUN PDM_BUILD_SCM_VERSION=1.0 pdm install --check --prod --no-editable + +## Instances should populate these dirs below +RUN mkdir -p /usr/local/treetrail/osm \ + /usr/local/treetrail/sprite \ + /usr/local/treetrail/cache/plantekey/img \ + /usr/local/treetrail/cache/plantekey/thumbnails \ + /usr/local/treetrail/cache/plantekey/type \ + /usr/local/treetrail/map/sprite \ + /usr/local/treetrail/map/osm \ + /usr/local/treetrail/attachments/tree \ + /usr/local/treetrail/attachments/trail \ + /usr/local/treetrail/attachments/poi +#COPY ./sprite /usr/local/treetrail +#COPY ./osm /usr/local/treetrail + +#RUN python -c 'import _version as v;print(v.__version__)' > version.txt + +#RUN PDM_BUILD_SCM_VERSION=$(cat version.txt) pdm install --check --prod --no-editable +# +# Clear some space (caches) +#RUN pdm cache clear +#RUN rm -rf .mypy_cache +#RUN rm -rf __pycache__ diff --git a/Containerfile.ci b/Containerfile.ci deleted file mode 100644 index 160472c..0000000 --- a/Containerfile.ci +++ /dev/null @@ -1,10 +0,0 @@ -# Build: podman build -t code.philo.ydns.eu/philorg/treetrail-backend-ci -f Containerfile.ci - -FROM code.philo.ydns.eu/philorg/python-ci - -COPY ./pyproject.toml ./README.md ./uv.lock /_lock/ - -RUN --mount=type=cache,target=/root/.cache <=0.6.1", - "orjson", - "pandas", - "passlib[bcrypt]", - "pillow", - "psycopg2-binary", - "pyarrow>=19.0.1", - "pydantic-settings", - "python-jose[cryptography]", - "python-multipart", - "requests", - "sqlalchemy[asyncio]", - "sqlmodel", - "uvicorn[standard]", - "uvloop", + "aiofiles", + "aiohttp-client-cache", + "aiosqlite", + "asyncpg", + "fastapi", + "geoalchemy2", + "geopandas", + "httptools>=0.6.1", + "orjson", + "pandas", + "passlib[bcrypt]", + "pillow", + "psycopg2-binary", + "pyarrow", + "pydantic-settings", + "python-jose[cryptography]", + "python-multipart", + "requests", + "sqlalchemy[asyncio]", + "sqlmodel", + "uvicorn[standard]", + "uvloop", ] requires-python = ">=3.11" readme = "README.md" -license = { text = "MIT" } +license = {text = "MIT"} classifiers = [ - "Development Status :: 3 - Alpha", - "Framework :: FastAPI", - "Environment :: Web Environment", - "Intended Audience :: Developers", - "License :: OSI Approved :: GNU General Public License (GPL)", - "Programming Language :: Python :: 3", - "Operating System :: MacOS :: MacOS X", - "Operating System :: POSIX", - "Programming Language :: Python", + "Development Status :: 3 - Alpha", + "Framework :: FastAPI", + "Environment :: Web Environment", + "Intended Audience :: Developers", + "License :: OSI Approved :: GNU General Public License (GPL)", + "Programming Language :: Python :: 3", + "Operating System :: MacOS :: MacOS X", + "Operating System :: POSIX", + "Programming Language :: Python", ] #[project.scripts] -#treetrail-backend = "treetrail_backend:main" - -[dependency-groups] -dev = ["dunamai>=1.23.0", "ipdb>=0.13.13"] +#treetrail-srv = "treetrail_srv:main" [build-system] -requires = ["hatchling", "uv-dynamic-versioning"] +requires = ["hatchling"] build-backend = "hatchling.build" -[tool.hatch.version] -source = "uv-dynamic-versioning" - [tool.hatch.build.targets.wheel] packages = ["src/treetrail"] -[tool.uv-dynamic-versioning] -style = "semver" - [tool.uv] -package = true dev-dependencies = [ - "httpx", - "ipdb", - "pandas-stubs", - "pytest", - "types-Pillow", - "types-PyYAML", - "types-aiofiles", - "types-passlib", - "types-python-jose", - "types-requests", + "httpx", + "ipdb", + "pandas-stubs", + "pytest", + "types-Pillow", + "types-PyYAML", + "types-aiofiles", + "types-passlib", + "types-python-jose", + "types-requests", ] -[tool.black] -line-length = 98 +#[tool.pdm.version] +#source = "scm" +#write_to = "treetrail/_version.py" +#write_template = "__version__ = '{}'" +# diff --git a/src/treetrail/__init__.py b/src/treetrail/__init__.py deleted file mode 100644 index 00eba03..0000000 --- a/src/treetrail/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -import importlib.metadata - -try: - from dunamai import Version, Style - - __version__ = Version.from_git().serialize(style=Style.SemVer, dirty=True) -except (ImportError, RuntimeError): - __version__ = importlib.metadata.version(__name__) diff --git a/src/treetrail/__main__.py b/src/treetrail/__main__.py deleted file mode 100644 index 2c86e3f..0000000 --- a/src/treetrail/__main__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .application import _main - -_main() \ No newline at end of file diff --git a/src/treetrail/_version.py b/src/treetrail/_version.py new file mode 100644 index 0000000..0404d81 --- /dev/null +++ b/src/treetrail/_version.py @@ -0,0 +1 @@ +__version__ = '0.3.0' diff --git a/src/treetrail/api_v1.py b/src/treetrail/api_v1.py index b1ba9d3..75573a9 100644 --- a/src/treetrail/api_v1.py +++ b/src/treetrail/api_v1.py @@ -36,8 +36,7 @@ from treetrail.models import (BaseMapStyles, User, Role, Bootstrap, MapStyle, Tree, Trail, TreeTrail, POI, UserWithRoles, Zone, VersionedComponent) -from treetrail.config import conf, get_cache_dir -from treetrail import __version__ +from treetrail.config import conf, get_cache_dir, __version__ from treetrail.plantekey import get_local_details from treetrail.tiles import registry as tilesRegistry @@ -51,7 +50,7 @@ api_app = FastAPI( default_response_class=responses.ORJSONResponse, ) -re_findmimetype = re.compile(r'^data:(\S+);') # type: ignore +re_findmimetype = re.compile('^data:(\S+);') # type: ignore attachment_types: dict[str, type[Tree] | type[Trail] | type[POI]] = { 'tree': Tree, diff --git a/src/treetrail/application.py b/src/treetrail/application.py index fab6476..afa8cd8 100755 --- a/src/treetrail/application.py +++ b/src/treetrail/application.py @@ -51,7 +51,22 @@ app.mount( def _main(argv=None): from argparse import ArgumentParser arg_parser = ArgumentParser( - description="Treetrail backend / server", + description="fastapi Application server", + prog="fastapi" + ) + arg_parser.add_argument( + '--path', + help='Path of socket file', + ) + arg_parser.add_argument( + "-H", "--hostname", + help="TCP/IP hostname to serve on (default: %(default)r)", + default="localhost" + ) + arg_parser.add_argument( + "-P", "--port", + help="TCP/IP port to serve on", + type=int, ) arg_parser.add_argument( "-c", "--create-db", @@ -139,11 +154,6 @@ def _main(argv=None): help="Set debug logging", action="store_true" ) - arg_parser.add_argument( - "--version", - help="Print version and exit", - action="store_true" - ) args = arg_parser.parse_args() if args.debug: @@ -151,11 +161,6 @@ def _main(argv=None): ## For ipdb: logging.getLogger('parso').setLevel(logging.WARNING) - if args.version: - import treetrail - print(treetrail.__version__) - sys.exit(0) - if args.create_db: from treetrail.database import create_db import asyncio @@ -228,8 +233,7 @@ def _main(argv=None): sys.exit(0) print( - 'No CLI option was given, try --help', - 'To run the server, use an asgi server like uvicorn.', + 'This application needs to be run with an asgi server like uvicorn.', 'For example:', 'uvicorn application:app', 'or:', diff --git a/src/treetrail/config.py b/src/treetrail/config.py index 2fd0934..865be4a 100644 --- a/src/treetrail/config.py +++ b/src/treetrail/config.py @@ -12,6 +12,8 @@ from pydantic_settings import ( ) from pydantic.v1.utils import deep_update +from treetrail._version import __version__ + logger = logging.getLogger(__name__) ENV = environ.get("env", "prod") @@ -63,11 +65,16 @@ def create_dirs(): def get_cache_dir() -> Path: return Path(conf.storage.root_cache_path) +class MyBaseSettings(BaseSettings): + model_config = SettingsConfigDict( + env_prefix='treetrail_', + env_nested_delimiter="_", + ) -class DB(BaseSettings): - model_config = SettingsConfigDict(env_prefix="treetrail_db_") + +class DB(MyBaseSettings): # uri: str - host: str = "localhost" + host: str = "treetrail-database" port: int = 5432 user: str = "treetrail" db: str = "treetrail" @@ -85,62 +92,53 @@ class DB(BaseSettings): return f"postgresql://{self.user}:{self.password}@{self.host}:{self.port}/{self.db}" -class App(BaseSettings): - model_config = SettingsConfigDict(env_prefix="treetrail_app_") +class App(MyBaseSettings): title: str = "Tree Trail" -class Storage(BaseSettings): - model_config = SettingsConfigDict(env_prefix="treetrail_storage_") +class Storage(MyBaseSettings): root_attachment_path: str = "/var/lib/treetrail/attachments" root_cache_path: str = "/var/lib/treetrail/cache" -class Tiles(BaseSettings): - model_config = SettingsConfigDict(env_prefix="treetrail_tiles_") +class Tiles(MyBaseSettings): baseDir: str = "/var/lib/treetrail/mbtiles_files" useRequestUrl: bool = True spriteBaseDir: str = "/var/lib/treetrail/mbtiles_sprites" - spriteUrl: str = "tiles/sprite/sprite" + spriteUrl: str = "/tiles/sprite/sprite" spriteBaseUrl: str = "https://treetrail.example.org" osmBaseDir: str = "/var/lib/treetrail/osm" -class Map(BaseSettings): - model_config = SettingsConfigDict(env_prefix="treetrail_map_") +class Map(MyBaseSettings): zoom: float = 14.0 pitch: float = 0.0 - lat: float = 45.8822 - lng: float = 6.1781 + lat: float = 12.0000 + lng: float = 79.8106 bearing: float = 0 background: str = "OpenFreeMap" -class Geo(BaseSettings): - model_config = SettingsConfigDict(env_prefix="treetrail_geo_") +class Geo(MyBaseSettings): simplify_geom_factor: int = 10000000 simplify_preserve_topology: bool = False -class Security(BaseSettings): - model_config = SettingsConfigDict(env_prefix="treetrail_security_") +class Security(MyBaseSettings): """ JWT security configuration """ - secret_key: str = token_hex(32) '''Generate with eg.: "openssl rand -hex 32"''' access_token_expire_minutes: float = 30 -class ExternalMapStyle(BaseSettings): - model_config = SettingsConfigDict(env_prefix="treetrail_external_map_style_") +class ExternalMapStyle(MyBaseSettings): name: str url: str -class Config(BaseSettings): - model_config = SettingsConfigDict(env_prefix="treetrail_") +class Config(MyBaseSettings): @classmethod def settings_customise_sources( @@ -157,15 +155,13 @@ class Config(BaseSettings): # postgres: dict storage: Storage = Storage() map: Map = Map() - mapStyles: dict[str, str] = { - "OpenFreeMap": "https://tiles.openfreemap.org/styles/liberty" - } + mapStyles: dict[str, str] = {} tiles: Tiles = Tiles() security: Security = Security() geo: Geo = Geo() - version: str = "-" + version: str db: DB = DB() - base_href: str = "/treetrail" + base_href: str = '/treetrail' -conf = Config() +conf = Config(version=__version__) # type: ignore diff --git a/src/treetrail/database.py b/src/treetrail/database.py index 94e15bf..abcb9b2 100644 --- a/src/treetrail/database.py +++ b/src/treetrail/database.py @@ -14,7 +14,7 @@ from treetrail.config import conf logger = logging.getLogger(__name__) -CREATE_DB_TIMEOUT = 10 +CREATE_DB_TIMEOUT = 30 engine = create_async_engine( conf.db.get_sqla_url(), @@ -33,7 +33,6 @@ async def create_db(drop=False): await conn.run_sync(SQLModel.metadata.drop_all) await conn.run_sync(SQLModel.metadata.create_all) - logger.debug(f"Connect to database with config: {conf.db}") while attempts > 0: try: await try_once() @@ -68,7 +67,6 @@ async def populate_init_db(): """Populate the database for a fresh install""" from sqlalchemy import text from treetrail.security import create_user, add_role, add_user_role - logger.info("Populating initial database") user = await create_user(username="admin", password="admin") @@ -77,7 +75,7 @@ async def populate_init_db(): async with db_session() as session: for initial in initials: await session.execute(text(initial)) - logger.debug(f"Added map style {initial}") + logger.debug(f'Added map style {initial}') await session.commit() diff --git a/src/treetrail/defaults.yml b/src/treetrail/defaults.yml index 60a86b4..e5f8667 100644 --- a/src/treetrail/defaults.yml +++ b/src/treetrail/defaults.yml @@ -19,7 +19,7 @@ map: baseDir: /var/lib/treetrail/mbtiles_files useRequestUrl: true spriteBaseDir: /var/lib/treetrail/mbtiles_sprites - spriteUrl: tiles/sprite/sprite + spriteUrl: /tiles/sprite/sprite spriteBaseUrl: https://treetrail.example.org osmBaseDir: /var/lib/treetrail/osm zoom: 14 diff --git a/src/treetrail/tiles.py b/src/treetrail/tiles.py index 4d07e8e..07a57ff 100644 --- a/src/treetrail/tiles.py +++ b/src/treetrail/tiles.py @@ -141,7 +141,7 @@ class MBTiles: 'tilejson': '2.0.0', 'version': 8, 'glyphs': "/assets/fonts/glyphs/{fontstack}/{range}.pbf", - 'sprite': f"{conf.tiles.spriteUrl}", + 'sprite': f"{base_url}{conf.tiles.spriteUrl}", 'sources': { 'treeTrailTiles': { 'type': 'vector', diff --git a/src/treetrail/utils.py b/src/treetrail/utils.py index 50efc95..52ee9d0 100644 --- a/src/treetrail/utils.py +++ b/src/treetrail/utils.py @@ -7,19 +7,19 @@ import pandas as pd from sqlalchemy.ext.declarative import DeclarativeMeta from sqlalchemy.engine.row import Row from sqlalchemy.sql.selectable import Select -import geopandas as gpd # type: ignore +import geopandas as gpd # type: ignore from treetrail.config import conf logger = logging.getLogger(__name__) - class AlchemyEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj.__class__, DeclarativeMeta): # an SQLAlchemy class fields = {} - for field in [x for x in dir(obj) if not x.startswith("_") and x != "metadata"]: + for field in [x for x in dir(obj) + if not x.startswith('_') and x != 'metadata']: data = obj.__getattribute__(field) try: # this will fail on non-encodable values, like other classes @@ -50,30 +50,24 @@ def get_attachment_root(type: str): def get_attachment_tree_root(): - return get_attachment_root("tree") + return get_attachment_root('tree') def get_attachment_trail_root(): - return get_attachment_root("trail") + return get_attachment_root('trail') def get_attachment_poi_root(): - return get_attachment_root("poi") + return get_attachment_root('poi') def pandas_query(session, query): return pd.read_sql_query(query, session.connection()) - -def geopandas_query( - session, - query: Select, - model, - *, - # simplify_tolerance: float|None=None, - crs=None, - cast=True, -): +def geopandas_query(session, query: Select, model, *, + # simplify_tolerance: float|None=None, + crs=None, cast=True, + ): ## XXX: I could not get the add_columns work without creating a subquery, ## so moving the simplification to geopandas - see in _get_df # if simplify_tolerance is not None: @@ -84,11 +78,9 @@ def geopandas_query( # query = query.add_columns(new_column) return gpd.GeoDataFrame.from_postgis(query, session.connection(), crs=crs) - def mkdir(dir: Path | str) -> Path: path = Path(dir) if not path.is_dir(): - logger.info(f"Create directory {path}") + logger.info(f'Create directory {path}') path.mkdir(parents=True, exist_ok=True) return path - diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/treetrail-kube.yaml b/treetrail-kube.yaml deleted file mode 100644 index a245ff3..0000000 --- a/treetrail-kube.yaml +++ /dev/null @@ -1,122 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: treetrail - annotations: - io.kubernetes.cri-o.SandboxID/gisaf-backend: treetrail-cri-o - io.kubernetes.cri-o.SandboxID/gisaf-database: treetrail-cri-o - io.kubernetes.cri-o.SandboxID/gisaf-frontend: treetrail-cri-o - io.kubernetes.cri-o.SandboxID/gisaf-redis: treetrail-cri-o - io.podman.annotations.infra.name: treetrail-infra - labels: - app: treetrail -spec: - ports: - - name: "80" - nodePort: 31080 - port: 80 - targetPort: 80 - - name: "4532" - nodePort: 31432 - port: 4532 - targetPort: 4532 - selector: - app: treetrail - type: NodePort ---- -apiVersion: v1 -kind: Pod -metadata: - labels: - app: treetrail - name: treetrail -spec: - containers: - - image: code.philo.ydns.eu/philorg/treetrail-frontend:latest - args: - - nginx - - -g - - daemon off; - name: treetrail-frontend - ports: - - containerPort: 80 - hostPort: 8080 - - image: code.philo.ydns.eu/philorg/treetrail-backend:latest - name: treetrail-backend - - image: code.philo.ydns.eu/philorg/treetrail-database:latest - args: - - postgres - name: treetrail-database - ports: - - containerPort: 4532 - hostPort: 15432 - volumeMounts: - - mountPath: /var/lib/postgresql/data - name: treetrail-pgdata - volumes: - - name: treetrail-pgdata - persistentVolumeClaim: - claimName: treetrail-pgdata-pvc - restartPolicy: Always ---- -apiVersion: v1 -kind: PersistentVolume -metadata: - name: treetrail-pgdata-pv - labels: - type: local - app: postgres -spec: - storageClassName: manual - capacity: - storage: 2Gi - accessModes: - - ReadWriteMany - hostPath: - path: /data/postgresql ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: treetrail-pgdata-pvc -spec: - storageClassName: manual - accessModes: - - ReadWriteMany - resources: - requests: - storage: 2Gi ---- -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: treetrail - namespace: default - #annotations: - # kubernetes.io/ingress.class: traefik - # #traefik.ingress.kubernetes.io/router.middlewares: default-strip-prefix@kubernetescrd -spec: - rules: - - http: - paths: - - path: /treetrail - pathType: Prefix - backend: - service: - name: treetrail-frontend - port: - number: 80 - - path: /treetrail/v1 - pathType: Prefix - backend: - service: - name: treetrail-backend - port: - number: 8081 - - path: /treetrail/plantekey - pathType: Prefix - backend: - service: - name: treetrail-backend - port: - number: 8081 diff --git a/uv.lock b/uv.lock index 20f6558..f93a336 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,4 @@ version = 1 -revision = 1 requires-python = ">=3.11" resolution-markers = [ "python_full_version < '3.12'", @@ -147,18 +146,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e4/f5/f2b75d2fc6f1a260f340f0e7c6a060f4dd2961cc16884ed851b0d18da06a/anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d", size = 90377 }, ] -[[package]] -name = "asttokens" -version = "2.4.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/45/1d/f03bcb60c4a3212e15f99a56085d93093a497718adf828d050b9d675da81/asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0", size = 62284 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/45/86/4736ac618d82a20d87d2f92ae19441ebc7ac9e7a581d7e58bbe79233b24a/asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24", size = 27764 }, -] - [[package]] name = "asyncpg" version = "0.30.0" @@ -343,7 +330,7 @@ name = "click" version = "8.1.7" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "platform_system == 'Windows'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 } wheels = [ @@ -388,27 +375,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/87/5c/3dab83cc4aba1f4b0e733e3f0c3e7d4386440d660ba5b1e3ff995feb734d/cryptography-43.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362", size = 3068026 }, ] -[[package]] -name = "decorator" -version = "5.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/66/0c/8d907af351aa16b42caae42f9d6aa37b900c67308052d10fdce809f8d952/decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330", size = 35016 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d5/50/83c593b07763e1161326b3b8c6686f0f4b0f24d5526546bee538c89837d6/decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186", size = 9073 }, -] - -[[package]] -name = "dunamai" -version = "1.23.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "packaging" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/06/4e/a5c8c337a1d9ac0384298ade02d322741fb5998041a5ea74d1cd2a4a1d47/dunamai-1.23.0.tar.gz", hash = "sha256:a163746de7ea5acb6dacdab3a6ad621ebc612ed1e528aaa8beedb8887fccd2c4", size = 44681 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/21/4c/963169386309fec4f96fd61210ac0a0666887d0fb0a50205395674d20b71/dunamai-1.23.0-py3-none-any.whl", hash = "sha256:a0906d876e92441793c6a423e16a4802752e723e9c9a5aabdc5535df02dbe041", size = 26342 }, -] - [[package]] name = "ecdsa" version = "0.19.0" @@ -421,15 +387,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/00/e7/ed3243b30d1bec41675b6394a1daae46349dc2b855cb83be846a5a918238/ecdsa-0.19.0-py2.py3-none-any.whl", hash = "sha256:2cea9b88407fdac7bbeca0833b189e4c9c53f2ef1e1eaa29f6224dbc809b707a", size = 149266 }, ] -[[package]] -name = "executing" -version = "2.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8c/e3/7d45f492c2c4a0e8e0fad57d081a7c8a0286cdd86372b070cca1ec0caa1e/executing-2.1.0.tar.gz", hash = "sha256:8ea27ddd260da8150fa5a708269c4a10e76161e2496ec3e587da9e3c0fe4b9ab", size = 977485 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/fd/afcd0496feca3276f509df3dbd5dae726fcc756f1a08d9e25abe1733f962/executing-2.1.0-py2.py3-none-any.whl", hash = "sha256:8d63781349375b5ebccc3142f4b30350c0cd9c79f921cde38be2be4637e98eaf", size = 25805 }, -] - [[package]] name = "fastapi" version = "0.115.3" @@ -655,40 +612,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, ] -[[package]] -name = "ipdb" -version = "0.13.13" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "decorator" }, - { name = "ipython" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3d/1b/7e07e7b752017f7693a0f4d41c13e5ca29ce8cbcfdcc1fd6c4ad8c0a27a0/ipdb-0.13.13.tar.gz", hash = "sha256:e3ac6018ef05126d442af680aad863006ec19d02290561ac88b8b1c0b0cfc726", size = 17042 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0c/4c/b075da0092003d9a55cf2ecc1cae9384a1ca4f650d51b00fc59875fe76f6/ipdb-0.13.13-py3-none-any.whl", hash = "sha256:45529994741c4ab6d2388bfa5d7b725c2cf7fe9deffabdb8a6113aa5ed449ed4", size = 12130 }, -] - -[[package]] -name = "ipython" -version = "8.28.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "decorator" }, - { name = "jedi" }, - { name = "matplotlib-inline" }, - { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "prompt-toolkit" }, - { name = "pygments" }, - { name = "stack-data" }, - { name = "traitlets" }, - { name = "typing-extensions", marker = "python_full_version < '3.12'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f7/21/48db7d9dd622b9692575004c7c98f85f5629428f58596c59606d36c51b58/ipython-8.28.0.tar.gz", hash = "sha256:0d0d15ca1e01faeb868ef56bc7ee5a0de5bd66885735682e8a322ae289a13d1a", size = 5495762 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/3a/5d8680279ada9571de8469220069d27024ee47624af534e537c9ff49a450/ipython-8.28.0-py3-none-any.whl", hash = "sha256:530ef1e7bb693724d3cdc37287c80b07ad9b25986c007a53aa1857272dac3f35", size = 819456 }, -] - [[package]] name = "itsdangerous" version = "2.2.0" @@ -698,30 +621,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234 }, ] -[[package]] -name = "jedi" -version = "0.19.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "parso" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d6/99/99b493cec4bf43176b678de30f81ed003fd6a647a301b9c927280c600f0a/jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd", size = 1227821 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/20/9f/bc63f0f0737ad7a60800bfd472a4836661adae21f9c2535f3957b1e54ceb/jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0", size = 1569361 }, -] - -[[package]] -name = "matplotlib-inline" -version = "0.1.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/99/5b/a36a337438a14116b16480db471ad061c36c3694df7c2084a0da7ba538b7/matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90", size = 8159 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca", size = 9899 }, -] - [[package]] name = "multidict" version = "6.1.0" @@ -907,28 +806,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ab/5f/b38085618b950b79d2d9164a711c52b10aefc0ae6833b96f626b7021b2ed/pandas-2.2.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ad5b65698ab28ed8d7f18790a0dc58005c7629f227be9ecc1072aa74c0c1d43a", size = 13098436 }, ] -[[package]] -name = "pandas-stubs" -version = "2.2.3.241009" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, - { name = "types-pytz" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d4/30/1ca31098512cdcfbc6ce366072848dff497880d4285281606b5895244bbc/pandas_stubs-2.2.3.241009.tar.gz", hash = "sha256:d4ab618253f0acf78a5d0d2bfd6dffdd92d91a56a69bdc8144e5a5c6d25be3b5", size = 103801 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/be/d9ba3109c4c19a78e125f63074c4e436e447f30ece15f0ef1865e7178233/pandas_stubs-2.2.3.241009-py3-none-any.whl", hash = "sha256:3a6f8f142105a42550be677ba741ba532621f4e0acad2155c0e7b2450f114cfa", size = 157883 }, -] - -[[package]] -name = "parso" -version = "0.8.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/66/94/68e2e17afaa9169cf6412ab0f28623903be73d1b32e208d9e8e541bb086d/parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d", size = 400609 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", size = 103650 }, -] - [[package]] name = "passlib" version = "1.7.4" @@ -943,18 +820,6 @@ bcrypt = [ { name = "bcrypt" }, ] -[[package]] -name = "pexpect" -version = "4.9.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "ptyprocess" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772 }, -] - [[package]] name = "pillow" version = "11.0.0" @@ -1013,18 +878,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, ] -[[package]] -name = "prompt-toolkit" -version = "3.0.48" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "wcwidth" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2d/4f/feb5e137aff82f7c7f3248267b97451da3644f6cdc218edfe549fb354127/prompt_toolkit-3.0.48.tar.gz", hash = "sha256:d6623ab0477a80df74e646bdbc93621143f5caf104206aa29294d53de1a03d90", size = 424684 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/6a/fd08d94654f7e67c52ca30523a178b3f8ccc4237fce4be90d39c938a831a/prompt_toolkit-3.0.48-py3-none-any.whl", hash = "sha256:f49a827f90062e411f1ce1f854f2aedb3c23353244f8108b89283587397ac10e", size = 386595 }, -] - [[package]] name = "propcache" version = "0.2.0" @@ -1122,60 +975,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ce/ac/5b1ea50fc08a9df82de7e1771537557f07c2632231bbab652c7e22597908/psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bb89f0a835bcfc1d42ccd5f41f04870c1b936d8507c6df12b7737febc40f0909", size = 2822712 }, { url = "https://files.pythonhosted.org/packages/c4/fc/504d4503b2abc4570fac3ca56eb8fed5e437bf9c9ef13f36b6621db8ef00/psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f0c2d907a1e102526dd2986df638343388b94c33860ff3bbe1384130828714b1", size = 2920155 }, { url = "https://files.pythonhosted.org/packages/b2/d1/323581e9273ad2c0dbd1902f3fb50c441da86e894b6e25a73c3fda32c57e/psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f8157bed2f51db683f31306aa497311b560f2265998122abe1dce6428bd86567", size = 2959356 }, - { url = "https://files.pythonhosted.org/packages/08/50/d13ea0a054189ae1bc21af1d85b6f8bb9bbc5572991055d70ad9006fe2d6/psycopg2_binary-2.9.10-cp313-cp313-win_amd64.whl", hash = "sha256:27422aa5f11fbcd9b18da48373eb67081243662f9b46e6fd07c3eb46e4535142", size = 2569224 }, -] - -[[package]] -name = "ptyprocess" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993 }, -] - -[[package]] -name = "pure-eval" -version = "0.2.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842 }, ] [[package]] name = "pyarrow" -version = "19.0.1" +version = "17.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7f/09/a9046344212690f0632b9c709f9bf18506522feb333c894d0de81d62341a/pyarrow-19.0.1.tar.gz", hash = "sha256:3bf266b485df66a400f282ac0b6d1b500b9d2ae73314a153dbe97d6d5cc8a99e", size = 1129437 } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/27/4e/ea6d43f324169f8aec0e57569443a38bab4b398d09769ca64f7b4d467de3/pyarrow-17.0.0.tar.gz", hash = "sha256:4beca9521ed2c0921c1023e68d097d0299b62c362639ea315572a58f3f50fd28", size = 1112479 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/55/f1a8d838ec07fe3ca53edbe76f782df7b9aafd4417080eebf0b42aab0c52/pyarrow-19.0.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:cc55d71898ea30dc95900297d191377caba257612f384207fe9f8293b5850f90", size = 30713987 }, - { url = "https://files.pythonhosted.org/packages/13/12/428861540bb54c98a140ae858a11f71d041ef9e501e6b7eb965ca7909505/pyarrow-19.0.1-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:7a544ec12de66769612b2d6988c36adc96fb9767ecc8ee0a4d270b10b1c51e00", size = 32135613 }, - { url = "https://files.pythonhosted.org/packages/2f/8a/23d7cc5ae2066c6c736bce1db8ea7bc9ac3ef97ac7e1c1667706c764d2d9/pyarrow-19.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0148bb4fc158bfbc3d6dfe5001d93ebeed253793fff4435167f6ce1dc4bddeae", size = 41149147 }, - { url = "https://files.pythonhosted.org/packages/a2/7a/845d151bb81a892dfb368bf11db584cf8b216963ccce40a5cf50a2492a18/pyarrow-19.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f24faab6ed18f216a37870d8c5623f9c044566d75ec586ef884e13a02a9d62c5", size = 42178045 }, - { url = "https://files.pythonhosted.org/packages/a7/31/e7282d79a70816132cf6cae7e378adfccce9ae10352d21c2fecf9d9756dd/pyarrow-19.0.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:4982f8e2b7afd6dae8608d70ba5bd91699077323f812a0448d8b7abdff6cb5d3", size = 40532998 }, - { url = "https://files.pythonhosted.org/packages/b8/82/20f3c290d6e705e2ee9c1fa1d5a0869365ee477e1788073d8b548da8b64c/pyarrow-19.0.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:49a3aecb62c1be1d822f8bf629226d4a96418228a42f5b40835c1f10d42e4db6", size = 42084055 }, - { url = "https://files.pythonhosted.org/packages/ff/77/e62aebd343238863f2c9f080ad2ef6ace25c919c6ab383436b5b81cbeef7/pyarrow-19.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:008a4009efdb4ea3d2e18f05cd31f9d43c388aad29c636112c2966605ba33466", size = 25283133 }, - { url = "https://files.pythonhosted.org/packages/78/b4/94e828704b050e723f67d67c3535cf7076c7432cd4cf046e4bb3b96a9c9d/pyarrow-19.0.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:80b2ad2b193e7d19e81008a96e313fbd53157945c7be9ac65f44f8937a55427b", size = 30670749 }, - { url = "https://files.pythonhosted.org/packages/7e/3b/4692965e04bb1df55e2c314c4296f1eb12b4f3052d4cf43d29e076aedf66/pyarrow-19.0.1-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:ee8dec072569f43835932a3b10c55973593abc00936c202707a4ad06af7cb294", size = 32128007 }, - { url = "https://files.pythonhosted.org/packages/22/f7/2239af706252c6582a5635c35caa17cb4d401cd74a87821ef702e3888957/pyarrow-19.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d5d1ec7ec5324b98887bdc006f4d2ce534e10e60f7ad995e7875ffa0ff9cb14", size = 41144566 }, - { url = "https://files.pythonhosted.org/packages/fb/e3/c9661b2b2849cfefddd9fd65b64e093594b231b472de08ff658f76c732b2/pyarrow-19.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3ad4c0eb4e2a9aeb990af6c09e6fa0b195c8c0e7b272ecc8d4d2b6574809d34", size = 42202991 }, - { url = "https://files.pythonhosted.org/packages/fe/4f/a2c0ed309167ef436674782dfee4a124570ba64299c551e38d3fdaf0a17b/pyarrow-19.0.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:d383591f3dcbe545f6cc62daaef9c7cdfe0dff0fb9e1c8121101cabe9098cfa6", size = 40507986 }, - { url = "https://files.pythonhosted.org/packages/27/2e/29bb28a7102a6f71026a9d70d1d61df926887e36ec797f2e6acfd2dd3867/pyarrow-19.0.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b4c4156a625f1e35d6c0b2132635a237708944eb41df5fbe7d50f20d20c17832", size = 42087026 }, - { url = "https://files.pythonhosted.org/packages/16/33/2a67c0f783251106aeeee516f4806161e7b481f7d744d0d643d2f30230a5/pyarrow-19.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:5bd1618ae5e5476b7654c7b55a6364ae87686d4724538c24185bbb2952679960", size = 25250108 }, - { url = "https://files.pythonhosted.org/packages/2b/8d/275c58d4b00781bd36579501a259eacc5c6dfb369be4ddeb672ceb551d2d/pyarrow-19.0.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:e45274b20e524ae5c39d7fc1ca2aa923aab494776d2d4b316b49ec7572ca324c", size = 30653552 }, - { url = "https://files.pythonhosted.org/packages/a0/9e/e6aca5cc4ef0c7aec5f8db93feb0bde08dbad8c56b9014216205d271101b/pyarrow-19.0.1-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:d9dedeaf19097a143ed6da37f04f4051aba353c95ef507764d344229b2b740ae", size = 32103413 }, - { url = "https://files.pythonhosted.org/packages/6a/fa/a7033f66e5d4f1308c7eb0dfcd2ccd70f881724eb6fd1776657fdf65458f/pyarrow-19.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ebfb5171bb5f4a52319344ebbbecc731af3f021e49318c74f33d520d31ae0c4", size = 41134869 }, - { url = "https://files.pythonhosted.org/packages/2d/92/34d2569be8e7abdc9d145c98dc410db0071ac579b92ebc30da35f500d630/pyarrow-19.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a21d39fbdb948857f67eacb5bbaaf36802de044ec36fbef7a1c8f0dd3a4ab2", size = 42192626 }, - { url = "https://files.pythonhosted.org/packages/0a/1f/80c617b1084fc833804dc3309aa9d8daacd46f9ec8d736df733f15aebe2c/pyarrow-19.0.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:99bc1bec6d234359743b01e70d4310d0ab240c3d6b0da7e2a93663b0158616f6", size = 40496708 }, - { url = "https://files.pythonhosted.org/packages/e6/90/83698fcecf939a611c8d9a78e38e7fed7792dcc4317e29e72cf8135526fb/pyarrow-19.0.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1b93ef2c93e77c442c979b0d596af45e4665d8b96da598db145b0fec014b9136", size = 42075728 }, - { url = "https://files.pythonhosted.org/packages/40/49/2325f5c9e7a1c125c01ba0c509d400b152c972a47958768e4e35e04d13d8/pyarrow-19.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:d9d46e06846a41ba906ab25302cf0fd522f81aa2a85a71021826f34639ad31ef", size = 25242568 }, - { url = "https://files.pythonhosted.org/packages/3f/72/135088d995a759d4d916ec4824cb19e066585b4909ebad4ab196177aa825/pyarrow-19.0.1-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:c0fe3dbbf054a00d1f162fda94ce236a899ca01123a798c561ba307ca38af5f0", size = 30702371 }, - { url = "https://files.pythonhosted.org/packages/2e/01/00beeebd33d6bac701f20816a29d2018eba463616bbc07397fdf99ac4ce3/pyarrow-19.0.1-cp313-cp313t-macosx_12_0_x86_64.whl", hash = "sha256:96606c3ba57944d128e8a8399da4812f56c7f61de8c647e3470b417f795d0ef9", size = 32116046 }, - { url = "https://files.pythonhosted.org/packages/1f/c9/23b1ea718dfe967cbd986d16cf2a31fe59d015874258baae16d7ea0ccabc/pyarrow-19.0.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f04d49a6b64cf24719c080b3c2029a3a5b16417fd5fd7c4041f94233af732f3", size = 41091183 }, - { url = "https://files.pythonhosted.org/packages/3a/d4/b4a3aa781a2c715520aa8ab4fe2e7fa49d33a1d4e71c8fc6ab7b5de7a3f8/pyarrow-19.0.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a9137cf7e1640dce4c190551ee69d478f7121b5c6f323553b319cac936395f6", size = 42171896 }, - { url = "https://files.pythonhosted.org/packages/23/1b/716d4cd5a3cbc387c6e6745d2704c4b46654ba2668260d25c402626c5ddb/pyarrow-19.0.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:7c1bca1897c28013db5e4c83944a2ab53231f541b9e0c3f4791206d0c0de389a", size = 40464851 }, - { url = "https://files.pythonhosted.org/packages/ed/bd/54907846383dcc7ee28772d7e646f6c34276a17da740002a5cefe90f04f7/pyarrow-19.0.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:58d9397b2e273ef76264b45531e9d552d8ec8a6688b7390b5be44c02a37aade8", size = 42085744 }, + { url = "https://files.pythonhosted.org/packages/f9/46/ce89f87c2936f5bb9d879473b9663ce7a4b1f4359acc2f0eb39865eaa1af/pyarrow-17.0.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:1c8856e2ef09eb87ecf937104aacfa0708f22dfeb039c363ec99735190ffb977", size = 29028748 }, + { url = "https://files.pythonhosted.org/packages/8d/8e/ce2e9b2146de422f6638333c01903140e9ada244a2a477918a368306c64c/pyarrow-17.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e19f569567efcbbd42084e87f948778eb371d308e137a0f97afe19bb860ccb3", size = 27190965 }, + { url = "https://files.pythonhosted.org/packages/3b/c8/5675719570eb1acd809481c6d64e2136ffb340bc387f4ca62dce79516cea/pyarrow-17.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b244dc8e08a23b3e352899a006a26ae7b4d0da7bb636872fa8f5884e70acf15", size = 39269081 }, + { url = "https://files.pythonhosted.org/packages/5e/78/3931194f16ab681ebb87ad252e7b8d2c8b23dad49706cadc865dff4a1dd3/pyarrow-17.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b72e87fe3e1db343995562f7fff8aee354b55ee83d13afba65400c178ab2597", size = 39864921 }, + { url = "https://files.pythonhosted.org/packages/d8/81/69b6606093363f55a2a574c018901c40952d4e902e670656d18213c71ad7/pyarrow-17.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:dc5c31c37409dfbc5d014047817cb4ccd8c1ea25d19576acf1a001fe07f5b420", size = 38740798 }, + { url = "https://files.pythonhosted.org/packages/4c/21/9ca93b84b92ef927814cb7ba37f0774a484c849d58f0b692b16af8eebcfb/pyarrow-17.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:e3343cb1e88bc2ea605986d4b94948716edc7a8d14afd4e2c097232f729758b4", size = 39871877 }, + { url = "https://files.pythonhosted.org/packages/30/d1/63a7c248432c71c7d3ee803e706590a0b81ce1a8d2b2ae49677774b813bb/pyarrow-17.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:a27532c38f3de9eb3e90ecab63dfda948a8ca859a66e3a47f5f42d1e403c4d03", size = 25151089 }, + { url = "https://files.pythonhosted.org/packages/d4/62/ce6ac1275a432b4a27c55fe96c58147f111d8ba1ad800a112d31859fae2f/pyarrow-17.0.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:9b8a823cea605221e61f34859dcc03207e52e409ccf6354634143e23af7c8d22", size = 29019418 }, + { url = "https://files.pythonhosted.org/packages/8e/0a/dbd0c134e7a0c30bea439675cc120012337202e5fac7163ba839aa3691d2/pyarrow-17.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f1e70de6cb5790a50b01d2b686d54aaf73da01266850b05e3af2a1bc89e16053", size = 27152197 }, + { url = "https://files.pythonhosted.org/packages/cb/05/3f4a16498349db79090767620d6dc23c1ec0c658a668d61d76b87706c65d/pyarrow-17.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0071ce35788c6f9077ff9ecba4858108eebe2ea5a3f7cf2cf55ebc1dbc6ee24a", size = 39263026 }, + { url = "https://files.pythonhosted.org/packages/c2/0c/ea2107236740be8fa0e0d4a293a095c9f43546a2465bb7df34eee9126b09/pyarrow-17.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:757074882f844411fcca735e39aae74248a1531367a7c80799b4266390ae51cc", size = 39880798 }, + { url = "https://files.pythonhosted.org/packages/f6/b0/b9164a8bc495083c10c281cc65064553ec87b7537d6f742a89d5953a2a3e/pyarrow-17.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:9ba11c4f16976e89146781a83833df7f82077cdab7dc6232c897789343f7891a", size = 38715172 }, + { url = "https://files.pythonhosted.org/packages/f1/c4/9625418a1413005e486c006e56675334929fad864347c5ae7c1b2e7fe639/pyarrow-17.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b0c6ac301093b42d34410b187bba560b17c0330f64907bfa4f7f7f2444b0cf9b", size = 39874508 }, + { url = "https://files.pythonhosted.org/packages/ae/49/baafe2a964f663413be3bd1cf5c45ed98c5e42e804e2328e18f4570027c1/pyarrow-17.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:392bc9feabc647338e6c89267635e111d71edad5fcffba204425a7c8d13610d7", size = 25099235 }, ] [[package]] @@ -1270,15 +1094,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/34/19/26bb6bdb9fdad5f0dfce538780814084fb667b4bc37fcb28459c14b8d3b5/pydantic_settings-2.6.0-py3-none-any.whl", hash = "sha256:4a819166f119b74d7f8c765196b165f95cc7487ce58ea27dec8a5a26be0970e0", size = 28578 }, ] -[[package]] -name = "pygments" -version = "2.18.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/62/8336eff65bcbc8e4cb5d05b55faf041285951b6e80f33e2bff2024788f31/pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", size = 4891905 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a", size = 1205513 }, -] - [[package]] name = "pyogrio" version = "0.10.0" @@ -1576,20 +1391,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/dd/b1/3af5104b716c420e40a6ea1b09886cae3a1b9f4538343875f637755cae5b/sqlmodel-0.0.22-py3-none-any.whl", hash = "sha256:a1ed13e28a1f4057cbf4ff6cdb4fc09e85702621d3259ba17b3c230bfb2f941b", size = 28276 }, ] -[[package]] -name = "stack-data" -version = "0.6.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "asttokens" }, - { name = "executing" }, - { name = "pure-eval" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521 }, -] - [[package]] name = "starlette" version = "0.41.0" @@ -1603,16 +1404,8 @@ wheels = [ ] [[package]] -name = "traitlets" -version = "5.14.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359 }, -] - -[[package]] -name = "treetrail-backend" +name = "treetrail-srv" +version = "0.1.0" source = { editable = "." } dependencies = [ { name = "aiofiles" }, @@ -1641,17 +1434,8 @@ dependencies = [ [package.dev-dependencies] dev = [ - { name = "dunamai" }, { name = "httpx" }, - { name = "ipdb" }, - { name = "pandas-stubs" }, { name = "pytest" }, - { name = "types-aiofiles" }, - { name = "types-passlib" }, - { name = "types-pillow" }, - { name = "types-python-jose" }, - { name = "types-pyyaml" }, - { name = "types-requests" }, ] [package.metadata] @@ -1669,7 +1453,7 @@ requires-dist = [ { name = "passlib", extras = ["bcrypt"] }, { name = "pillow" }, { name = "psycopg2-binary" }, - { name = "pyarrow", specifier = ">=19.0.1" }, + { name = "pyarrow" }, { name = "pydantic-settings" }, { name = "python-jose", extras = ["cryptography"] }, { name = "python-multipart" }, @@ -1682,96 +1466,8 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ - { name = "dunamai", specifier = ">=1.23.0" }, - { name = "httpx" }, - { name = "ipdb" }, - { name = "ipdb", specifier = ">=0.13.13" }, - { name = "pandas-stubs" }, - { name = "pytest" }, - { name = "types-aiofiles" }, - { name = "types-passlib" }, - { name = "types-pillow" }, - { name = "types-python-jose" }, - { name = "types-pyyaml" }, - { name = "types-requests" }, -] - -[[package]] -name = "types-aiofiles" -version = "24.1.0.20240626" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/13/e9/013940b017c313c2e15c64017268fdb0c25e0638621fb8a5d9ebe00fb0f4/types-aiofiles-24.1.0.20240626.tar.gz", hash = "sha256:48604663e24bc2d5038eac05ccc33e75799b0779e93e13d6a8f711ddc306ac08", size = 9357 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c3/ad/c4b3275d21c5be79487c4f6ed7cd13336997746fe099236cb29256a44a90/types_aiofiles-24.1.0.20240626-py3-none-any.whl", hash = "sha256:7939eca4a8b4f9c6491b6e8ef160caee9a21d32e18534a57d5ed90aee47c66b4", size = 9389 }, -] - -[[package]] -name = "types-passlib" -version = "1.7.7.20240819" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d3/19/5041c4bce2909c67fc3f9471ad67972d94c31cb591a970a8faf1220a3717/types-passlib-1.7.7.20240819.tar.gz", hash = "sha256:8fc8df71623845032293d5cf7f8091f0adfeba02d387a2888684b8413f14b3d0", size = 18386 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/4b/606ac25e89908e4577cd1aa19ffbebe55a6720cff69303db68701f3cc388/types_passlib-1.7.7.20240819-py3-none-any.whl", hash = "sha256:c4d299083497b66e12258c7b77c08952574213fdf7009da3135d8181a6a25f23", size = 33240 }, -] - -[[package]] -name = "types-pillow" -version = "10.2.0.20240822" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/18/4a/4495264dddaa600d65d68bcedb64dcccf9d9da61adff51f7d2ffd8e4c9ce/types-Pillow-10.2.0.20240822.tar.gz", hash = "sha256:559fb52a2ef991c326e4a0d20accb3bb63a7ba8d40eb493e0ecb0310ba52f0d3", size = 35389 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/66/23/e81a5354859831fcf54d488d33b80ba6133ea84f874a9c0ec40a4881e133/types_Pillow-10.2.0.20240822-py3-none-any.whl", hash = "sha256:d9dab025aba07aeb12fd50a6799d4eac52a9603488eca09d7662543983f16c5d", size = 54354 }, -] - -[[package]] -name = "types-pyasn1" -version = "0.6.0.20240913" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c5/e2/42410b64ba53584a8f2b681e76b23569a61869a22325cfeef2728e999ffd/types-pyasn1-0.6.0.20240913.tar.gz", hash = "sha256:a1da054db13d3d4ccfa69c515678154014336ad3d9f9ade01845f9edb1a2bc71", size = 12375 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ff/6a/847b2a137dba37974e17cc2ae5f62bed0d68006ac609a063810038adecff/types_pyasn1-0.6.0.20240913-py3-none-any.whl", hash = "sha256:95f3cb1fbd63ff91cd0410945f8aeae6b0be359533c00f39d8e17124884157af", size = 19338 }, -] - -[[package]] -name = "types-python-jose" -version = "3.3.4.20240106" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "types-pyasn1" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/4d/83/5824277f62a0a07ab3eaade216f19b59fadea4efdad9071d70799d97f170/types-python-jose-3.3.4.20240106.tar.gz", hash = "sha256:b18cf8c5080bbfe1ef7c3b707986435d9efca3e90889acb6a06f65e06bc3405a", size = 6937 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/84/bd/fe23e814f1ca70f8427bf5defb981b8e0636731863c7836a6d6b6e49c715/types_python_jose-3.3.4.20240106-py3-none-any.whl", hash = "sha256:b515a6c0c61f5e2a53bc93e3a2b024cbd42563e2e19cbde9fd1c2cc2cfe77ccc", size = 9712 }, -] - -[[package]] -name = "types-pytz" -version = "2024.2.0.20241003" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/66/d0/73aa3063a9ef9881bd7103cb4ae379bfd8fafda0e86b01b694d676313a4b/types-pytz-2024.2.0.20241003.tar.gz", hash = "sha256:575dc38f385a922a212bac00a7d6d2e16e141132a3c955078f4a4fd13ed6cb44", size = 5474 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/86/60/2a2977ce0f91255bbb668350b127a801a06ad37c326a2e5bfd52f03e0784/types_pytz-2024.2.0.20241003-py3-none-any.whl", hash = "sha256:3e22df1336c0c6ad1d29163c8fda82736909eb977281cb823c57f8bae07118b7", size = 5245 }, -] - -[[package]] -name = "types-pyyaml" -version = "6.0.12.20240917" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/92/7d/a95df0a11f95c8f48d7683f03e4aed1a2c0fc73e9de15cca4d38034bea1a/types-PyYAML-6.0.12.20240917.tar.gz", hash = "sha256:d1405a86f9576682234ef83bcb4e6fff7c9305c8b1fbad5e0bcd4f7dbdc9c587", size = 12381 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/2c/c1d81d680997d24b0542aa336f0a65bd7835e5224b7670f33a7d617da379/types_PyYAML-6.0.12.20240917-py3-none-any.whl", hash = "sha256:392b267f1c0fe6022952462bf5d6523f31e37f6cea49b14cee7ad634b6301570", size = 15264 }, -] - -[[package]] -name = "types-requests" -version = "2.32.0.20241016" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fa/3c/4f2a430c01a22abd49a583b6b944173e39e7d01b688190a5618bd59a2e22/types-requests-2.32.0.20241016.tar.gz", hash = "sha256:0d9cad2f27515d0e3e3da7134a1b6f28fb97129d86b867f24d9c726452634d95", size = 18065 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/01/485b3026ff90e5190b5e24f1711522e06c79f4a56c8f4b95848ac072e20f/types_requests-2.32.0.20241016-py3-none-any.whl", hash = "sha256:4195d62d6d3e043a4eaaf08ff8a62184584d2e8684e9d2aa178c7915a7da3747", size = 15836 }, + { name = "httpx", specifier = ">=0.27.2" }, + { name = "pytest", specifier = ">=8.3.3" }, ] [[package]] @@ -1912,15 +1608,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a6/8b/8a7755c5e7221bb35fe4af2dc44db9174f90ebf0344fd5e9b1e8b42d381e/watchfiles-0.24.0-cp313-none-win_amd64.whl", hash = "sha256:a974231b4fdd1bb7f62064a0565a6b107d27d21d9acb50c484d2cdba515b9366", size = 276622 }, ] -[[package]] -name = "wcwidth" -version = "0.2.13" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6c/63/53559446a878410fc5a5974feb13d31d78d752eb18aeba59c7fef1af7598/wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5", size = 101301 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166 }, -] - [[package]] name = "websockets" version = "13.1"