diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..d91b45c --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,48 @@ +# CI template: runs the pre-commit hooks and the test suite on every push. +# +# The Python version below should match the one in containers/apptainer.def; +# change it in both places when the project moves on. + +name: CI + +on: + push: + branches: [main] + pull_request: + +# A new push to a branch cancels any run still in progress for it. +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + PYTHON_VERSION: "3.12" + +jobs: + # Runs every hook in .pre-commit-config.yaml (mdformat, ruff, ty, ...) over + # the whole repo, not just the changed files. + pre-commit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: astral-sh/setup-uv@v8.3.2 + with: + python-version: ${{ env.PYTHON_VERSION }} + enable-cache: true + - uses: actions/cache@v6 + with: + path: ~/.cache/pre-commit + key: pre-commit-${{ hashFiles('.pre-commit-config.yaml') }} + - run: uvx pre-commit run --all-files --show-diff-on-failure + + pytest: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: astral-sh/setup-uv@v8.3.2 + with: + python-version: ${{ env.PYTHON_VERSION }} + enable-cache: true + # --frozen fails if uv.lock is out of date with pyproject.toml. + - run: uv sync --frozen + - run: uv run pytest diff --git a/.gitignore b/.gitignore index acf0849..1fc9c00 100644 --- a/.gitignore +++ b/.gitignore @@ -4,10 +4,7 @@ __pycache__/ *$py.class # User defined folders -docs/ data/ -containers/ -models/ # Data files. *.csv diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6fb8386..7e32fd6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 + rev: v6.0.0 hooks: - id: check-added-large-files args: ["--maxkb=4096"] @@ -9,14 +9,14 @@ repos: - id: trailing-whitespace files: \.(js|rb|md|py|sh|txt|yaml|yml|kidm)$ - - repo: https://github.com/igorshubovych/markdownlint-cli - rev: v0.30.0 + - repo: local hooks: - - id: markdownlint - files: \.md$ - language_version: "13.14.0" - args: - - --fix + - id: mdformat + name: mdformat + entry: uvx --with mdformat-gfm --with mdformat-frontmatter mdformat --wrap 100 --number + language: system + types: [markdown] + pass_filenames: true - repo: local hooks: diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..b48d33d --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,47 @@ +# High-level project description + +> Describe your project here + +## Research workflows + +- Maintain a append-only `LOGBOOK.md` file for each iteration, with the following structure in + antichronological order: + + ``` + ## - YYYY-MM-DD + + + + + + + + + ``` + +- Maintain a `RESULTS.md` that compiles the (comparable) results obtained so far. It should be an + up-to-date version of the key results found in `LOGBOOK.md`. + +## Reporting + +Reports are written in quarto. All plots should be generated with Python cells (not copied from +elsewhere), ideally from cached results to minimize the generation time. Reporting code should be +re-usable, so favor functions instead of throwaway code. + +## Coding Style + +- Use `uv` to run scripts +- Use `uv ruff check` to lint the code and `uvx ty check` to type check it. +- Always use `uv ruff format` to format the code according to our guidelines after you are done + editing a file. +- All functions must have type hints for their arguments and return values +- All functions should have docstings (numpy style), the docstring should be short and simple, avoid + notes sections and exemples sections in docstrings unless strictly necessary. +- Code should focus on simplicity and clarity, avoid scope creep, avoid implementing non-necessary + options. +- Polars should be prefered over pandas unless really necessary (e.g., geopandas). +- Project configurations and data paths are defined in `src/package_name/data/config.yaml` and + `src/package_name/config.py`, data folder paths should not be hardcoded in scripts, rather they + should be loaded from configurations. +- Tests live in `tests/`, are run with `uv run pytest`, and follow the same style rules as the rest + of the code (type hints, short numpy-style docstrings). diff --git a/GUIDELINES.md b/GUIDELINES.md new file mode 100644 index 0000000..3346ce6 --- /dev/null +++ b/GUIDELINES.md @@ -0,0 +1,113 @@ +# Project template + +This template should be used for every Python project in the lab. It uses: + +- [`uv`](https://docs.astral.sh/uv/) for dependency management. +- [`ruff`](https://docs.astral.sh/ruff/) for code formatting. +- [`ty`](https://docs.astral.sh/ty/) for type checking. +- [`pre-commit`](https://pre-commit.com/) hooks for automated validation. +- [`pytest`](https://docs.pytest.org/) for testing. +- GitHub Actions to run the hooks and the tests on every push. + +## Dependency management + +We use [`uv`](https://docs.astral.sh/uv/) for dependency management. It is just as full-featured as +`poetry`, but _much faster_. Follow the instructions below to create a new project: + +1. Update the name of the project in `pyproject.toml`. This is the distribution name, and it usually + matches the name of the repository (hyphens are fine here). + +2. Rename the folder `src/package_name` to the name of your package, and update the import in + `tests/test_hello.py` to match. This is a Python module name, so it must use underscores rather + than hyphens (`my_project`, not `my-project`) — otherwise it cannot be imported. + +3. Run `uv sync` from the root of the repo. This will create a virtual environment and install + needed development dependencies. + +4. Add the dependencies you need (and run this same command every time you need a new package): + + ```sh + uv add polars lightgbm + ``` + +5. Take a look at the `uv`'s [Getting started guide](https://docs.astral.sh/uv/getting-started/). + +## Pre-commit hooks + +Install the pre-commit hooks: + +```sh +uvx pre-commit install +``` + +This will create a `.git/hooks/pre-commit` file that will run the pre-commit hooks every time you +commit. Upon the first commit, the hooks will be installed. + +Some hooks output error message that require a manual change (e.g., linting errors). Other hooks +perform automated fixes. Either way, you need to re-run the commit command: + +```sh +git commit -m "My message" +``` + +### Code formatting + +Among the pre-commit hooks, you will find one that runs [`ruff`](https://docs.astral.sh/ruff/) on +every Python file. It is also warmly recommended that you set up `ruff` in your IDE (e.g., Visual +Studio Code, PyCharm). + +### Typing + +We recommend the use of [type hints](https://docs.python.org/3/library/typing.html) of your code. +One of the pre-commit hooks is [`ty`](https://docs.astral.sh/ty/), which will perform type checking +when hints are available. This reduces greatly the risk of bugs and the maintainability of the code. + +## Tests + +Tests live in `tests/` and are run with [`pytest`](https://docs.pytest.org/): + +```sh +uv run pytest +``` + +Unlike the linters, `pytest` is a dev dependency in `pyproject.toml` rather than a `uvx` tool: it +has to import your package, so it needs the project environment. It is installed by `uv sync`. + +`tests/test_hello.py` is a stub covering the example `hello` function. Populate `tests/` as follows: + +1. Delete `src/package_name/hello.py` and `tests/test_hello.py` once your own code replaces the + example. + +2. Name test files `test_*.py` and test functions `test_*`, mirroring the layout of your package + (`src/package_name/foo.py` is tested by `tests/test_foo.py`). + +3. Write one test per behaviour you want to keep working, and name it after that behaviour + (`test_hello_returns_greeting`, not `test_1`). A test that would still pass if the function were + broken is not worth having. + +4. Cover the cases you are tempted to check by hand in a notebook: the empty input, the boundary, + the error path. Add a test reproducing any bug you fix, so it cannot come back. + +5. Keep tests fast and independent of the lab storage. If a test needs data, generate a small + fixture in the test itself rather than reading from a data path. + +The same style rules apply to test code as to the rest: type hints and a short numpy-style docstring +on every test function. + +## Continuous integration + +`.github/workflows/ci.yml` defines two jobs, which run on every push to `main` and on every pull +request: + +- `pre-commit` runs every hook over all files, so CI fails on anything you did not run locally. +- `pytest` runs `uv sync --frozen` and the test suite. `--frozen` fails if `uv.lock` is out of date + with `pyproject.toml`, so commit the lockfile whenever you add a dependency. + +Both jobs pin the Python version through the `PYTHON_VERSION` variable at the top of the workflow. +It should match the version in `containers/apptainer.def`; change it in both places. To reproduce a +CI failure locally: + +```sh +uvx pre-commit run --all-files +uv run pytest +``` diff --git a/README.md b/README.md index 3adac2e..d435100 100644 --- a/README.md +++ b/README.md @@ -1,59 +1,85 @@ -# Project template +# {Project name} -This template should be used for every Python project in the lab. It uses: +> One or two sentences on what this project does and why it exists. -- [`uv`](https://docs.astral.sh/uv/) for dependency management. -- [`ruff`](https://docs.astral.sh/ruff/) for code formatting. -- [`ty`](https://docs.astral.sh/ty/) for type checking. -- [`pre-commit`](https://pre-commit.com/) hooks for automated validation. +## Status -## Dependency management +{Early exploration | Active development | Stable | Archived}. {Anything a newcomer should know +before relying on this: what works, what doesn't.} -We use [`uv`](https://docs.astral.sh/uv/) for dependency management. It is just as -full-featured as `poetry`, but _much faster_. Follow the instructions below to -create a new project: +## Getting started -1. Update the name of the project in `pyproject.toml`. -2. Change the name of the folder `src/python-base` to match the project name. -3. Run `uv sync` from the root of the repo. -This will create a virtual environment and install needed development dependencies. -4. Add the dependencies you need (and run this same command every time you need - a new package): +Requires Python >=3.12 and [`uv`](https://docs.astral.sh/uv/). - ```sh - uv add polars lightgbm - ``` +```sh +uv sync # create the virtualenv and install dependencies +uvx pre-commit install # install the pre-commit hooks +``` + +Check the install works: -5. Take a look at the `uv`'s [Getting started guide](https://docs.astral.sh/uv/getting-started/). +```sh +uv run python -m {package_name}.hello +``` -## Pre-commit hooks +## Usage -Install the pre-commit hooks: +{The shortest command that produces something useful, and the output it prints. Add one example per +entry point.} ```sh -uvx pre-commit install +uv run python -m {package_name}.{entry_point} --help ``` -This will create a `.git/hooks/pre-commit` file that will run the pre-commit -hooks every time you commit. Upon the first commit, the hooks will be installed. +## Layout + +| Path | Contents | +| -------------------------- | ------------------------------------------------- | +| `src/{package_name}/` | Library code, importable as `{package_name}`. | +| `src/{package_name}/data/` | `config.yaml` — data paths and project settings. | +| `tests/` | Test suite, run with `uv run pytest`. | +| `containers/` | Apptainer definition and entrypoint. | +| {scripts, notebooks, …} | {Fill in the folders this project actually adds.} | + +Data paths live in `config.yaml` and are read through `config.py` — never hardcode them in scripts. + +## Data + +{Where the inputs come from, where they live on the lab storage, and how to get them. Say if +anything is restricted or must not be committed.} -Some hooks output error message that require a manual change (e.g., linting -errors). Other hooks perform automated fixes. Either way, you need to re-run -the commit command: +## Results + +`LOGBOOK.md` records each iteration in antichronological order (hypothesis, method, key results, +next steps). `RESULTS.md` compiles the comparable results across iterations, and is the place to +look first. + +{Link the reports here as they are produced.} + +## Containers + +Build and run the Apptainer image, binding your working directory: ```sh -git commit -m "My message" +apptainer build --build-arg PROJECT_NAME={project-name} project.sif containers/apptainer.def +apptainer run --bind /path/to/workdir:/mnt/{project-name} project.sif ``` -### Code formatting +See the header of `containers/apptainer.def` for the available build arguments. + +## Development + +`GUIDELINES.md` covers the lab-wide toolchain (`uv`, `ruff`, `ty`, `pre-commit`); `AGENTS.md` covers +the coding style and research workflow, and is what coding agents read. Both apply to this project — +document only the deviations here. + +```sh +uv run pytest # run the tests +uvx pre-commit run --all-files # run every hook, as CI does +``` -Among the pre-commit hooks, you will find one that runs -[`ruff`](https://docs.astral.sh/ruff/) on every Python file. It is also warmly -recommended that you set up `ruff` in your IDE (e.g., Visual Studio Code, PyCharm). +`.github/workflows/ci.yml` runs those same two checks on every push. -### Typing +## Contact -We recommend the use of [type hints](https://docs.python.org/3/library/typing.html) -of your code. One of the pre-commit hooks is [`ty`](https://docs.astral.sh/ty/), -which will perform type checking when hints are available. This reduces greatly the -risk of bugs and the maintainability of the code. +{Maintainer name and how to reach them.} diff --git a/containers/apptainer.def b/containers/apptainer.def new file mode 100644 index 0000000..5b890b2 --- /dev/null +++ b/containers/apptainer.def @@ -0,0 +1,58 @@ +# Minimal apptainer definition file for a Python project based on uv. +# +# Build with the defaults below, or override them: +# +# apptainer build project.sif apptainer.def +# apptainer build --build-arg PROJECT_NAME=my-project \ +# --build-arg PYTHON_VERSION=3.13 \ +# project.sif apptainer.def +# +# The project root (the parent of this folder) is copied to /opt/$PROJECT_NAME, +# and /mnt/$PROJECT_NAME is the working directory at runtime (bind your data +# there with `apptainer run --bind /path/to/workdir:/mnt/$PROJECT_NAME ...`). +# +# Running the container with no arguments runs ENTRYPOINT; define what the +# project should do there. Any command passed to `apptainer run` overrides it: +# +# apptainer run project.sif # runs ENTRYPOINT +# apptainer run project.sif python -m python_base.hello + +Bootstrap: docker +From: ghcr.io/astral-sh/uv:python{{ PYTHON_VERSION }}-bookworm-slim + +%arguments + PROJECT_NAME=python-base + PYTHON_VERSION=3.12 + MAINTAINER=unknown + VERSION=0.1 + ENTRYPOINT=containers/entrypoint.sh + +%labels + Maintainer "{{ MAINTAINER }}" + Version "{{ VERSION }}" + +%files + ../ /opt/{{ PROJECT_NAME }} + +%post + echo "**** Installing system dependencies ****" + apt-get update && apt-get install -y git curl && apt-get clean + + echo "**** Installing Python dependencies ****" + cd /opt/{{ PROJECT_NAME }} + uv venv --python {{ PYTHON_VERSION }} + uv sync + + chmod +x /opt/{{ PROJECT_NAME }}/{{ ENTRYPOINT }} + mkdir -p /mnt/{{ PROJECT_NAME }} + +%environment + export VIRTUAL_ENV="/opt/{{ PROJECT_NAME }}/.venv" + export PATH="$VIRTUAL_ENV/bin:$PATH" + +%runscript + cd /mnt/{{ PROJECT_NAME }} + if [ $# -eq 0 ]; then + exec /opt/{{ PROJECT_NAME }}/{{ ENTRYPOINT }} + fi + exec "$@" diff --git a/containers/entrypoint.sh b/containers/entrypoint.sh new file mode 100644 index 0000000..af91fc4 --- /dev/null +++ b/containers/entrypoint.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# Default entrypoint for the container, run when no command is given to +# `apptainer run`. Replace the body with whatever makes sense for this project +# (a training run, a pipeline, a server, ...). +# +# The project venv is already on PATH, and the working directory is the bind +# mount /mnt/, so scripts can be called directly: +# +# python -m python_base.hello +set -euo pipefail + +echo "No entrypoint defined for this project yet." +echo "Edit containers/entrypoint.sh, or pass a command:" +echo " apptainer run project.sif python -m python_base.hello" diff --git a/pyproject.toml b/pyproject.toml index d2ebae9..ca60d16 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,6 +25,10 @@ extend-select = [ [tool.ruff.lint.pydocstyle] convention = "numpy" -# Set ruff as only a local deps for development. +# Dev dependencies. Linters (ruff, ty, pre-commit) are run through uvx and are +# deliberately absent here; pytest must import the project, so it lives in the env. [dependency-groups] -dev = [] +dev = ["pytest>=8"] + +[tool.pytest.ini_options] +testpaths = ["tests"] diff --git a/src/package_name/__init__.py b/src/package_name/__init__.py new file mode 100644 index 0000000..5769c84 --- /dev/null +++ b/src/package_name/__init__.py @@ -0,0 +1 @@ +"""Example package. Rename this folder to your own package name.""" diff --git a/src/python-base/hello.py b/src/package_name/hello.py similarity index 100% rename from src/python-base/hello.py rename to src/package_name/hello.py diff --git a/src/python-base/__init__.py b/src/python-base/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/test_hello.py b/tests/test_hello.py new file mode 100644 index 0000000..aa3bfc0 --- /dev/null +++ b/tests/test_hello.py @@ -0,0 +1,8 @@ +"""Tests for the example module. Replace these with tests for your own code.""" + +from package_name.hello import hello + + +def test_hello_returns_greeting() -> None: + """Check that hello returns the expected greeting.""" + assert hello() == "Hello, World!" diff --git a/uv.lock b/uv.lock index 9db3e19..c5f8267 100644 --- a/uv.lock +++ b/uv.lock @@ -3,191 +3,77 @@ revision = 3 requires-python = ">=3.12" [[package]] -name = "cfgv" -version = "3.4.0" +name = "colorama" +version = "0.4.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/11/74/539e56497d9bd1d484fd863dd69cbbfa653cd2aa27abfe35653494d85e94/cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560", size = 7114, upload-time = "2023-08-12T20:38:17.776Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c5/55/51844dd50c4fc7a33b653bfaba4c2456f06955289ca770a5dbd5fd267374/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", size = 7249, upload-time = "2023-08-12T20:38:16.269Z" }, + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] [[package]] -name = "distlib" -version = "0.3.9" +name = "iniconfig" +version = "2.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0d/dd/1bec4c5ddb504ca60fc29472f3d27e8d4da1257a854e1d96742f15c1d02d/distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403", size = 613923, upload-time = "2024-10-09T18:35:47.551Z" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/91/a1/cf2472db20f7ce4a6be1253a81cfdf85ad9c7885ffbed7047fb72c24cf87/distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87", size = 468973, upload-time = "2024-10-09T18:35:44.272Z" }, + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, ] [[package]] -name = "filelock" -version = "3.18.0" +name = "packaging" +version = "26.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0a/10/c23352565a6544bdc5353e0b15fc1c563352101f30e24bf500207a54df9a/filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2", size = 18075, upload-time = "2025-03-14T07:11:40.47Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de", size = 16215, upload-time = "2025-03-14T07:11:39.145Z" }, + { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" }, ] [[package]] -name = "identify" -version = "2.6.10" +name = "pluggy" +version = "1.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0c/83/b6ea0334e2e7327084a46aaaf71f2146fc061a192d6518c0d020120cd0aa/identify-2.6.10.tar.gz", hash = "sha256:45e92fd704f3da71cc3880036633f48b4b7265fd4de2b57627cb157216eb7eb8", size = 99201, upload-time = "2025-04-19T15:10:38.32Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2b/d3/85feeba1d097b81a44bcffa6a0beab7b4dfffe78e82fc54978d3ac380736/identify-2.6.10-py2.py3-none-any.whl", hash = "sha256:5f34248f54136beed1a7ba6a6b5c4b6cf21ff495aac7c359e1ef831ae3b8ab25", size = 99101, upload-time = "2025-04-19T15:10:36.701Z" }, + { 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 = "nodeenv" -version = "1.9.1" +name = "pygments" +version = "2.20.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437, upload-time = "2024-06-04T18:44:11.171Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, ] [[package]] -name = "platformdirs" -version = "4.3.8" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/8b/3c73abc9c759ecd3f1f7ceff6685840859e8070c4d947c93fae71f6a0bf2/platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc", size = 21362, upload-time = "2025-05-07T22:47:42.121Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/39/979e8e21520d4e47a0bbe349e2713c0aac6f3d853d0e5b34d76206c439aa/platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4", size = 18567, upload-time = "2025-05-07T22:47:40.376Z" }, -] - -[[package]] -name = "pre-commit" -version = "4.2.0" +name = "pytest" +version = "9.1.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "cfgv" }, - { name = "identify" }, - { name = "nodeenv" }, - { name = "pyyaml" }, - { name = "virtualenv" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/08/39/679ca9b26c7bb2999ff122d50faa301e49af82ca9c066ec061cfbc0c6784/pre_commit-4.2.0.tar.gz", hash = "sha256:601283b9757afd87d40c4c4a9b2b5de9637a8ea02eaff7adc2d0fb4e04841146", size = 193424, upload-time = "2025-03-18T21:35:20.987Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313", size = 1636369, upload-time = "2026-06-19T10:58:32.857Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/74/a88bf1b1efeae488a0c0b7bdf71429c313722d1fc0f377537fbe554e6180/pre_commit-4.2.0-py2.py3-none-any.whl", hash = "sha256:a009ca7205f1eb497d10b845e52c838a98b6cdd2102a6c8e4540e94ee75c58bd", size = 220707, upload-time = "2025-03-18T21:35:19.343Z" }, + { url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c", size = 386536, upload-time = "2026-06-19T10:58:31.347Z" }, ] [[package]] name = "python-base" version = "0.1.0" source = { editable = "." } -dependencies = [ - { name = "pre-commit" }, - { name = "ruff" }, - { name = "ty" }, -] [package.dev-dependencies] dev = [ - { name = "pre-commit" }, - { name = "ruff" }, - { name = "ty" }, + { name = "pytest" }, ] [package.metadata] -requires-dist = [ - { name = "pre-commit", specifier = ">=4.2.0" }, - { name = "ruff", specifier = ">=0.11.10" }, - { name = "ty", specifier = ">=0.0.0" }, -] [package.metadata.requires-dev] -dev = [ - { name = "pre-commit", specifier = ">=4.2.0" }, - { name = "ruff", specifier = ">=0.11.10" }, - { name = "ty", specifier = ">=0.0.0" }, -] - -[[package]] -name = "pyyaml" -version = "6.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" }, - { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" }, - { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" }, - { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" }, - { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" }, - { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" }, - { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" }, - { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, - { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, - { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, - { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, - { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, - { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, - { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, - { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, - { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, - { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, -] - -[[package]] -name = "ruff" -version = "0.11.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e8/4c/4a3c5a97faaae6b428b336dcca81d03ad04779f8072c267ad2bd860126bf/ruff-0.11.10.tar.gz", hash = "sha256:d522fb204b4959909ecac47da02830daec102eeb100fb50ea9554818d47a5fa6", size = 4165632, upload-time = "2025-05-15T14:08:56.76Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2f/9f/596c628f8824a2ce4cd12b0f0b4c0629a62dfffc5d0f742c19a1d71be108/ruff-0.11.10-py3-none-linux_armv6l.whl", hash = "sha256:859a7bfa7bc8888abbea31ef8a2b411714e6a80f0d173c2a82f9041ed6b50f58", size = 10316243, upload-time = "2025-05-15T14:08:12.884Z" }, - { url = "https://files.pythonhosted.org/packages/3c/38/c1e0b77ab58b426f8c332c1d1d3432d9fc9a9ea622806e208220cb133c9e/ruff-0.11.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:968220a57e09ea5e4fd48ed1c646419961a0570727c7e069842edd018ee8afed", size = 11083636, upload-time = "2025-05-15T14:08:16.551Z" }, - { url = "https://files.pythonhosted.org/packages/23/41/b75e15961d6047d7fe1b13886e56e8413be8467a4e1be0a07f3b303cd65a/ruff-0.11.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:1067245bad978e7aa7b22f67113ecc6eb241dca0d9b696144256c3a879663bca", size = 10441624, upload-time = "2025-05-15T14:08:19.032Z" }, - { url = "https://files.pythonhosted.org/packages/b6/2c/e396b6703f131406db1811ea3d746f29d91b41bbd43ad572fea30da1435d/ruff-0.11.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4854fd09c7aed5b1590e996a81aeff0c9ff51378b084eb5a0b9cd9518e6cff2", size = 10624358, upload-time = "2025-05-15T14:08:21.542Z" }, - { url = "https://files.pythonhosted.org/packages/bd/8c/ee6cca8bdaf0f9a3704796022851a33cd37d1340bceaf4f6e991eb164e2e/ruff-0.11.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8b4564e9f99168c0f9195a0fd5fa5928004b33b377137f978055e40008a082c5", size = 10176850, upload-time = "2025-05-15T14:08:23.682Z" }, - { url = "https://files.pythonhosted.org/packages/e9/ce/4e27e131a434321b3b7c66512c3ee7505b446eb1c8a80777c023f7e876e6/ruff-0.11.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b6a9cc5b62c03cc1fea0044ed8576379dbaf751d5503d718c973d5418483641", size = 11759787, upload-time = "2025-05-15T14:08:25.733Z" }, - { url = "https://files.pythonhosted.org/packages/58/de/1e2e77fc72adc7cf5b5123fd04a59ed329651d3eab9825674a9e640b100b/ruff-0.11.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:607ecbb6f03e44c9e0a93aedacb17b4eb4f3563d00e8b474298a201622677947", size = 12430479, upload-time = "2025-05-15T14:08:28.013Z" }, - { url = "https://files.pythonhosted.org/packages/07/ed/af0f2340f33b70d50121628ef175523cc4c37619e98d98748c85764c8d88/ruff-0.11.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7b3a522fa389402cd2137df9ddefe848f727250535c70dafa840badffb56b7a4", size = 11919760, upload-time = "2025-05-15T14:08:30.956Z" }, - { url = "https://files.pythonhosted.org/packages/24/09/d7b3d3226d535cb89234390f418d10e00a157b6c4a06dfbe723e9322cb7d/ruff-0.11.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2f071b0deed7e9245d5820dac235cbdd4ef99d7b12ff04c330a241ad3534319f", size = 14041747, upload-time = "2025-05-15T14:08:33.297Z" }, - { url = "https://files.pythonhosted.org/packages/62/b3/a63b4e91850e3f47f78795e6630ee9266cb6963de8f0191600289c2bb8f4/ruff-0.11.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a60e3a0a617eafba1f2e4186d827759d65348fa53708ca547e384db28406a0b", size = 11550657, upload-time = "2025-05-15T14:08:35.639Z" }, - { url = "https://files.pythonhosted.org/packages/46/63/a4f95c241d79402ccdbdb1d823d156c89fbb36ebfc4289dce092e6c0aa8f/ruff-0.11.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:da8ec977eaa4b7bf75470fb575bea2cb41a0e07c7ea9d5a0a97d13dbca697bf2", size = 10489671, upload-time = "2025-05-15T14:08:38.437Z" }, - { url = "https://files.pythonhosted.org/packages/6a/9b/c2238bfebf1e473495659c523d50b1685258b6345d5ab0b418ca3f010cd7/ruff-0.11.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ddf8967e08227d1bd95cc0851ef80d2ad9c7c0c5aab1eba31db49cf0a7b99523", size = 10160135, upload-time = "2025-05-15T14:08:41.247Z" }, - { url = "https://files.pythonhosted.org/packages/ba/ef/ba7251dd15206688dbfba7d413c0312e94df3b31b08f5d695580b755a899/ruff-0.11.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5a94acf798a82db188f6f36575d80609072b032105d114b0f98661e1679c9125", size = 11170179, upload-time = "2025-05-15T14:08:43.762Z" }, - { url = "https://files.pythonhosted.org/packages/73/9f/5c336717293203ba275dbfa2ea16e49b29a9fd9a0ea8b6febfc17e133577/ruff-0.11.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:3afead355f1d16d95630df28d4ba17fb2cb9c8dfac8d21ced14984121f639bad", size = 11626021, upload-time = "2025-05-15T14:08:46.451Z" }, - { url = "https://files.pythonhosted.org/packages/d9/2b/162fa86d2639076667c9aa59196c020dc6d7023ac8f342416c2f5ec4bda0/ruff-0.11.10-py3-none-win32.whl", hash = "sha256:dc061a98d32a97211af7e7f3fa1d4ca2fcf919fb96c28f39551f35fc55bdbc19", size = 10494958, upload-time = "2025-05-15T14:08:49.601Z" }, - { url = "https://files.pythonhosted.org/packages/24/f3/66643d8f32f50a4b0d09a4832b7d919145ee2b944d43e604fbd7c144d175/ruff-0.11.10-py3-none-win_amd64.whl", hash = "sha256:5cc725fbb4d25b0f185cb42df07ab6b76c4489b4bfb740a175f3a59c70e8a224", size = 11650285, upload-time = "2025-05-15T14:08:52.392Z" }, - { url = "https://files.pythonhosted.org/packages/95/3a/2e8704d19f376c799748ff9cb041225c1d59f3e7711bc5596c8cfdc24925/ruff-0.11.10-py3-none-win_arm64.whl", hash = "sha256:ef69637b35fb8b210743926778d0e45e1bffa850a7c61e428c6b971549b5f5d1", size = 10765278, upload-time = "2025-05-15T14:08:54.56Z" }, -] - -[[package]] -name = "ty" -version = "0.0.19" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/84/5e/da108b9eeb392e02ff0478a34e9651490b36af295881cb56575b83f0cc3a/ty-0.0.19.tar.gz", hash = "sha256:ee3d9ed4cb586e77f6efe3d0fe5a855673ca438a3d533a27598e1d3502a2948a", size = 5220026, upload-time = "2026-02-26T12:13:15.215Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5a/31/fd8c6067abb275bea11523d21ecf64e1d870b1ce80cac529cf6636df1471/ty-0.0.19-py3-none-linux_armv6l.whl", hash = "sha256:29bed05d34c8a7597567b8e327c53c1aed4a07dcfbe6c81e6d60c7444936ad77", size = 10268470, upload-time = "2026-02-26T12:13:42.881Z" }, - { url = "https://files.pythonhosted.org/packages/15/de/16a11bbf7d98c75849fc41f5d008b89bb5d080a4b10dc8ea851ee2bd371b/ty-0.0.19-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:79140870c688c97ec68e723c28935ddef9d91a76d48c68e665fe7c851e628b8a", size = 10098562, upload-time = "2026-02-26T12:13:31.618Z" }, - { url = "https://files.pythonhosted.org/packages/e7/4f/086d6ff6686eadf903913c45b53ab96694b62bbfee1d8cf3e55a9b5aa4b2/ty-0.0.19-py3-none-macosx_11_0_arm64.whl", hash = "sha256:6e9c1f9cfa6a26f7881d14d75cf963af743f6c4189e6aa3e3b4056a65f22e730", size = 9604073, upload-time = "2026-02-26T12:13:24.645Z" }, - { url = "https://files.pythonhosted.org/packages/95/13/888a6b6c7ed4a880fee91bec997f775153ce86215ee4c56b868516314734/ty-0.0.19-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbca43b050edf1db2e64ae7b79add233c2aea2855b8a876081bbd032edcd0610", size = 10106295, upload-time = "2026-02-26T12:13:40.584Z" }, - { url = "https://files.pythonhosted.org/packages/cb/e8/05a372cae8da482de73b8246fb43236bf11e24ac28c879804568108759db/ty-0.0.19-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8acaa88ab1955ca6b15a0ccc274011c4961377fe65c3948e5d2b212f2517b87c", size = 10098234, upload-time = "2026-02-26T12:13:33.725Z" }, - { url = "https://files.pythonhosted.org/packages/c5/f1/5b0958e9e9576e7662192fe689bbb3dc88e631a4e073db3047793a547d58/ty-0.0.19-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a901b6a6dd9d17d5b3b2e7bafc3057294e88da3f5de507347316687d7f191a1", size = 10607218, upload-time = "2026-02-26T12:13:17.576Z" }, - { url = "https://files.pythonhosted.org/packages/fb/ab/358c78b77844f58ff5aca368550ab16c719f1ab0ec892ceb1114d7500f4e/ty-0.0.19-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8deafdaaaee65fd121c66064da74a922d8501be4a2d50049c71eab521a23eff7", size = 11160593, upload-time = "2026-02-26T12:13:36.008Z" }, - { url = "https://files.pythonhosted.org/packages/95/59/827fc346d66a59fe48e9689a5ceb67dbbd5b4de2e8d4625371af39a2e8b7/ty-0.0.19-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:035e56071af280897441018f74f921b97d53aec0856f8af85f4f949df8eda07d", size = 10822392, upload-time = "2026-02-26T12:13:29.415Z" }, - { url = "https://files.pythonhosted.org/packages/81/f9/3bbfbbe35478de9bcd63848f4bc9bffda72278dd9732dbad3efc3978432e/ty-0.0.19-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abdf5885130393ce74501dba792f48ce0a515756ec81c33a4b324bdf3509df6e", size = 10707139, upload-time = "2026-02-26T12:13:20.148Z" }, - { url = "https://files.pythonhosted.org/packages/12/9e/597023b183ec4ade83a36a0cea5c103f3bffa34f70813d46386c61447fb8/ty-0.0.19-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:877e89005c8f9d1dbff5ad14cbac9f35c528406fde38926f9b44f24830de8d6a", size = 10096933, upload-time = "2026-02-26T12:13:45.266Z" }, - { url = "https://files.pythonhosted.org/packages/1e/76/d0d2f6e674db2a17c8efa5e26682b9dfa8d34774705f35902a7b45ebd3bd/ty-0.0.19-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:39bd1da051c1e4d316efaf79dbed313255633f7c6ad6e24d29f4d9c6ffaf4de6", size = 10109547, upload-time = "2026-02-26T12:13:22.17Z" }, - { url = "https://files.pythonhosted.org/packages/a4/b0/76026c06b852a3aa4fdb5bd329fdc2175aaf3c64a3fafece9cc4df167cee/ty-0.0.19-py3-none-musllinux_1_2_i686.whl", hash = "sha256:87df8415a6c9cb27b8f1382fcdc6052e59f5b9f50f78bc14663197eb5c8d3699", size = 10289110, upload-time = "2026-02-26T12:13:38.29Z" }, - { url = "https://files.pythonhosted.org/packages/14/6c/f3b3a189816b4f079b20fe5d0d7ee38e38a472f53cc6770bb6571147e3de/ty-0.0.19-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:89b6bb23c332ed5c38dd859eb5793f887abcc936f681a40d4ea68e35eac1af33", size = 10796479, upload-time = "2026-02-26T12:13:10.992Z" }, - { url = "https://files.pythonhosted.org/packages/3d/18/caee33d1ce9dd50bd94c26cde7cda4f6971e22e474e7d72a5c86d745ad58/ty-0.0.19-py3-none-win32.whl", hash = "sha256:19b33df3aa7af7b1a9eaa4e1175c3b4dec0f5f2e140243e3492c8355c37418f3", size = 9677215, upload-time = "2026-02-26T12:13:08.519Z" }, - { url = "https://files.pythonhosted.org/packages/81/41/18fc0771d0b1da7d7cc2fc9af278d3122b754fe8b521a748734f4e16ecfd/ty-0.0.19-py3-none-win_amd64.whl", hash = "sha256:b9052c61464cdd76bc8e6796f2588c08700f25d0dcbc225bb165e390ea9d96a4", size = 10651252, upload-time = "2026-02-26T12:13:13.035Z" }, - { url = "https://files.pythonhosted.org/packages/8b/8c/26f7ce8863eb54510082747b3dfb1046ba24f16fc11de18c0e5feb36ff18/ty-0.0.19-py3-none-win_arm64.whl", hash = "sha256:9329804b66dcbae8e7af916ef4963221ed53b8ec7d09b0793591c5ae8a0f3270", size = 10093195, upload-time = "2026-02-26T12:13:26.816Z" }, -] - -[[package]] -name = "virtualenv" -version = "20.31.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "distlib" }, - { name = "filelock" }, - { name = "platformdirs" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/56/2c/444f465fb2c65f40c3a104fd0c495184c4f2336d65baf398e3c75d72ea94/virtualenv-20.31.2.tar.gz", hash = "sha256:e10c0a9d02835e592521be48b332b6caee6887f332c111aa79a09b9e79efc2af", size = 6076316, upload-time = "2025-05-08T17:58:23.811Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f3/40/b1c265d4b2b62b58576588510fc4d1fe60a86319c8de99fd8e9fec617d2c/virtualenv-20.31.2-py3-none-any.whl", hash = "sha256:36efd0d9650ee985f0cad72065001e66d49a6f24eb44d98980f630686243cf11", size = 6057982, upload-time = "2025-05-08T17:58:21.15Z" }, -] +dev = [{ name = "pytest", specifier = ">=8" }]