diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 199a819..1368b3a 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -1,5 +1,5 @@ -# This workflow will install Python dependencies, run tests and lint with a variety of Python versions -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python +# This workflow installs Python dependencies, runs tests, and lints across Python versions. +# For details see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python name: Python package @@ -11,30 +11,59 @@ on: jobs: build: - runs-on: ubuntu-latest strategy: fail-fast: false matrix: - python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] + python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] + env: + UV_PYTHON: ${{ matrix.python-version }} steps: - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - python -m pip install flake8 pytest - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - - name: Lint with flake8 + + - name: Set up uv + uses: astral-sh/setup-uv@v6 + with: + version: "0.13.7" + enable-cache: true + + - name: Sync dependencies + run: uv sync --locked --extra dev --python ${{ matrix.python-version }} + + - name: Lint with ruff run: | - # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics - # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + uv run --locked --extra dev ruff check . + - name: Test with pytest run: | - pytest + uv run --locked --extra dev pytest + + - name: Smoke test installed wheel + run: | + smoke_dir="$(mktemp -d "$RUNNER_TEMP/verbecc-wheel.XXXXXX")" + uv build --wheel --out-dir "$smoke_dir/dist" + uv venv --python "${{ matrix.python-version }}" "$smoke_dir/venv" + uv pip install --python "$smoke_dir/venv/bin/python" "$smoke_dir"/dist/*.whl + cd "$smoke_dir" + "$smoke_dir/venv/bin/python" -I - <<'PY' + from verbecc import CompleteConjugator + from verbecc.core.defs.types.lang_code import LangCodeISO639_1 as Lang + + for lang, infinitive in [ + (Lang.ca, "parlar"), + (Lang.fr, "parler"), + (Lang.it, "parlare"), + (Lang.pt, "falar"), + (Lang.ro, "vorbi"), + (Lang.es, "hablar"), + ]: + conjugation = CompleteConjugator(lang=lang).conjugate(infinitive) + assert conjugation, f"No conjugation for {lang}: {infinitive}" + print(f"Installed wheel smoke test passed: {lang} {infinitive}") + PY \ No newline at end of file diff --git a/.gitignore b/.gitignore index ccb3a8a..6c3ff17 100755 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,13 @@ .eggs *.egg-info .tox/ +.venv/ __pycache__ dist build .coverage coverage.xml .vscode -verbecc/data/models/*.zip +src/verbecc/data/models/*.zip *.log *.log.* \ No newline at end of file diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..6324d40 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.14 diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e0121d..9a8940d 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,79 @@ # verbecc Changelog +- 2.1.0 [7 November 2026] + - In a nutshell + - This PR (2.1.0) modernizes the project layout and drops Python 3.9 support. The biggest user-facing changes are a move to a standard src/ layout and a package rename/restructure (verbecc.src → verbecc.core). Development and CI now use uv with locked dependencies. Several __init__.py files were simplified, which may break some import paths, but `from verbecc import CompleteConjugator` remains supported. Fixed missing wheel data and added installed-wheel smoke tests. + - Summary (key data points) + - PR: 2.1.0 — "Misc. modernization" (author: bretttolbert) + - URL: https://github.com/bretttolbert/verbecc/pull/54 + - State: open (draft) + - Description highlights: + - Dropping support for Python 3.9 + - Restructured repository to standard src layout (verbecc/src/verbecc) + - Renamed package/namespace from verbecc.src to verbecc.core + - Simplified multiple __init__.py files (potential import breakages) + - Transitioned development and CI to uv with `uv.lock` + - Fixed wheel resource packaging and preserved the public `CompleteConjugator` import + - Added clean-environment wheel smoke tests for all six supported languages + - CHANGELOG link included in PR description + - Size: 252 files changed, +2,214 additions, −2,006 deletions (large refactor) + - Risk assessment: Medium–High + - Why: Large movement of files + package renames and __init__ simplifications are likely to break downstream imports, packaging, and third-party integrations. Dropping Python 3.9 reduces the test surface but may require CI and packaging updates. + - Validation: 36 targeted public API, conjugator, and import-style tests passed. The installed-wheel smoke test passed locally on Python 3.14 for all six languages; CI runs it across Python 3.10–3.14. Coverage and full matrix results are not reported here. + - Breaking-change likelihood: High for consumers who imported using old package paths or relied on package layout; moderate for internal code once imports are updated. + - Details + - Fixed packaging, misc. modernization + - **Dropping support for python3.9** (it has been EOL for nearly a year) + - Migrated from `importlib_resources`to `importlib.resources` + - Eliminates python39 import resource hacks + - Eliminates backports (e.g., `importlib_resources` for Python <3.13). Dependencies simplified and updated accordingly. + - Changed structure from `verbecc/verbecc/src` to more standard `verbecc/src/verbecc` + - Before data was at `verbecc/verbecc/data` + - After data is at `verbecc/src/verbecc/data` + - Source is now at `verbecc/src/verbecc/core` + - `verbecc.src` is now `verbecc.core` + - Modified `pyproject.toml` to scan for packages inside `src` + - Fixed wheels missing YAML configuration, XML conjugation/verb data, trained models, and `py.typed` + - Replaced the non-package `trained_models` package-data key with patterns relative to the `verbecc` package + - Preserved existing icon and font resources + - Removed `verbecc/__init__.py` which should not exist because this project is using a `src` layout + - Modified (simplified) contents of a many `__init__.py` files + - Restored `from verbecc import CompleteConjugator` through one-level re-exports via `core` and `core.conjugator`, preserving R005/R006 compliance + - Added public API regression tests for re-export identity and conjugation + - **This will likely break some things**, consequently bumping minor rev + - Doing this to comply with new style guide rule: + - [R006 - `__init__.py` files shall not contain imports deeper than one level](./CONTRIBUTING.md#r006---__init__py-files-shall-not-contain-imports-deeper-than-one-level) + - Changed `setup.cfg` `description-file` to `description_file` to fix warning + - Added numerous missing type annotations + - Fixed all VSCode warnings with strict type checking enabled + - Added `str` as optional type for public API methods, e.g. so that either specific types like `Mood` or generic strings are explicitly allowed e.g. + - Before: `mood: Mood` + - After: `mood: Mood | str` + - Contd. cleaning up (removing) excessive `__init__.py` imports + - Modernized Python syntax + - Systematic updates across the codebase + - Converted from `List` to modern `list` + - Converted from `Dict` to modern `dict` + - Modified build configuration to generate type stubs + - Transitioned development and GitHub Actions CI to uv + - Added `uv.lock` for reproducible development dependency resolution + - Use `uv sync --locked --extra dev` to set up the project-root `.venv` + - Run linting and tests with `uv run --locked --extra dev ruff check .` and `uv run --locked --extra dev pytest` + - Run `uv lock` after changing dependencies and commit the updated lockfile + - Updated the [development environment instructions](./CONTRIBUTING.md#development-environment) + - Modernized GitHub Actions CI config (`.github/workflows/python-package.yml`) + - Test Python 3.10–3.14 with uv-managed environments + - Build the wheel, install it and its runtime dependencies into a fresh virtual environment, and conjugate one verb per supported language + - Run the wheel smoke test outside the checkout with `python -I` so editable installs and source-tree imports cannot hide missing package data or broken public imports + - Migrated linter from `flake8` to `ruff` + - Updated dependencies to explicitly specify `pytest` and `ruff` as optional `dev` dependencies + - E.g. install verbecc including optional dev deps: + - From PyPi: `pip install "verbecc[dev]"` + - From GitHub: `pip install "git+https://github.com/bretttolbert/verbecc.git[dev]"` + - Local development: `uv sync --locked --extra dev` + - Updated dependencies to explicitly pull optional `yaml` deps for `dataclass-wizard` + - I.e. `"dataclass-wizard[yaml]>=0.39.1",` + - 2.0.3 [26 August 2026] - PR #51 [Peter Abolins] - Fixes [#49](https://github.com/bretttolbert/verbecc/issues/49) [ro] Four damaged templates in conjugations-ro.xml produce non-words: contraf:ace, a:vea, :vrea, dezmi:nţi diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..6c0969a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,71 @@ +# Contributing to verbecc + +First off, thank you for taking the time to contribute! 🎉 + +--- + +## Table of Contents + +- [Development environment](#development-environment) +- [Style Guide](#style-guide) + +## Development environment + +Install [uv](https://docs.astral.sh/uv/getting-started/installation/), then run +these commands from the repository root: + +```bash +uv sync --locked --extra dev +uv run --locked --extra dev ruff check . +uv run --locked --extra dev pytest +``` + +Use the project-root `.venv` as your editor's Python interpreter. Dependencies +are managed in `pyproject.toml` and `uv.lock`; run `uv lock` after changing +dependencies and commit the updated lockfile. + +CI also builds a wheel and installs it with its runtime dependencies into a +fresh virtual environment for each supported Python version. The smoke test +runs outside the checkout in Python isolated mode, imports the public +`CompleteConjugator` entry point, and conjugates one verb in each of the six +supported languages to catch missing package data and broken public imports. + +## Style Guide + +### R001 - The Python `@property` decorator shall not be used + +This is primarily because I intend to port verbecc to Java and other languages and I wish to keep the implementations as consistent as possible, preferably a _1:1_ equivalence in all symbol names, _mutata mutandis_. + +### R002 - There shall not be more than one class definition per file + +This simplifies porting to Java, allowing _1:1_ source file correspondence. This rule is enforced by the `test_ast` unit-tests. + +### R003 - Type annotations are required for all parameters and return statements + +This rule is enforced by the `test_ast` unit-tests. + +### R004 - Don't use parentheses in import statements + +Without parentheses, I can easily sort the import statements (_Ctrl+P Sort Lines Ascending_), +but with parentheses, I can't do that. + +### R005 - `__init__.py` files shall only use relative imports + +- Allowed: `from .module import SomeClass` +- Not allowed: `from verbecc.core.foo import bar` + +How to check: +```bash +uv run --locked --extra dev pytest -k test_STYLE_GUIDE_R005_only_relative_imports +``` + +### R006 - `__init__.py` files shall not contain imports deeper than one level + +- Allowed: `from .module import SomeClass` +- Not Allowed: `from .module.submodule import SomeClass` + +Why: +- Pollutes the namespace +- Hides where things come from +- Slows down import time by unnecessarily loading unused modules +- Causes circular imports diff --git a/README.md b/README.md index c14e925..32fc59a 100755 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ + + # Python library for verb conjugation in French, Spanish, Catalan, Italian, Portuguese, and Romanian, enhanced by machine learning - `verbecc` python library @@ -56,25 +58,97 @@ * Meticulously organized source tree * Has a plethora of unit-tests to ensure correctness of verb conjugations * Continuous Integration with GitHub Actions CI/CD pipeline - * CI tests python 3.9, 3.10, 3.11, 3.12, 3.13 and 3.14. + * CI tests python 3.10, 3.11, 3.12, 3.13 and 3.14. * Dependencies: `scikit-learn`, `scipy`, `numpy`, `lxml`, `pyaml`, `jsbeautifier`, `importlib_resources` * **Trusted** * Cited in [academic publications](#academic-publications-referencing-verbecc) +## Installation + +Verbecc development and CI have transitioned to +[uv](https://docs.astral.sh/uv/), using `uv.lock` for reproducible development +environments. uv is optional for library users: Verbecc remains a standard +Python package that you can install with pip. + +Install [uv](https://docs.astral.sh/uv/getting-started/installation/) to follow +the examples below. + +### Compatibility with pip + +uv's pip-compatible interface lets you replace common `pip ...` commands with +`uv pip ...` commands while continuing to use standard Python packages and +virtual environments: -## Quick Start +| pip | uv equivalent | +| --- | --- | +| `pip install verbecc` | `uv pip install verbecc` | +| `pip install --upgrade verbecc` | `uv pip install --upgrade verbecc` | +| `pip install -e ".[dev]"` | `uv pip install -e ".[dev]"` | +| `pip install -r requirements.txt` | `uv pip install -r requirements.txt` | +| `pip uninstall verbecc` | `uv pip uninstall verbecc` | +| `pip list` | `uv pip list` | + +By default, `uv pip` installs into an active virtual environment or a discovered +`.venv`; create one with `uv venv` first. To target a specific interpreter, use +`uv pip install --python /path/to/venv/bin/python verbecc`. If you prefer pip, +use `python -m venv .venv`, activate it, and run `python -m pip install verbecc`. + +This compatibility covers common workflows, not every pip option or behavior. +uv uses its own configuration and environment variables rather than +`pip.conf` or `PIP_*` settings; see the +[uv/pip compatibility guide](https://docs.astral.sh/uv/pip/compatibility/). +For development in this repository, prefer `uv sync --locked --extra dev` +over `uv pip install -e ".[dev]"` so the committed lockfile is respected. + +### (User) Install from PyPi ```bash -git clone https://github.com/bretttolbert/verbecc.git -cd verbecc -pip install . +uv venv +uv pip install "verbecc" ``` -### Academic publications referencing verbecc +### (User) Install from GitHub repo +```bash +uv venv +uv pip install "git+https://github.com/bretttolbert/verbecc.git" +``` + +### (Developer) Clone GitHub repo and install +```bash +git clone git@github.com/bretttolbert/verbecc.git && cd verbecc +uv sync --locked --extra dev +``` + +This creates `.venv` in the project root and installs the project in editable +mode with its development dependencies. The default development Python version +is recorded in `.python-version`; Python 3.10 through 3.14 remain supported. +To use another supported version, pass `--python`, for example +`uv sync --locked --extra dev --python 3.10`. + +Run commands in this environment without activating it: +```bash +uv run --locked --extra dev pytest +uv run --locked --extra dev ruff check . +``` + +In VS Code, select `.venv/bin/python` (or `.venv\Scripts\python.exe` on +Windows) using **Python: Select Interpreter**. For an interactive shell, +activate the environment with `source .venv/bin/activate` on POSIX or +`.venv\Scripts\Activate.ps1` in PowerShell. + +Dependencies are declared in `pyproject.toml` and pinned in the committed +`uv.lock`, which replaces `requirements.txt`. After changing dependency +declarations, run `uv lock` and `uv sync --locked --extra dev`, and commit +both the manifest and lockfile. + +### Optional dependency extras +- `[dev]` - development dependencies (includes `pytest` and `ruff`) + +## Academic publications referencing verbecc - [Segura Lores, Alba. (2025) Estudio de la variación del sujeto pronominal en la ciudad de Málaga: sociolingüística cognitiva de su producción y percepción. Universität Heidelberg. pp. 69. [DOI:10.11588/heidok.00037508]](https://nbn-resolving.org/urn:nbn:de:bsz:16-heidok-375088) -### What's new in Verbecc 2.0 +## What's new in Verbecc 2.0 | verbecc 1.x | verbecc 2.x | | --- | --- | @@ -92,8 +166,8 @@ pip install . | Array index is used to determine `Person`, i.e. `1s, 2s, 3s, 1p, 2p, 3p` | Each `Conjugation` object in the `TenseConjugation` has `Person`, `Number` and `Gender` values (any of which may be `None` if not-applicable) | | Returned objects are primitive (`Dict`) data types | Returned wrapper objects are subclasses of `AbstractConjugation` (e.g. `CompleteConjugation`) with `get_data()` and `to_json()` methods | | `Conjugator` returns `CompleteConjugationData` | `CompleteConjugator` returns wrapper type `CompleteConjugation`, `CompleteConjugation.get_data()` returns `CompleteConjugationData` | -| (no wrapper types) | Wrapper types hierarchy: `CompleteConjugation` > `MoodsConjugation` > `MoodConjugation` > `TenseConjugation` > `Conjugation` -> `conjugations: List[str]` | -| Primitive data types hierarchy: `Conjugation` > `MoodsConjugation` > `MoodConjugation` > `TenseConjugation` > `PersonConjugation` | Primitive data types hierarchy: `CompleteConjugationData` > `MoodsConjugationData` > `MoodConjugationData` > `TenseConjugationData` > `ConjugationData` -> `conjugations: List[str]` | +| (no wrapper types) | Wrapper types hierarchy: `CompleteConjugation` > `MoodsConjugation` > `MoodConjugation` > `TenseConjugation` > `Conjugation` -> `conjugations: list[str]` | +| Primitive data types hierarchy: `Conjugation` > `MoodsConjugation` > `MoodConjugation` > `TenseConjugation` > `PersonConjugation` | Primitive data types hierarchy: `CompleteConjugationData` > `MoodsConjugationData` > `MoodConjugationData` > `TenseConjugationData` > `ConjugationData` -> `conjugations: list[str]` | | `pred_score` was always included in the output | `pred_score` is only included in output if `predicted` is `true` | | Only returned primitive Python data | `Conjugation` objects have both `.to_json()` and `.to_yaml()` methods | | diff --git a/STYLE_GUIDE.md b/STYLE_GUIDE.md deleted file mode 100644 index a503cc0..0000000 --- a/STYLE_GUIDE.md +++ /dev/null @@ -1,58 +0,0 @@ -# verbecc Style Guide - -## The Python `@property` decorator shall not be used - -This is primarily because I intend to port verbecc to Java and other languages and I wish to keep the implementations as consistent as possible, preferably a _1:1_ equivalence in all symbol names, _mutata mutandis_. - -## There shall not be more than class definition per file - -This simplifies porting to Java, allowing _1:1_ source file correspondence. This rule is enforced by the `test_ast` unit-tests. - -## Type annotations are required for all parameters and return statements - -This rule is enforced by the `test_ast` unit-tests. - -## Don't use parentheses in import statements - -Without parentheses, I can easily sort the import statements (_Ctrl+P Sort Lines Ascending_), -but with parentheses, I can't do that. - -Do this: -```python -from verbecc.src.conjugator.conjugation_object import ConjugationObjects -from verbecc.src.defs.types.data.person_ending import PersonEnding -from verbecc.src.defs.types.data.tense_template import TenseTemplate -from verbecc.src.defs.types.gender import Gender -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 -from verbecc.src.defs.types.lang_specific_options import LangSpecificOptions -from verbecc.src.defs.types.lang_specific_options import LangSpecificOptionsEs -from verbecc.src.defs.types.lang_specific_options import LangSpecificOptionsFactory -from verbecc.src.defs.types.lang_specific_options import VoseoOptions -from verbecc.src.defs.types.mood import Mood, Moods -from verbecc.src.defs.types.number import Number -from verbecc.src.defs.types.person import Person -from verbecc.src.defs.types.tense import Tense, Tenses -from verbecc.src.inflectors.inflector import Inflector -from verbecc.src.utils.string_utils import strip_accents -``` - -Don't do this: -```python -from verbecc.src.conjugator.conjugation_object import ConjugationObjects -from verbecc.src.defs.types.data.person_ending import PersonEnding -from verbecc.src.defs.types.data.tense_template import TenseTemplate -from verbecc.src.defs.types.gender import Gender -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 -from verbecc.src.defs.types.lang_specific_options import ( - LangSpecificOptions, - LangSpecificOptionsEs, - LangSpecificOptionsFactory, - VoseoOptions, -) -from verbecc.src.defs.types.mood import Mood, Moods -from verbecc.src.defs.types.number import Number -from verbecc.src.defs.types.person import Person -from verbecc.src.defs.types.tense import Tense, Tenses -from verbecc.src.inflectors.inflector import Inflector -from verbecc.src.utils.string_utils import strip_accents -``` \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 9e579a0..ff4d9d3 100755 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,26 +4,8 @@ build-backend = "setuptools.build_meta" [project] name = "verbecc" -version = "2.0.3" -dependencies = [ - "backports.strenum (>=1.3.1,<2.0) ; python_version < '3.11'", - "cython>=3.1.4", - "dataclass-wizard==0.35.1", - "importlib_resources==6.4.5 ; python_version < '3.13'", - "importlib_resources==6.5.2 ; python_version >= '3.13'", - "jsbeautifier>=1.15.4,<2.0", - "lxml-stubs>=0.5.1", - "lxml>=6.0.2", - "numpy==1.26.2 ; python_version < '3.11'", - "numpy==2.3.3 ; python_version >= '3.11'", - "pyaml==25.7.0", - "scikit-learn==1.6.1 ; python_version < '3.10'", - "scikit-learn==1.7.2 ; python_version >= '3.10'", - "scipy==1.13.1 ; python_version < '3.10'", - "scipy==1.15.3 ; python_version == '3.10'", - "scipy==1.16.2 ; python_version >= '3.11'", -] -requires-python = ">=3.9" +version = "2.1.0" +requires-python = ">=3.10" authors = [{ name = "Brett Tolbert", email = "bretttolbert@gmail.com" }] maintainers = [{ name = "Brett Tolbert", email = "bretttolbert@gmail.com" }] description = "Verbs Completely Conjugated: machine learning conjugator for Catalan, French, Italian, Portuguese, Romanian and Spanish" @@ -71,7 +53,6 @@ classifiers = [ 'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: 3.13', 'Programming Language :: Python :: 3.14', - 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3', 'Topic :: Education', 'Topic :: Scientific/Engineering :: Artificial Intelligence', @@ -80,6 +61,29 @@ classifiers = [ 'Topic :: Utilities', ] +dependencies = [ + "backports.strenum>=1.3.1,<2.0 ; python_version < '3.11'", + "cython>=3.0.11", + "dataclass-wizard[yaml]>=0.39.1", + "importlib_resources>=6.4.5 ; python_version < '3.13'", + "jsbeautifier>=1.15.4,<2.0", + "lxml-stubs>=0.5.1", + "lxml>=6.0.2", + "numpy>=1.26.4 ; python_version < '3.10'", + "numpy>=2.0.2 ; python_version >= '3.10'", + "pyaml>=25.7.0", + "scikit-learn>=1.6.1 ; python_version < '3.11'", + "scikit-learn>=1.7.2 ; python_version >= '3.11'", + "scipy>=1.13.1 ; python_version < '3.10'", + "scipy>=1.15.3 ; python_version >= '3.10'", +] + +[project.optional-dependencies] +dev = [ + "ruff>=0.1.0", + "pytest>=9.1.1", +] + [project.urls] Homepage = "https://github.com/bretttolbert/verbecc" Documentation = "https://github.com/bretttolbert/verbecc" @@ -88,13 +92,22 @@ Repository = "https://github.com/bretttolbert/verbecc.git" Changelog = "https://github.com/bretttolbert/verbecc/blob/master/CHANGELOG.md" [tool.setuptools.package-data] -trained_models = ['verbecc/data/models/*'] +verbecc = [ + "py.typed", + "config/*.yaml", + "data/xml/conjugations/*.xml", + "data/xml/verbs/*.xml", + "data/models/*", + "resources/icons/*.png", + "resources/icons/*.svg", + "resources/fonts/*.ttf", +] -[tool.setuptools.packages] -find = {} +[tool.setuptools.packages.find] +where = ["src"] # <-- This tells setuptools to scan inside src/ [project.scripts] -train-verb-models = 'verbecc.src.utils.utils:train_models' +train-verb-models = 'verbecc.core.utils.utils:train_models' [tool.pytest.ini_options] pythonpath = [ @@ -124,4 +137,24 @@ addopts = [ "--ignore=verbecc/data", "--ignore=data", "--ignore=doc" -] \ No newline at end of file +] + +[tool.ruff] +# Set the maximum line length to match your GitHub Actions setup +line-length = 127 + +[tool.ruff.lint] +# Enable Flake8 syntax/error equivalents (E9, F63, F7, F82) +# "E" and "F" enable pycodestyle errors and Pyflakes +select = ["E9", "F63", "F7", "F82"] + +# Enable McCabe complexity checking (equivalent to flake8 --max-complexity=10) +[tool.ruff.lint.mccabe] +max-complexity = 10 + +[tool.mypy] +mypy_path = "typings" + +[[tool.mypy.overrides]] +module = "*.pyi" +ignore_errors = true diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 3f942f3..0000000 --- a/requirements.txt +++ /dev/null @@ -1,18 +0,0 @@ -backports.strenum>=1.3.1,<2.0;python_version<"3.11" -Cython==3.1.4 -dataclass-wizard==0.35.1 -importlib_resources>=6.4.5,<=6.5.2 -iniconfig==2.1.0 -joblib==1.4.2 -jsbeautifier==1.15.4 -lxml-stubs==0.5.1 -lxml==6.1.0 -numpy>=2.0.2,<=2.3.3 -packaging==25.0 -pluggy==1.6.0 -pyaml==25.7.0 -pytest==8.4.2;python_version<="3.9" -pytest==9.0.3;python_version>"3.9" -scikit-learn>=1.6.1,<=1.7.2 -scipy>=1.13.1,<=1.16.1 -threadpoolctl==3.6.0 \ No newline at end of file diff --git a/verbecc/src/__init__.py b/scripts/__init__.py similarity index 100% rename from verbecc/src/__init__.py rename to scripts/__init__.py diff --git a/scripts/xml_modifier.py b/scripts/xml_modifier.py index 7b3a477..376d926 100755 --- a/scripts/xml_modifier.py +++ b/scripts/xml_modifier.py @@ -14,22 +14,22 @@ """ -from typing import Optional +from typing import Optional, cast from pathlib import Path -from lxml import etree, objectify -import os -from typing import List, Sequence, Tuple -from verbecc.src.defs.types.tense import Tense, Tenses -from verbecc.src.defs.types.mood import Mood, Moods -from verbecc.src.utils.logging_utils import LoggingUtils +from typing import Sequence, Tuple -INPUT_PATH = "../verbecc/data/xml/conjugations/conjugations-es.xml" -OUTPUT_PATH = "../verbecc/data/xml/conjugations/conjugations-es.mod.xml" +from verbecc.core.defs.types.data.xml_types import XmlElement, XmlElementTree, XmlParser +from verbecc.core.defs.types.mood import Mood, Moods +from verbecc.core.defs.types.tense import Tense, Tenses +from verbecc.core.utils.logging_utils import LoggingUtils +from verbecc.core.utils.xml_utils import xml_element_remove, xml_element_repr, xml_element_to_string, xml_element_deannotate, xml_element_xpath, xml_parse -logger = LoggingUtils.get_logger(__name__) +INPUT_PATH = "src/verbecc/data/xml/conjugations/conjugations-es.xml" +OUTPUT_PATH = "src/verbecc/data/xml/conjugations/conjugations-es.mod.xml" +logger = LoggingUtils.get_logger(__name__) -def remove_tenses(root: etree._Element, tenses_to_remove: List[Tense]) -> None: +def remove_tenses(root: XmlElement, tenses_to_remove: list[Tense]) -> None: removed_elem_cnt = 0 for template_elem in root: if template_elem.tag == "template": @@ -41,7 +41,7 @@ def remove_tenses(root: etree._Element, tenses_to_remove: List[Tense]) -> None: logger.info("removed {} elements".format(removed_elem_cnt)) -def remove_mood(root: etree._Element, moods_to_remove: List[Mood]) -> None: +def remove_mood(root: XmlElement, moods_to_remove: list[Mood]) -> None: removed_elem_cnt = 0 for template_elem in root: if template_elem.tag == "template": @@ -53,11 +53,11 @@ def remove_mood(root: etree._Element, moods_to_remove: List[Mood]) -> None: def find_tense( - template_elem: etree._Element, + template_elem: XmlElement, mood: Mood, tense: Tense, should_remove_mood: bool = False, -) -> Optional[etree._Element]: +) -> Optional[XmlElement]: # find tense to move for mood_elem in template_elem: if mood_elem.tag == mood: @@ -77,7 +77,7 @@ def find_tense( def move_tense( - root: etree._Element, + root: XmlElement, tense: Tense, old_mood: Mood, new_mood: Mood, @@ -100,34 +100,26 @@ def move_tense( logger.info("moved {} elements".format(moved_elem_cnt)) -def read_input_file(path: Path) -> etree._ElementTree: - parser = etree.XMLParser(dtd_validation=False, encoding="utf-8") - tree = etree.parse(path, parser) +def read_input_file(path: Path) -> XmlElementTree: + parser = XmlParser(dtd_validation=False, encoding="utf-8") + tree = xml_parse(path, parser) return tree -def elem_tobytes(elem: etree._Element) -> bytes: - return etree.tostring( +def elem_tobytes(elem: XmlElement) -> bytes: + return xml_element_to_string( elem, encoding="utf-8", method="xml", pretty_print=True, xml_declaration=True, - ) - - -def elem_tostring(elem: etree._Element) -> str: - return elem_tobytes(elem).decode("utf-8") - + ).encode("utf-8") -def repr_elem(elem: etree._Element) -> str: - return f"{elem.tag}: {elem} {elem_tostring(elem)}" - -def write_output_file(tree: etree._ElementTree, path: Path) -> None: +def write_output_file(tree: XmlElementTree, path: Path) -> None: root = tree.getroot() with open(path, "wb") as f: - objectify.deannotate(root, cleanup_namespaces=True) + xml_element_deannotate(root) xml = elem_tobytes(root) f.write(xml) @@ -201,7 +193,7 @@ def do_romanian_mods(input_path: Path, output_path: Path) -> None: def remove_nth_element_of_every_matching_great_grandchild( - root: etree._Element, + root: XmlElement, great_grandparent_elem_tag: str, grandparent_elem_tag: str, parent_elem_tag: str, @@ -210,52 +202,53 @@ def remove_nth_element_of_every_matching_great_grandchild( dry_run: bool = True, ) -> int: """ - n = the (1-based) indice of the element to remove - - returns number of elements removed + n = the 1-based index of the element to remove. + Returns the number of elements removed. """ if n < 1: - raise ValueError("n must be nonzero") + raise ValueError("n must be greater than or equal to 1") + + # Construct XPath path leading directly to parent elements. + # Note: Using translate() handles case-insensitivity for the grandparent tag. + xpath_query = ( + f"./{great_grandparent_elem_tag}/" + f"*[translate(name(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') = '{grandparent_elem_tag.lower()}']/" + f"{parent_elem_tag}" + ) + cnt = 0 - for great_grandparent_elem in root: - # E.g. template - if great_grandparent_elem.tag == great_grandparent_elem_tag: - # E.g. mood - for grandparent_elem in great_grandparent_elem: - if grandparent_elem.tag.lower() == grandparent_elem_tag: - # E.g. tense - for parent_elem in grandparent_elem: - if parent_elem.tag == parent_elem_tag: - elem_n = 1 - # E.g.
elem - for elem in parent_elem: - if elem.tag == elem_to_remove_tag: - if elem_n == n: - if dry_run is False: - parent_elem.remove(elem) - logger.info( - f"Removed elem {repr_elem(elem)}" - ) - else: - logger.info( - f"Would have removed elem {repr_elem(elem)}" - ) - cnt += 1 - elem_n += 1 - qualifier = "" - if dry_run: - qualifier = "would have " + # This XPath selects elements, but lxml's type stubs model ``xpath`` as + # potentially returning scalar XPath results as well. + parents = cast(list[XmlElement], xml_element_xpath(root, xpath_query)) # type: ignore + for parent in parents: + # Filter children matching the target tag + matching_children = [ + child for child in parent if child.tag == elem_to_remove_tag + ] + + # Check if the 1-based index exists + if len(matching_children) >= n: + target_elem = matching_children[n - 1] + action_str = "Would have removed" if dry_run else "Removed" + + if not dry_run: + xml_element_remove(parent, target_elem) + + logger.info(f"{action_str} elem {xml_element_repr(target_elem)}") + cnt += 1 + + qualifier = "would have " if dry_run else "" logger.info( f"{qualifier}removed {cnt} <{elem_to_remove_tag}> elements " - + f"descendent from parent element {parent_elem_tag}, " - + f"from grandparent element {grandparent_elem_tag}, " - + f"from great-grandparent element {great_grandparent_elem_tag}, " + f"descendent from parent element {parent_elem_tag}, " + f"from grandparent element {grandparent_elem_tag}, " + f"from great-grandparent element {great_grandparent_elem_tag}." ) return cnt def remove_second_p_element_from_every_matching_template( - root: etree._Element, mood: Mood, tense: Tense, dry_run: bool = True + root: XmlElement, mood: Mood, tense: Tense, dry_run: bool = True ) -> int: return remove_nth_element_of_every_matching_great_grandchild( root, diff --git a/setup.cfg b/setup.cfg index 224a779..0f94f37 100755 --- a/setup.cfg +++ b/setup.cfg @@ -1,2 +1,2 @@ [metadata] -description-file = README.md \ No newline at end of file +description_file = README.md \ No newline at end of file diff --git a/setup.py b/setup.py deleted file mode 100755 index fc1f76c..0000000 --- a/setup.py +++ /dev/null @@ -1,3 +0,0 @@ -from setuptools import setup - -setup() \ No newline at end of file diff --git a/src/verbecc/__init__.py b/src/verbecc/__init__.py new file mode 100644 index 0000000..e336bb0 --- /dev/null +++ b/src/verbecc/__init__.py @@ -0,0 +1 @@ +from .core import CompleteConjugator as CompleteConjugator \ No newline at end of file diff --git a/verbecc/config/logging_config.yaml b/src/verbecc/config/logging_config.yaml similarity index 100% rename from verbecc/config/logging_config.yaml rename to src/verbecc/config/logging_config.yaml diff --git a/verbecc/config/verbecc_config.yaml b/src/verbecc/config/verbecc_config.yaml similarity index 100% rename from verbecc/config/verbecc_config.yaml rename to src/verbecc/config/verbecc_config.yaml diff --git a/src/verbecc/core/__init__.py b/src/verbecc/core/__init__.py new file mode 100644 index 0000000..e11a4d3 --- /dev/null +++ b/src/verbecc/core/__init__.py @@ -0,0 +1 @@ +from .conjugator import CompleteConjugator as CompleteConjugator \ No newline at end of file diff --git a/src/verbecc/core/conjugator/__init__.py b/src/verbecc/core/conjugator/__init__.py new file mode 100644 index 0000000..e0f6e82 --- /dev/null +++ b/src/verbecc/core/conjugator/__init__.py @@ -0,0 +1 @@ +from .complete_conjugator import CompleteConjugator as CompleteConjugator \ No newline at end of file diff --git a/verbecc/src/conjugator/abstract_conjugator.py b/src/verbecc/core/conjugator/abstract_conjugator.py similarity index 67% rename from verbecc/src/conjugator/abstract_conjugator.py rename to src/verbecc/core/conjugator/abstract_conjugator.py index f4274c2..2c62ba4 100644 --- a/verbecc/src/conjugator/abstract_conjugator.py +++ b/src/verbecc/core/conjugator/abstract_conjugator.py @@ -1,21 +1,20 @@ from abc import ABC -from typing import List, Optional +from typing import Optional -from verbecc.src.conjugator.conjugation_object import ConjugationObjects -from verbecc.src.defs.types.conjugation.conjugation import Conjugation -from verbecc.src.defs.types.conjugation.tense_conjugation import TenseConjugation -from verbecc.src.defs.types.data.conjugation_template import ConjugationTemplate -from verbecc.src.defs.types.data.person_ending import PersonEnding -from verbecc.src.defs.types.data.verb import Verb -from verbecc.src.defs.types.exceptions.verb_not_found_error import VerbNotFoundError -from verbecc.src.defs.types.gender import Gender -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 -from verbecc.src.defs.types.lang_specific_options import LangSpecificOptions -from verbecc.src.defs.types.number import Number -from verbecc.src.defs.types.person import Person -from verbecc.src.inflectors.inflector import Inflector -from verbecc.src.inflectors.inflector_factory import InflectorFactory -from verbecc.src.utils.logging_utils import LoggingUtils +from verbecc.core.conjugator.conjugation_object import ConjugationObjects +from verbecc.core.defs.types.conjugation.conjugation import Conjugation +from verbecc.core.defs.types.conjugation.tense_conjugation import TenseConjugation +from verbecc.core.defs.types.data.conjugation_template import ConjugationTemplate +from verbecc.core.defs.types.data.person_ending import PersonEnding +from verbecc.core.defs.types.data.verb import Verb +from verbecc.core.defs.types.exceptions.verb_not_found_error import VerbNotFoundError +from verbecc.core.defs.types.gender import Gender +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 +from verbecc.core.defs.types.lang_specific_options import LangSpecificOptions +from verbecc.core.defs.types.number import Number +from verbecc.core.inflectors.inflector import Inflector +from verbecc.core.inflectors.inflector_factory import InflectorFactory +from verbecc.core.utils.logging_utils import LoggingUtils class AbstractConjugator(ABC): @@ -36,7 +35,7 @@ def __init__( self._logger = LoggingUtils.get_logger(subclass_name) super().__init__() - def _get_conj_obs(self, infinitive: str) -> ConjugationObjects: + def _get_conj_objs(self, infinitive: str) -> ConjugationObjects: infinitive = infinitive.lower() is_reflexive, infinitive = self._inflector.split_reflexive(infinitive) if is_reflexive and not self._inflector.verb_can_be_reflexive(infinitive): @@ -48,16 +47,16 @@ def _get_conj_obs(self, infinitive: str) -> ConjugationObjects: ) return ConjugationObjects(infinitive, verb, template, verb_stem, is_reflexive) - def get_verbs(self) -> List[Verb]: + def get_verbs(self) -> list[Verb]: return self._inflector.get_verbs() - def get_infinitives(self) -> List[str]: + def get_infinitives(self) -> list[str]: return self._inflector.get_infinitives() - def get_templates(self) -> List[ConjugationTemplate]: + def get_templates(self) -> list[ConjugationTemplate]: return self._inflector.get_templates() - def get_template_names(self) -> List[str]: + def get_template_names(self) -> list[str]: return self._inflector.get_template_names() def find_verb_by_infinitive(self, infinitive: str) -> Verb: @@ -66,14 +65,14 @@ def find_verb_by_infinitive(self, infinitive: str) -> Verb: def find_template(self, name: str) -> ConjugationTemplate: return self._inflector.find_template(name) - def get_verbs_that_start_with(self, query: str, max_results: int) -> List[str]: + def get_verbs_that_start_with(self, query: str, max_results: int) -> list[str]: return self._inflector.get_verbs_that_start_with(query, max_results) def get_person_ending_by_gender_and_number( self, - person_endings: List[PersonEnding], - gender: Optional[Gender], - number: Optional[Number], + person_endings: list[PersonEnding], + gender: Optional[Gender | str], + number: Optional[Number | str], ) -> PersonEnding: resolved_gender = Gender.m resolved_number = Number.Singular @@ -92,8 +91,8 @@ def get_person_ending_by_gender_and_number( def get_conjugation_by_gender_and_number( self, tense_conjugation: TenseConjugation, - gender: Optional[Gender], - number: Optional[Number], + gender: Optional[Gender | str], + number: Optional[Number | str], ) -> Conjugation: resolved_gender = Gender.m resolved_number = Number.Singular @@ -111,3 +110,6 @@ def get_conjugation_by_gender_and_number( self._logger.error("Failed to get conjugation, tense_conjugation is empty") raise Exception("Failed to get conjugation, tense_conjugation is empty") return tense_conjugation[0] + + def _get_inflector(self) -> Inflector: + return self._inflector diff --git a/verbecc/src/conjugator/complete_conjugator.py b/src/verbecc/core/conjugator/complete_conjugator.py similarity index 70% rename from verbecc/src/conjugator/complete_conjugator.py rename to src/verbecc/core/conjugator/complete_conjugator.py index 2c135b4..cbdecc0 100755 --- a/verbecc/src/conjugator/complete_conjugator.py +++ b/src/verbecc/core/conjugator/complete_conjugator.py @@ -1,16 +1,17 @@ from typing import Optional -from verbecc.src.conjugator.abstract_conjugator import AbstractConjugator -from verbecc.src.conjugator.mood_conjugator import MoodConjugator -from verbecc.src.defs.types.conjugation.complete_conjugation import CompleteConjugation -from verbecc.src.defs.types.conjugation.mood_conjugation import MoodConjugation -from verbecc.src.defs.types.conjugation.moods_conjugation import MoodsConjugation -from verbecc.src.defs.types.conjugation.verb_info import VerbInfo -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 -from verbecc.src.defs.types.lang_specific_options import LangSpecificOptions -from verbecc.src.defs.types.mood import Mood -from verbecc.src.defs.types.tense import Tense -from verbecc.src.defs.types.conjugation.tense_conjugation import TenseConjugation +from verbecc.core.conjugator.abstract_conjugator import AbstractConjugator +from verbecc.core.conjugator.mood_conjugator import MoodConjugator +from verbecc.core.defs.types.conjugation.complete_conjugation import CompleteConjugation +from verbecc.core.defs.types.conjugation.mood_conjugation import MoodConjugation +from verbecc.core.defs.types.conjugation.moods_conjugation import MoodsConjugation +from verbecc.core.defs.types.conjugation.verb_info import VerbInfo +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 +from verbecc.core.defs.types.lang_specific_options import LangSpecificOptions +from verbecc.core.defs.types.mood import Mood +from verbecc.core.defs.types.tense import Tense +from verbecc.core.defs.types.conjugation.tense_conjugation import TenseConjugation +from verbecc.core.inflectors.inflector import Inflector class CompleteConjugator(AbstractConjugator): @@ -47,10 +48,10 @@ def conjugate( :param lang_specific_options: options specific to certain languages. :type lang_specific_options: LangSpecificOptions """ - co = self._get_conj_obs(infinitive) + co = self._get_conj_objs(infinitive) moods = MoodsConjugation() for mood, _ in co.template.mood_templates.items(): - moods[mood] = self._mood_conjugator._conjugate_mood( + moods[mood] = self._mood_conjugator._conjugate_mood( # type: ignore co, mood, conjugate_pronouns, @@ -71,7 +72,7 @@ def conjugate( def conjugate_mood( self, infinitive: str, - mood: Mood, + mood: Mood | str, conjugate_pronouns: bool = True, ) -> MoodConjugation: return self._mood_conjugator.conjugate_mood( @@ -83,8 +84,8 @@ def conjugate_mood( def conjugate_mood_tense( self, infinitive: str, - mood: Mood, - tense: Tense, + mood: Mood | str, + tense: Tense | str, conjugate_pronouns: bool = True, ) -> TenseConjugation: return self._mood_conjugator.conjugate_mood_tense( @@ -93,3 +94,6 @@ def conjugate_mood_tense( tense, conjugate_pronouns=conjugate_pronouns, ) + + def _get_inflector(self) -> Inflector: + return self._inflector diff --git a/verbecc/src/conjugator/conjugation_object.py b/src/verbecc/core/conjugator/conjugation_object.py similarity index 86% rename from verbecc/src/conjugator/conjugation_object.py rename to src/verbecc/core/conjugator/conjugation_object.py index 4d74e9b..7aee758 100644 --- a/verbecc/src/conjugator/conjugation_object.py +++ b/src/verbecc/core/conjugator/conjugation_object.py @@ -1,5 +1,5 @@ -from verbecc.src.defs.types.data.verb import Verb -from verbecc.src.defs.types.data.conjugation_template import ConjugationTemplate +from verbecc.core.defs.types.data.verb import Verb +from verbecc.core.defs.types.data.conjugation_template import ConjugationTemplate class ConjugationObjects: diff --git a/verbecc/src/conjugator/conjugator.py b/src/verbecc/core/conjugator/conjugator.py similarity index 79% rename from verbecc/src/conjugator/conjugator.py rename to src/verbecc/core/conjugator/conjugator.py index 16a4687..ed02785 100644 --- a/verbecc/src/conjugator/conjugator.py +++ b/src/verbecc/core/conjugator/conjugator.py @@ -1,19 +1,19 @@ -from typing import List, Optional +from typing import Optional, cast -from verbecc.src.conjugator.abstract_conjugator import AbstractConjugator -from verbecc.src.defs.constants import grammar_defines -from verbecc.src.defs.types.conjugation.conjugation import Conjugation -from verbecc.src.defs.types.data.person_ending import PersonEnding -from verbecc.src.defs.types.data.tense_template import TenseTemplate -from verbecc.src.defs.types.gender import Gender -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 -from verbecc.src.defs.types.lang_specific_options import LangSpecificOptions -from verbecc.src.defs.types.mood import Mood -from verbecc.src.defs.types.number import Number -from verbecc.src.defs.types.person import Person -from verbecc.src.defs.types.tense import Tense -from verbecc.src.inflectors.inflector import Inflector -from verbecc.src.defs.types.pronoun import Pronoun +from verbecc.core.conjugator.abstract_conjugator import AbstractConjugator +from verbecc.core.defs.constants import grammar_defines +from verbecc.core.defs.types.conjugation.conjugation import Conjugation +from verbecc.core.defs.types.data.person_ending import PersonEnding +from verbecc.core.defs.types.data.tense_template import TenseTemplate +from verbecc.core.defs.types.gender import Gender +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 +from verbecc.core.defs.types.lang_specific_options import LangSpecificOptions +from verbecc.core.defs.types.mood import Mood +from verbecc.core.defs.types.number import Number +from verbecc.core.defs.types.person import Person +from verbecc.core.defs.types.tense import Tense +from verbecc.core.inflectors.inflector import Inflector +from verbecc.core.defs.types.pronoun import Pronoun class Conjugator(AbstractConjugator): @@ -42,17 +42,23 @@ def __init__( def conjugate( self, verb_stem: str, - mood: Mood, - tense: Tense, + mood: Mood | str, + tense: Tense | str, tense_template: TenseTemplate, - person: Optional[Person], + person: Optional[Person | str], person_ending: PersonEnding, - number: Optional[Number], - pronoun: Optional[Pronoun], + number: Optional[Number | str], + pronoun: Optional[Pronoun | str], is_reflexive: bool = False, - primary_tense: Optional[Tense] = None, + primary_tense: Optional[Tense | str] = None, tense_conjugated_with_pronoun: bool = True, ) -> Conjugation: + mood = cast(Mood, mood) + tense = cast(Tense, tense) + person = cast(Optional[Person], person) + number = cast(Optional[Number], number) + pronoun = cast(Optional[Pronoun], pronoun) + primary_tense = cast(Optional[Tense], primary_tense) # here's where the voseo magic happens person_ending = self._inflector.modify_person_ending_if_applicable( person_ending, mood, tense, tense_template, pronoun @@ -77,7 +83,7 @@ def conjugate( pronoun_str = self._inflector.make_pronoun_reflexive(pronoun) # get endings i.e. primary and optional alternate(s) - endings: List[str] = [] + endings: list[str] = [] endings.extend(person_ending.get_endings()) if len(endings) == 0: diff --git a/verbecc/src/conjugator/mood_conjugator.py b/src/verbecc/core/conjugator/mood_conjugator.py similarity index 64% rename from verbecc/src/conjugator/mood_conjugator.py rename to src/verbecc/core/conjugator/mood_conjugator.py index 34e263a..47e60af 100644 --- a/verbecc/src/conjugator/mood_conjugator.py +++ b/src/verbecc/core/conjugator/mood_conjugator.py @@ -1,17 +1,17 @@ -from typing import Optional +from typing import Optional, cast -from verbecc.src.conjugator.abstract_conjugator import AbstractConjugator -from verbecc.src.conjugator.conjugation_object import ConjugationObjects -from verbecc.src.conjugator.tense_conjugator import TenseConjugator -from verbecc.src.defs.types.conjugation.mood_conjugation import MoodConjugation -from verbecc.src.defs.types.conjugation.mood_conjugation_util import MoodConjugationUtil -from verbecc.src.defs.types.conjugation.tense_conjugation import TenseConjugation -from verbecc.src.defs.types.exceptions import InvalidMoodError -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 -from verbecc.src.defs.types.lang_specific_options import LangSpecificOptions -from verbecc.src.defs.types.mood import Mood -from verbecc.src.defs.types.tense import Tense -from verbecc.src.inflectors.inflector import Inflector +from verbecc.core.conjugator.abstract_conjugator import AbstractConjugator +from verbecc.core.conjugator.conjugation_object import ConjugationObjects +from verbecc.core.conjugator.tense_conjugator import TenseConjugator +from verbecc.core.defs.types.conjugation.mood_conjugation import MoodConjugation +from verbecc.core.defs.types.conjugation.mood_conjugation_util import MoodConjugationUtil +from verbecc.core.defs.types.conjugation.tense_conjugation import TenseConjugation +from verbecc.core.defs.types.exceptions import InvalidMoodError +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 +from verbecc.core.defs.types.lang_specific_options import LangSpecificOptions +from verbecc.core.defs.types.mood import Mood +from verbecc.core.defs.types.tense import Tense +from verbecc.core.inflectors.inflector import Inflector class MoodConjugator(AbstractConjugator): @@ -31,17 +31,17 @@ def __init__( def conjugate_mood( self, infinitive: str, - mood: Mood, + mood: Mood | str, conjugate_pronouns: bool = True, ) -> MoodConjugation: - co = self._get_conj_obs(infinitive) + co = self._get_conj_objs(infinitive) return self._conjugate_mood(co, mood, conjugate_pronouns) def conjugate_mood_tense( self, infinitive: str, - mood: Mood, - tense: Tense, + mood: Mood | str, + tense: Tense | str, conjugate_pronouns: bool = True, ) -> TenseConjugation: return self._tense_conjugator.conjugate_mood_tense( @@ -54,7 +54,7 @@ def conjugate_mood_tense( def _conjugate_mood( self, co: ConjugationObjects, - mood: Mood, + mood: Mood | str, conjugate_pronouns: bool = True, ) -> MoodConjugation: if mood not in co.template.mood_templates.keys(): @@ -77,13 +77,13 @@ def _conjugate_mood( def _get_simple_conjugations_for_mood( self, co: ConjugationObjects, - mood: Mood, + mood: Mood | str, conjugate_pronouns: bool = True, ) -> MoodConjugation: - ret = MoodConjugation(mood) - mood_template = co.template.mood_templates[mood] + ret = MoodConjugation(cast(Mood, mood)) + mood_template = co.template.mood_templates[cast(Mood, mood)] for tense in mood_template.tense_templates: - ret[tense] = self._tense_conjugator._conjugate_mood_tense( + ret[tense] = self._tense_conjugator._conjugate_mood_tense( # type: ignore co, mood, tense, @@ -94,14 +94,14 @@ def _get_simple_conjugations_for_mood( def _get_compound_conjugations_for_mood( self, co: ConjugationObjects, - mood: Mood, + mood: Mood | str, conjugate_pronouns: bool = True, ) -> MoodConjugation: - ret = MoodConjugation(mood) + ret = MoodConjugation(cast(Mood, mood)) comp_conj_map = self._inflector.get_compound_conjugations_aux_verb_map() - if mood in comp_conj_map: - for tense in comp_conj_map[mood]: - ret[tense] = self._tense_conjugator._conjugate_mood_tense( + if cast(Mood, mood) in comp_conj_map: + for tense in comp_conj_map[cast(Mood, mood)]: + ret[tense] = self._tense_conjugator._conjugate_mood_tense( # type: ignore co, mood, tense, diff --git a/verbecc/src/conjugator/tense_conjugator.py b/src/verbecc/core/conjugator/tense_conjugator.py similarity index 54% rename from verbecc/src/conjugator/tense_conjugator.py rename to src/verbecc/core/conjugator/tense_conjugator.py index b5ebfd3..1ea010b 100644 --- a/verbecc/src/conjugator/tense_conjugator.py +++ b/src/verbecc/core/conjugator/tense_conjugator.py @@ -1,16 +1,16 @@ -from typing import Optional +from typing import Optional, cast -from verbecc.src.conjugator.conjugation_object import ConjugationObjects -from verbecc.src.defs.types.mood import Mood -from verbecc.src.defs.types.tense import Tense -from verbecc.src.defs.types.exceptions import InvalidTenseError -from verbecc.src.defs.types.conjugation.tense_conjugation import TenseConjugation -from verbecc.src.defs.types.lang_specific_options import LangSpecificOptions -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 -from verbecc.src.inflectors.inflector import Inflector -from verbecc.src.conjugator.abstract_conjugator import AbstractConjugator -from verbecc.src.conjugator.tense_conjugator_simple import TenseConjugatorSimple -from verbecc.src.conjugator.tense_conjugator_compound import TenseConjugatorCompound +from verbecc.core.conjugator.conjugation_object import ConjugationObjects +from verbecc.core.defs.types.mood import Mood +from verbecc.core.defs.types.tense import Tense +from verbecc.core.defs.types.exceptions import InvalidTenseError +from verbecc.core.defs.types.conjugation.tense_conjugation import TenseConjugation +from verbecc.core.defs.types.lang_specific_options import LangSpecificOptions +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 +from verbecc.core.inflectors.inflector import Inflector +from verbecc.core.conjugator.abstract_conjugator import AbstractConjugator +from verbecc.core.conjugator.tense_conjugator_simple import TenseConjugatorSimple +from verbecc.core.conjugator.tense_conjugator_compound import TenseConjugatorCompound class TenseConjugator(AbstractConjugator): @@ -39,11 +39,11 @@ def __init__( def conjugate_mood_tense( self, infinitive: str, - mood: Mood, - tense: Tense, + mood: Mood | str, + tense: Tense | str, conjugate_pronouns: bool = True, ) -> TenseConjugation: - co = self._get_conj_obs(infinitive) + co = self._get_conj_objs(infinitive) return self._conjugate_mood_tense( co, mood, @@ -54,34 +54,36 @@ def conjugate_mood_tense( def _conjugate_mood_tense( self, co: ConjugationObjects, - mood: Mood, - tense: Tense, + mood: Mood | str, + tense: Tense | str, conjugate_pronouns: bool = True, ) -> TenseConjugation: comp_conj_map = self._inflector.get_compound_conjugations_aux_verb_map() - if mood in comp_conj_map and tense in comp_conj_map[mood]: - aux_mood, aux_tense = comp_conj_map[mood][tense] + mood_key = cast(Mood, mood) + tense_key = cast(Tense, tense) + if mood_key in comp_conj_map and tense_key in comp_conj_map[mood_key]: + aux_mood, aux_tense = comp_conj_map[mood_key][tense_key] aux_uses_alternate = ( - self._inflector.auxiliary_verb_uses_alternate_conjugation(tense) + self._inflector.auxiliary_verb_uses_alternate_conjugation(tense_key) ) - return self._tense_conjugator_compound._conjugate_compound_mood_tense( + return self._tense_conjugator_compound._conjugate_compound_mood_tense( # type: ignore co, - mood, - tense, + mood_key, + tense_key, aux_mood, aux_tense, aux_uses_alternate, conjugate_pronouns=conjugate_pronouns, ) else: - mood_template = co.template.mood_templates[mood] - if tense not in mood_template.tense_templates: + mood_template = co.template.mood_templates[mood_key] + if tense_key not in mood_template.tense_templates: raise InvalidTenseError() - tense_template = mood_template.tense_templates[tense] - return self._tense_conjugator_simple._conjugate_simple_mood_tense( + tense_template = mood_template.tense_templates[tense_key] + return self._tense_conjugator_simple.conjugate_simple_mood_tense( co.verb_stem, - mood, - tense, + mood_key, + tense_key, tense_template, is_reflexive=co.is_reflexive, modify_stem_strip_accents=bool( @@ -89,3 +91,9 @@ def _conjugate_mood_tense( ), conjugate_pronouns=conjugate_pronouns, ) + + def _get_tense_conjugator_simple(self) -> TenseConjugatorSimple: + return self._tense_conjugator_simple + + def _get_tense_conjugator_compound(self) -> TenseConjugatorCompound: + return self._tense_conjugator_compound diff --git a/verbecc/src/conjugator/tense_conjugator_compound.py b/src/verbecc/core/conjugator/tense_conjugator_compound.py similarity index 90% rename from verbecc/src/conjugator/tense_conjugator_compound.py rename to src/verbecc/core/conjugator/tense_conjugator_compound.py index 2c519ec..8fc2d97 100644 --- a/verbecc/src/conjugator/tense_conjugator_compound.py +++ b/src/verbecc/core/conjugator/tense_conjugator_compound.py @@ -1,20 +1,20 @@ import copy -from typing import List, Optional +from typing import Optional -from verbecc.src.conjugator.conjugation_object import ConjugationObjects -from verbecc.src.defs.constants import grammar_defines -from verbecc.src.defs.types.gender import Gender -from verbecc.src.defs.types.number import Number -from verbecc.src.defs.types.person import Person -from verbecc.src.defs.types.mood import Mood -from verbecc.src.defs.types.tense import Tense -from verbecc.src.defs.types.conjugation.tense_conjugation import TenseConjugation -from verbecc.src.defs.types.conjugation.conjugation import Conjugation -from verbecc.src.defs.types.lang_specific_options import LangSpecificOptions -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 -from verbecc.src.inflectors.inflector import Inflector -from verbecc.src.conjugator.abstract_conjugator import AbstractConjugator -from verbecc.src.conjugator.tense_conjugator_simple import TenseConjugatorSimple +from verbecc.core.conjugator.conjugation_object import ConjugationObjects +from verbecc.core.defs.constants import grammar_defines +from verbecc.core.defs.types.data.person_ending import PersonEnding +from verbecc.core.defs.types.gender import Gender +from verbecc.core.defs.types.number import Number +from verbecc.core.defs.types.person import Person +from verbecc.core.defs.types.mood import Mood +from verbecc.core.defs.types.tense import Tense +from verbecc.core.defs.types.conjugation.tense_conjugation import TenseConjugation +from verbecc.core.defs.types.conjugation.conjugation import Conjugation +from verbecc.core.defs.types.lang_specific_options import LangSpecificOptions +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 +from verbecc.core.conjugator.abstract_conjugator import AbstractConjugator +from verbecc.core.conjugator.tense_conjugator_simple import TenseConjugatorSimple class TenseConjugatorCompound(AbstractConjugator): @@ -58,18 +58,18 @@ def _conjugate_compound_mood_tense( .person_endings ) aux_verb = self._inflector.get_auxiliary_verb(co, mood, tense) - aux_co = self._get_conj_obs(aux_verb) + aux_co = self._get_conj_objs(aux_verb) aux_tense_template = copy.deepcopy( aux_co.template.mood_templates[aux_mood].tense_templates[aux_tense] ) - aux_person_endings = [] + aux_person_endings: list[PersonEnding] = [] for aux_pe in aux_tense_template.person_endings: if aux_pe.person is not None and aux_pe.person in [ pe.person for pe in person_endings if pe.person is not None ]: aux_person_endings.append(aux_pe) aux_tense_template.person_endings = aux_person_endings - aux_conj = self._tense_conjugator_simple._conjugate_simple_mood_tense( + aux_conj = self._tense_conjugator_simple.conjugate_simple_mood_tense( aux_co.verb_stem, aux_mood, # todo: investigate (used to be "") aux_tense, @@ -133,7 +133,7 @@ def _conjugate_compound_primary_verb( ils/elles sont allé(e)s """ ret = TenseConjugation(tense) - aux_conj_scalar: List[str] = [] + aux_conj_scalar: list[str] = [] for pc in aux_conj: conjugations = pc.get_conjugations() if aux_uses_alternate and len(conjugations) > 1: @@ -151,7 +151,7 @@ def _conjugate_compound_primary_verb( ): p_conj.append(Conjugation(None, None, None, None, [co.infinitive])) else: - p_conj = self._tense_conjugator_simple._conjugate_simple_mood_tense( + p_conj = self._tense_conjugator_simple.conjugate_simple_mood_tense( co.verb_stem, p_mood, p_tense, @@ -282,18 +282,13 @@ def _conjugate_compound_primary_verb( for i, hv in enumerate(aux_conj_scalar): aux_pc = aux_conj[i] # e.g. "suis" # need to get person_ending, e.g. "allé", based on gender and number of aux_pc - gender = Gender.m number = Number.Singular - aux_pc_gender = aux_pc.get_gender() - if aux_pc_gender is not None: - gender = aux_pc_gender - aux_pc_number = aux_pc.get_number() if aux_pc_number is not None: number = aux_pc_number - genders = [] + genders: list[Gender | None] = [] if ( aux_pc.get_person() == Person.Third and aux_pc.get_gender() is not None @@ -325,7 +320,7 @@ def _conjugate_compound_primary_verb( def _conjugate_compound_participle_inflected( self, - gender: Gender, + gender: Gender | None, number: Number, aux_pc: Conjugation, p_conj: TenseConjugation, diff --git a/verbecc/src/conjugator/tense_conjugator_simple.py b/src/verbecc/core/conjugator/tense_conjugator_simple.py similarity index 83% rename from verbecc/src/conjugator/tense_conjugator_simple.py rename to src/verbecc/core/conjugator/tense_conjugator_simple.py index 8b25f58..1395921 100644 --- a/verbecc/src/conjugator/tense_conjugator_simple.py +++ b/src/verbecc/core/conjugator/tense_conjugator_simple.py @@ -1,15 +1,15 @@ -from typing import Optional +from typing import Optional, cast -from verbecc.src.defs.types.mood import Mood -from verbecc.src.defs.types.tense import Tense -from verbecc.src.defs.types.conjugation.tense_conjugation import TenseConjugation -from verbecc.src.defs.types.lang_specific_options import LangSpecificOptions -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 -from verbecc.src.defs.types.data.tense_template import TenseTemplate -from verbecc.src.inflectors.inflector import Inflector -from verbecc.src.utils.string_utils import strip_accents -from verbecc.src.conjugator.abstract_conjugator import AbstractConjugator -from verbecc.src.conjugator.conjugator import Conjugator +from verbecc.core.defs.types.mood import Mood +from verbecc.core.defs.types.tense import Tense +from verbecc.core.defs.types.conjugation.tense_conjugation import TenseConjugation +from verbecc.core.defs.types.lang_specific_options import LangSpecificOptions +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 +from verbecc.core.defs.types.data.tense_template import TenseTemplate +from verbecc.core.inflectors.inflector import Inflector +from verbecc.core.utils.string_utils import strip_accents +from verbecc.core.conjugator.abstract_conjugator import AbstractConjugator +from verbecc.core.conjugator.conjugator import Conjugator class TenseConjugatorSimple(AbstractConjugator): @@ -25,7 +25,7 @@ def __init__( ) self._conjugator = Conjugator(lang, lang_specific_options, self._inflector) - def _conjugate_simple_mood_tense( + def conjugate_simple_mood_tense( self, verb_stem: str, mood: Mood, @@ -47,7 +47,7 @@ def _conjugate_simple_mood_tense( if modify_stem_strip_accents and mood != self._inflector.get_infinitive_mood(): verb_stem = strip_accents(verb_stem) ret = TenseConjugation(tense) - tense = tense_template.tense + tense = cast(Tense, tense_template.tense) tense_conjugated_with_pronoun = True if ( tense in self._inflector.get_tenses_conjugated_without_pronouns() diff --git a/verbecc/src/conjugator/__init__.py b/src/verbecc/core/defs/__init__.py similarity index 100% rename from verbecc/src/conjugator/__init__.py rename to src/verbecc/core/defs/__init__.py diff --git a/verbecc/src/defs/__init__.py b/src/verbecc/core/defs/constants/__init__.py similarity index 100% rename from verbecc/src/defs/__init__.py rename to src/verbecc/core/defs/constants/__init__.py diff --git a/verbecc/src/defs/constants/grammar_defines.py b/src/verbecc/core/defs/constants/grammar_defines.py similarity index 90% rename from verbecc/src/defs/constants/grammar_defines.py rename to src/verbecc/core/defs/constants/grammar_defines.py index 175fed6..9a3760b 100755 --- a/verbecc/src/defs/constants/grammar_defines.py +++ b/src/verbecc/core/defs/constants/grammar_defines.py @@ -1,22 +1,15 @@ -import sys +from typing import Tuple -if sys.version_info >= (3, 11): - from enum import StrEnum -else: - from backports.strenum import StrEnum - -from typing import Dict, List, Tuple - -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 -from verbecc.src.defs.types.participle_inflection import ParticipleInflection -from verbecc.src.defs.types.person import Person -from verbecc.src.defs.types.number import Number +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 +from verbecc.core.defs.types.participle_inflection import ParticipleInflection +from verbecc.core.defs.types.person import Person +from verbecc.core.defs.types.number import Number # placeholder used in instances where no value is available NO_VALUE = "-" # map of ISO 639-1 codes to long names (in target language) -SUPPORTED_LANGUAGES: Dict[LangCodeISO639_1, str] = { +SUPPORTED_LANGUAGES: dict[LangCodeISO639_1, str] = { LangCodeISO639_1.ca: "català", LangCodeISO639_1.es: "español", LangCodeISO639_1.fr: "français", @@ -82,7 +75,7 @@ (Person.Second, Number.Plural), ) -IMPERATIVE_PERSONS: Dict[LangCodeISO639_1, tuple[Tuple[Person, Number], ...]] = { +IMPERATIVE_PERSONS: dict[LangCodeISO639_1, tuple[Tuple[Person, Number], ...]] = { LangCodeISO639_1.fr: IMPERATIVE_PERSONS_FR, LangCodeISO639_1.es: IMPERATIVE_PERSONS_ES, LangCodeISO639_1.ca: IMPERATIVE_PERSONS_CA, @@ -115,7 +108,7 @@ ParticipleInflection.FemininePlural, ) -PARTICIPLE_INFLECTIONS: Dict[ +PARTICIPLE_INFLECTIONS: dict[ LangCodeISO639_1, tuple[ParticipleInflection, ...], ] = { diff --git a/verbecc/src/defs/constants/localization.py b/src/verbecc/core/defs/constants/localization.py similarity index 87% rename from verbecc/src/defs/constants/localization.py rename to src/verbecc/core/defs/constants/localization.py index ac198da..ee0ed4e 100644 --- a/verbecc/src/defs/constants/localization.py +++ b/src/verbecc/core/defs/constants/localization.py @@ -1,10 +1,10 @@ -from typing import Dict +from typing import cast -from verbecc.src.defs.types.mood import Mood, Moods -from verbecc.src.defs.types.tense import Tense, TenseEn, Tenses -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 +from verbecc.core.defs.types.mood import Mood, Moods +from verbecc.core.defs.types.tense import Tense, Tenses +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 -MOOD_MAP: Dict[Mood, Dict[LangCodeISO639_1, Mood]] = { +MOOD_MAP: dict[Mood, dict[LangCodeISO639_1, Mood]] = { Moods.en.Indicative: { LangCodeISO639_1.ca: Moods.ca.Indicatiu, LangCodeISO639_1.es: Moods.es.Indicativo, @@ -35,7 +35,8 @@ LangCodeISO639_1.fr: Moods.fr.Conditionnel, LangCodeISO639_1.it: Moods.it.Condizionale, LangCodeISO639_1.pt: Moods.pt.Condicional, - LangCodeISO639_1.ro: Moods.ro.NA, # The conditional mood is formed by combining the conditional particle "ar" with the infinitive form of the verb + LangCodeISO639_1.ro: Moods.ro.NA, # The conditional mood is formed by + # combining the conditional particle "ar" with the infinitive form of the verb }, Moods.en.Infinitive: { LangCodeISO639_1.ca: Moods.ca.Infinitiu, @@ -67,7 +68,7 @@ }, } -TENSE_MAP: Dict[Tense, Dict[LangCodeISO639_1, Tense]] = { +TENSE_MAP: dict[Tense, dict[LangCodeISO639_1, Tense]] = { Tenses.en.Present: { LangCodeISO639_1.ca: Tenses.ca.Present, LangCodeISO639_1.es: Tenses.es.Presente, @@ -87,7 +88,8 @@ LangCodeISO639_1.ca: Tenses.ca.PassatSimple, LangCodeISO639_1.es: Tenses.es.PretéritoPerfectoSimple, LangCodeISO639_1.fr: Tenses.fr.PasséSimple, - LangCodeISO639_1.it: Tenses.it.PassatoRemoto, # The passato prossimo (compound tense) is roughly equivalent to the present perfect and past simple tenses + LangCodeISO639_1.it: Tenses.it.PassatoRemoto, # The passato prossimo + # (compound tense) is roughly equivalent to the present perfect and past simple tenses # however passato-remoto is the literal simple past tense e.g. 'io fui, tu fosti, lui fu, noi fummo', LangCodeISO639_1.pt: Tenses.pt.PretéritoPerfeito, LangCodeISO639_1.ro: Tenses.ro.PerfectSimplu, @@ -119,17 +121,17 @@ } -def xmood(lang: LangCodeISO639_1, m: Mood) -> Mood: +def xmood(lang: LangCodeISO639_1 | str, m: Mood | str) -> Mood: """Takes a mood name in EN and translates it to the specified language :raises: Exception if mood or lang doesn't exist """ - return MOOD_MAP[m][lang] + return MOOD_MAP[cast(Mood, m)][cast(LangCodeISO639_1, lang)] -def xtense(lang: LangCodeISO639_1, t: Tense) -> Tense: +def xtense(lang: LangCodeISO639_1 | str, t: Tense | str) -> Tense: """Takes a tense name in EN and translates it to the specified language :raises: Exception if tense or lang doesn't exist """ - return TENSE_MAP[t][lang] + return TENSE_MAP[cast(Tense, t)][cast(LangCodeISO639_1, lang)] \ No newline at end of file diff --git a/verbecc/src/defs/constants/__init__.py b/src/verbecc/core/defs/types/__init__.py similarity index 100% rename from verbecc/src/defs/constants/__init__.py rename to src/verbecc/core/defs/types/__init__.py diff --git a/verbecc/src/defs/types/config/jsbeautifier_opts.py b/src/verbecc/core/defs/types/config/jsbeautifier_opts.py similarity index 95% rename from verbecc/src/defs/types/config/jsbeautifier_opts.py rename to src/verbecc/core/defs/types/config/jsbeautifier_opts.py index 0dd21ea..bb82299 100644 --- a/verbecc/src/defs/types/config/jsbeautifier_opts.py +++ b/src/verbecc/core/defs/types/config/jsbeautifier_opts.py @@ -1,5 +1,5 @@ from dataclasses import dataclass, field -from dataclass_wizard import YAMLWizard +from dataclass_wizard.v0 import YAMLWizard @dataclass diff --git a/verbecc/src/defs/types/config/json_opts.py b/src/verbecc/core/defs/types/config/json_opts.py similarity index 86% rename from verbecc/src/defs/types/config/json_opts.py rename to src/verbecc/core/defs/types/config/json_opts.py index 69a3247..761b6be 100644 --- a/verbecc/src/defs/types/config/json_opts.py +++ b/src/verbecc/core/defs/types/config/json_opts.py @@ -1,6 +1,6 @@ from typing import Optional from dataclasses import dataclass, field -from dataclass_wizard import YAMLWizard +from dataclass_wizard.v0 import YAMLWizard @dataclass diff --git a/verbecc/src/defs/types/__init__.py b/src/verbecc/core/defs/types/config/logging/__init__.py similarity index 100% rename from verbecc/src/defs/types/__init__.py rename to src/verbecc/core/defs/types/config/logging/__init__.py diff --git a/verbecc/src/defs/types/config/logging/file_handler_config.py b/src/verbecc/core/defs/types/config/logging/file_handler_config.py similarity index 81% rename from verbecc/src/defs/types/config/logging/file_handler_config.py rename to src/verbecc/core/defs/types/config/logging/file_handler_config.py index fc009b6..0637648 100644 --- a/verbecc/src/defs/types/config/logging/file_handler_config.py +++ b/src/verbecc/core/defs/types/config/logging/file_handler_config.py @@ -1,6 +1,6 @@ from dataclasses import dataclass, field -from verbecc.src.defs.types.config.logging.handler_config import HandlerConfig +from verbecc.core.defs.types.config.logging.handler_config import HandlerConfig @dataclass diff --git a/verbecc/src/defs/types/config/logging/formatter_config.py b/src/verbecc/core/defs/types/config/logging/formatter_config.py similarity index 100% rename from verbecc/src/defs/types/config/logging/formatter_config.py rename to src/verbecc/core/defs/types/config/logging/formatter_config.py diff --git a/verbecc/src/defs/types/config/logging/handler_config.py b/src/verbecc/core/defs/types/config/logging/handler_config.py similarity index 100% rename from verbecc/src/defs/types/config/logging/handler_config.py rename to src/verbecc/core/defs/types/config/logging/handler_config.py diff --git a/verbecc/src/defs/types/config/logging/logger_config.py b/src/verbecc/core/defs/types/config/logging/logger_config.py similarity index 67% rename from verbecc/src/defs/types/config/logging/logger_config.py rename to src/verbecc/core/defs/types/config/logging/logger_config.py index 6c7460c..562c59d 100644 --- a/verbecc/src/defs/types/config/logging/logger_config.py +++ b/src/verbecc/core/defs/types/config/logging/logger_config.py @@ -1,9 +1,8 @@ from dataclasses import dataclass, field -from typing import List @dataclass class LoggerConfig: level: str = field(default="CRITICAL") - handlers: List[str] = field(default_factory=list) + handlers: list[str] = field(default_factory=list) # type: ignore propagate: bool = field(default=True) diff --git a/src/verbecc/core/defs/types/config/logging/logging_config.py b/src/verbecc/core/defs/types/config/logging/logging_config.py new file mode 100644 index 0000000..95b68dd --- /dev/null +++ b/src/verbecc/core/defs/types/config/logging/logging_config.py @@ -0,0 +1,25 @@ +from dataclasses import dataclass, field +from typing import Optional + +from verbecc.core.defs.types.config.logging.formatter_config import FormatterConfig +from verbecc.core.defs.types.config.logging.stream_handler_config import ( + StreamHandlerConfig, +) +from verbecc.core.defs.types.config.logging.file_handler_config import FileHandlerConfig +from verbecc.core.defs.types.config.logging.handler_config import HandlerConfig +from verbecc.core.defs.types.config.logging.logger_config import LoggerConfig + + +@dataclass +class LoggingConfig: + version: int = field(default=1) + disable_existing_loggers: bool = field(default=False) + formatters: dict[str, FormatterConfig] = field(default_factory=dict[str, FormatterConfig]) + handlers: dict[str, HandlerConfig] = field( + default_factory=lambda: { + "consoleHandler": StreamHandlerConfig(), + "fileHandler": FileHandlerConfig(), + } + ) + loggers: dict[str, LoggerConfig] = field(default_factory=dict[str, LoggerConfig]) + root: Optional[LoggerConfig] = field(default_factory=LoggerConfig) diff --git a/verbecc/src/defs/types/config/logging/stream_handler_config.py b/src/verbecc/core/defs/types/config/logging/stream_handler_config.py similarity index 77% rename from verbecc/src/defs/types/config/logging/stream_handler_config.py rename to src/verbecc/core/defs/types/config/logging/stream_handler_config.py index 539edea..c11547f 100644 --- a/verbecc/src/defs/types/config/logging/stream_handler_config.py +++ b/src/verbecc/core/defs/types/config/logging/stream_handler_config.py @@ -1,6 +1,6 @@ from dataclasses import dataclass, field -from verbecc.src.defs.types.config.logging.handler_config import HandlerConfig +from verbecc.core.defs.types.config.logging.handler_config import HandlerConfig @dataclass diff --git a/verbecc/src/defs/types/config/verbecc_config.py b/src/verbecc/core/defs/types/config/verbecc_config.py similarity index 66% rename from verbecc/src/defs/types/config/verbecc_config.py rename to src/verbecc/core/defs/types/config/verbecc_config.py index d4768a7..661be5a 100644 --- a/verbecc/src/defs/types/config/verbecc_config.py +++ b/src/verbecc/core/defs/types/config/verbecc_config.py @@ -1,8 +1,8 @@ from dataclasses import dataclass, field -from dataclass_wizard import YAMLWizard +from dataclass_wizard.v0 import YAMLWizard -from verbecc.src.defs.types.config.jsbeautifier_opts import JSBeautifierOpts -from verbecc.src.defs.types.config.json_opts import JSONOpts +from verbecc.core.defs.types.config.jsbeautifier_opts import JSBeautifierOpts +from verbecc.core.defs.types.config.json_opts import JSONOpts @dataclass diff --git a/src/verbecc/core/defs/types/conjugation/__init__.py b/src/verbecc/core/defs/types/conjugation/__init__.py new file mode 100644 index 0000000..7f30b72 --- /dev/null +++ b/src/verbecc/core/defs/types/conjugation/__init__.py @@ -0,0 +1,2 @@ +from .conjugation import Conjugation # type: ignore +from .tense_conjugation import TenseConjugation # type: ignore \ No newline at end of file diff --git a/verbecc/src/defs/types/conjugation/abstract_conjugation.py b/src/verbecc/core/defs/types/conjugation/abstract_conjugation.py similarity index 83% rename from verbecc/src/defs/types/conjugation/abstract_conjugation.py rename to src/verbecc/core/defs/types/conjugation/abstract_conjugation.py index 846b3fe..cfa5d7b 100644 --- a/verbecc/src/defs/types/conjugation/abstract_conjugation.py +++ b/src/verbecc/core/defs/types/conjugation/abstract_conjugation.py @@ -1,17 +1,12 @@ -from dataclasses import fields -from typing import cast, Optional +from typing import Optional from abc import ABC, abstractmethod import json -import yaml -from verbecc.src.utils.dict_utils import DictUtils -from verbecc.src.defs.types.config.verbecc_config import VerbeccConfig -from verbecc.src.defs.types.config.json_opts import JSONOpts -from verbecc.src.utils.config.verbecc_config_util import VerbeccConfigUtil -from verbecc.src.utils.jsbeautifier_utils import JSBeautifier -from verbecc.src.utils.json_utils import JSONUtils -from verbecc.src.utils.yaml_utils import YAMLUtils -from verbecc.src.defs.types.conjugation.conjugation_data import ConjugationKeyPerson +from verbecc.core.utils.dict_utils import DictUtils +from verbecc.core.utils.config.verbecc_config_util import VerbeccConfigUtil +from verbecc.core.utils.json_utils import JSONUtils +from verbecc.core.utils.yaml_utils import YAMLUtils +from verbecc.core.defs.types.conjugation.conjugation_data import ConjugationKeyPerson config = VerbeccConfigUtil().load_config() @@ -26,7 +21,7 @@ def get_parent(self) -> Optional[object]: def set_parent(self, value: object) -> None: if isinstance(value, AbstractConjugation): - self._parent = cast(AbstractConjugation, value) + self._parent = value else: raise TypeError() @@ -68,7 +63,7 @@ def to_yaml(self) -> str: # around all the string values, unlike YAML) # TODO: Figure out how to do this with custom yaml.Dumper - data = DictUtils.cast_values_recursive(data, ConjugationKeyPerson, int) + data = DictUtils.cast_values_recursive(data, ConjugationKeyPerson, int) # type: ignore # TODO: If possiuble, figure out how to prevent YAML from putting quotes around the # French pronoun "on" ("on" is considered an "ambiguous value" in YAML, by default) diff --git a/verbecc/src/defs/types/conjugation/complete_conjugation.py b/src/verbecc/core/defs/types/conjugation/complete_conjugation.py similarity index 77% rename from verbecc/src/defs/types/conjugation/complete_conjugation.py rename to src/verbecc/core/defs/types/conjugation/complete_conjugation.py index 5d12195..de40dff 100644 --- a/verbecc/src/defs/types/conjugation/complete_conjugation.py +++ b/src/verbecc/core/defs/types/conjugation/complete_conjugation.py @@ -1,15 +1,14 @@ -import json from typing import Iterable -from verbecc.src.defs.types.conjugation.abstract_conjugation import AbstractConjugation -from verbecc.src.defs.types.conjugation.verb_info import VerbInfo -from verbecc.src.defs.types.mood import Mood -from verbecc.src.defs.types.conjugation.mood_conjugation import MoodConjugation -from verbecc.src.defs.types.conjugation.moods_conjugation import MoodsConjugation -from verbecc.src.defs.types.conjugation.complete_conjugation_data import ( +from verbecc.core.defs.types.conjugation.abstract_conjugation import AbstractConjugation +from verbecc.core.defs.types.conjugation.verb_info import VerbInfo +from verbecc.core.defs.types.mood import Mood +from verbecc.core.defs.types.conjugation.mood_conjugation import MoodConjugation +from verbecc.core.defs.types.conjugation.moods_conjugation import MoodsConjugation +from verbecc.core.defs.types.conjugation.complete_conjugation_data import ( CompleteConjugationData, ) -from verbecc.src.utils.config.verbecc_config_util import VerbeccConfigUtil +from verbecc.core.utils.config.verbecc_config_util import VerbeccConfigUtil config = VerbeccConfigUtil().load_config() @@ -53,7 +52,7 @@ def __len__(self) -> int: return len(self._moods_conjugation) def __iter__(self) -> Iterable[Mood]: - return iter(self._moods_conjugation._data) + return iter(self._moods_conjugation.get_data().keys()) def __contains__(self, key: Mood) -> bool: return key in self._moods_conjugation diff --git a/src/verbecc/core/defs/types/conjugation/complete_conjugation_data.py b/src/verbecc/core/defs/types/conjugation/complete_conjugation_data.py new file mode 100644 index 0000000..68d5592 --- /dev/null +++ b/src/verbecc/core/defs/types/conjugation/complete_conjugation_data.py @@ -0,0 +1,8 @@ +from typing import Union + +from verbecc.core.defs.types.conjugation.verb_info_data import VerbInfoData +from verbecc.core.defs.types.conjugation.moods_conjugation_data import ( + MoodsConjugationData, +) + +CompleteConjugationData = dict[str, Union[VerbInfoData, MoodsConjugationData]] diff --git a/verbecc/src/defs/types/conjugation/conjugation.py b/src/verbecc/core/defs/types/conjugation/conjugation.py similarity index 77% rename from verbecc/src/defs/types/conjugation/conjugation.py rename to src/verbecc/core/defs/types/conjugation/conjugation.py index 12d1c74..6739d07 100644 --- a/verbecc/src/defs/types/conjugation/conjugation.py +++ b/src/verbecc/core/defs/types/conjugation/conjugation.py @@ -1,11 +1,15 @@ -from typing import cast, Dict, Iterator, List, Optional, Union - -from verbecc.src.defs.types.person import Person -from verbecc.src.defs.types.number import Number -from verbecc.src.defs.types.gender import Gender -from verbecc.src.defs.types.pronoun import Pronoun -from verbecc.src.defs.types.conjugation.abstract_conjugation import AbstractConjugation -from verbecc.src.defs.types.conjugation.conjugation_data import ( +from typing import cast, Iterator, Optional, overload +try: + from typing import Self # type: ignore +except ImportError: + from typing_extensions import Self # type: ignore + +from verbecc.core.defs.types.person import Person +from verbecc.core.defs.types.number import Number +from verbecc.core.defs.types.gender import Gender +from verbecc.core.defs.types.pronoun import Pronoun +from verbecc.core.defs.types.conjugation.abstract_conjugation import AbstractConjugation +from verbecc.core.defs.types.conjugation.conjugation_data import ( ConjugationData, ConjugationKeyPerson, ConjugationKeyNumber, @@ -33,7 +37,7 @@ def __init__( number: Optional[Number] = None, gender: Optional[Gender] = None, pronoun: Optional[Pronoun] = None, - conjugations: Optional[List[str]] = None, + conjugations: Optional[list[str]] = None, ) -> None: """ :param person (optional): The grammatical person, i.e. first, second or third person. @@ -50,10 +54,10 @@ def __init__( conjugating the auxiliary verb to form certain compound conjugations. """ super().__init__() - self._person = person - self._number = number - self._gender = gender - self._pronoun = pronoun + self._person: Optional[Person] = person + self._number: Optional[Number] = number + self._gender: Optional[Gender] = gender + self._pronoun: Optional[Pronoun] = pronoun if conjugations is not None: self._conjugations = conjugations else: @@ -86,28 +90,30 @@ def __hash__(self) -> int: ) ) - def __getitem__(self, index: int) -> Union[object, str]: - """ - Allows accessing elements using square bracket notation. + @overload + def __getitem__(self, index: int) -> str: ... + + @overload + def __getitem__(self, index: slice) -> Self: ... # type: ignore + + def __getitem__(self, index: int | slice) -> str | Self: # type: ignore + """Allows accessing elements using square bracket notation. + Handles both integer indexing and slicing. """ - if isinstance(index, slice): - # If a slice object is provided, return a new MyCustomList - # containing the sliced portion of the internal data. - return Conjugation( - self.person, - self.number, - self.gender, - self.pronoun, - self._conjugations[index], - ) - elif isinstance(index, int): - # If an integer index is provided, return the element at that index. - # This will automatically raise IndexError if the index is out of range. - return self._conjugations[index] - else: - # Raise a TypeError for unsupported index types. - raise TypeError("Index must be an integer or a slice object.") + match index: + case slice(): + return type(self)( + self._person, + self._number, + self._gender, + self._pronoun, + self._conjugations[index], + ) + case int(): + return self._conjugations[index] + case _: + raise TypeError("Index must be an integer or a slice object.") def __len__(self) -> int: return len(self._conjugations) @@ -142,10 +148,10 @@ def get_pronoun(self) -> Optional[Pronoun]: def set_pronoun(self, value: Pronoun) -> None: self._pronoun = value - def get_conjugations(self) -> List[str]: + def get_conjugations(self) -> list[str]: return self._conjugations - def set_conjugations(self, value: List[str]) -> None: + def set_conjugations(self, value: list[str]) -> None: self._conjugations = value def get_data(self) -> ConjugationData: diff --git a/verbecc/src/defs/types/conjugation/conjugation_data.py b/src/verbecc/core/defs/types/conjugation/conjugation_data.py similarity index 83% rename from verbecc/src/defs/types/conjugation/conjugation_data.py rename to src/verbecc/core/defs/types/conjugation/conjugation_data.py index 98df514..abc1240 100644 --- a/verbecc/src/defs/types/conjugation/conjugation_data.py +++ b/src/verbecc/core/defs/types/conjugation/conjugation_data.py @@ -1,11 +1,11 @@ -from typing import Dict, List, Optional, Tuple, Union +from typing import Optional, Union -from verbecc.src.defs.types.gender import Gender -from verbecc.src.defs.types.person import Person -from verbecc.src.defs.types.number import Number -from verbecc.src.defs.types.pronoun import Pronoun, Pronouns +from verbecc.core.defs.types.gender import Gender +from verbecc.core.defs.types.person import Person +from verbecc.core.defs.types.number import Number +from verbecc.core.defs.types.pronoun import Pronoun -# ConjugationData is a dict of {"p":Person, "n":Number, "g":Gender, "pr":Pronoun, "c":List[Conjugations]} +# ConjugationData is a dict of {"p":Person, "n":Number, "g":Gender, "pr":Pronoun, "c":list[Conjugations]} # # This allows us to have one Conjugation for "tú" and another for "vos" e.g. # {"p":Person.Second, "n":Number.Singular, "g":Gender.m, "pr":"tú", "c":["tú bebes"]], @@ -52,6 +52,6 @@ Optional[Number], Optional[Gender], Optional[Pronoun], - List[str], + list[str], ] -ConjugationData = Dict[ConjugationKey, ConjugationValue] +ConjugationData = dict[ConjugationKey, ConjugationValue] diff --git a/verbecc/src/defs/types/conjugation/mood_conjugation.py b/src/verbecc/core/defs/types/conjugation/mood_conjugation.py similarity index 76% rename from verbecc/src/defs/types/conjugation/mood_conjugation.py rename to src/verbecc/core/defs/types/conjugation/mood_conjugation.py index 502419c..4e4ce50 100644 --- a/verbecc/src/defs/types/conjugation/mood_conjugation.py +++ b/src/verbecc/core/defs/types/conjugation/mood_conjugation.py @@ -1,10 +1,10 @@ -from typing import cast, Dict, Iterable, Optional +from typing import cast, Iterable, Optional -from verbecc.src.defs.types.mood import Mood -from verbecc.src.defs.types.tense import Tense -from verbecc.src.defs.types.conjugation.tense_conjugation import TenseConjugation -from verbecc.src.defs.types.conjugation.abstract_conjugation import AbstractConjugation -from verbecc.src.defs.types.conjugation.mood_conjugation_data import MoodConjugationData +from verbecc.core.defs.types.mood import Mood +from verbecc.core.defs.types.tense import Tense +from verbecc.core.defs.types.conjugation.tense_conjugation import TenseConjugation +from verbecc.core.defs.types.conjugation.abstract_conjugation import AbstractConjugation +from verbecc.core.defs.types.conjugation.mood_conjugation_data import MoodConjugationData class MoodConjugation(AbstractConjugation): @@ -15,11 +15,11 @@ class MoodConjugation(AbstractConjugation): """ def __init__( - self, mood: Mood, data: Optional[Dict[Tense, TenseConjugation]] = None + self, mood: Mood, data: Optional[dict[Tense, TenseConjugation]] = None ) -> None: super().__init__() self._mood = mood - self._data: Dict[Tense, TenseConjugation] = {} + self._data: dict[Tense, TenseConjugation] = {} if data is not None: for k, v in data.items(): v.set_parent(self) @@ -54,6 +54,9 @@ def __iter__(self) -> Iterable[Tense]: def __contains__(self, key: Tense) -> bool: return key in self._data + def get_mood(self) -> Mood: + return self._mood + def get_data(self) -> MoodConjugationData: return {t: tc.get_data() for t, tc in self._data.items()} diff --git a/src/verbecc/core/defs/types/conjugation/mood_conjugation_data.py b/src/verbecc/core/defs/types/conjugation/mood_conjugation_data.py new file mode 100644 index 0000000..38234f2 --- /dev/null +++ b/src/verbecc/core/defs/types/conjugation/mood_conjugation_data.py @@ -0,0 +1,6 @@ +from verbecc.core.defs.types.tense import Tense +from verbecc.core.defs.types.conjugation.tense_conjugation_data import ( + TenseConjugationData, +) + +MoodConjugationData = dict[Tense, TenseConjugationData] diff --git a/verbecc/src/defs/types/conjugation/mood_conjugation_util.py b/src/verbecc/core/defs/types/conjugation/mood_conjugation_util.py similarity index 52% rename from verbecc/src/defs/types/conjugation/mood_conjugation_util.py rename to src/verbecc/core/defs/types/conjugation/mood_conjugation_util.py index d713cb3..da53e72 100644 --- a/verbecc/src/defs/types/conjugation/mood_conjugation_util.py +++ b/src/verbecc/core/defs/types/conjugation/mood_conjugation_util.py @@ -1,4 +1,6 @@ -from verbecc.src.defs.types.conjugation.mood_conjugation import MoodConjugation +from verbecc.core.defs.types.conjugation.mood_conjugation import MoodConjugation +from verbecc.core.defs.types.conjugation.tense_conjugation import TenseConjugation +from verbecc.core.defs.types.tense import Tense class MoodConjugationUtil: @@ -11,9 +13,10 @@ def combine(cls, a: MoodConjugation, b: MoodConjugation) -> MoodConjugation: (MoodConjugation isn't defined until MoodConjugation is initialized). Putting it in a separate file seems preferable to casting. """ - if a._mood != b._mood: + if a.get_mood() != b.get_mood(): raise TypeError("Cannot combine MoodsConjugations with different moods") - combined = {} - for mc in (a, b): - combined.update(mc._data) - return MoodConjugation(a._mood, combined) + combined: dict[Tense, TenseConjugation] = { + tense: a[tense] for tense in a.get_data() + } + combined.update({tense: b[tense] for tense in b.get_data()}) + return MoodConjugation(a.get_mood(), combined) diff --git a/verbecc/src/defs/types/conjugation/moods_conjugation.py b/src/verbecc/core/defs/types/conjugation/moods_conjugation.py similarity index 79% rename from verbecc/src/defs/types/conjugation/moods_conjugation.py rename to src/verbecc/core/defs/types/conjugation/moods_conjugation.py index e8616d6..9ec11e4 100644 --- a/verbecc/src/defs/types/conjugation/moods_conjugation.py +++ b/src/verbecc/core/defs/types/conjugation/moods_conjugation.py @@ -1,9 +1,9 @@ -from typing import cast, Iterable, Dict, Optional +from typing import cast, Iterable, Optional -from verbecc.src.defs.types.mood import Mood -from verbecc.src.defs.types.conjugation.abstract_conjugation import AbstractConjugation -from verbecc.src.defs.types.conjugation.mood_conjugation import MoodConjugation -from verbecc.src.defs.types.conjugation.moods_conjugation_data import ( +from verbecc.core.defs.types.mood import Mood +from verbecc.core.defs.types.conjugation.abstract_conjugation import AbstractConjugation +from verbecc.core.defs.types.conjugation.mood_conjugation import MoodConjugation +from verbecc.core.defs.types.conjugation.moods_conjugation_data import ( MoodsConjugationData, ) @@ -17,10 +17,10 @@ class MoodsConjugation(AbstractConjugation): def __init__( self, - data: Optional[Dict[Mood, MoodConjugation]] = None, + data: Optional[dict[Mood, MoodConjugation]] = None, ) -> None: super().__init__() - self._data: Dict[Mood, MoodConjugation] = {} + self._data: dict[Mood, MoodConjugation] = {} if data is not None: for k, v in data.items(): v.set_parent(self) diff --git a/src/verbecc/core/defs/types/conjugation/moods_conjugation_data.py b/src/verbecc/core/defs/types/conjugation/moods_conjugation_data.py new file mode 100644 index 0000000..35eaffc --- /dev/null +++ b/src/verbecc/core/defs/types/conjugation/moods_conjugation_data.py @@ -0,0 +1,4 @@ +from verbecc.core.defs.types.mood import Mood +from verbecc.core.defs.types.conjugation.mood_conjugation_data import MoodConjugationData + +MoodsConjugationData = dict[Mood, MoodConjugationData] # the "moods" section diff --git a/verbecc/src/defs/types/conjugation/tense_conjugation.py b/src/verbecc/core/defs/types/conjugation/tense_conjugation.py similarity index 83% rename from verbecc/src/defs/types/conjugation/tense_conjugation.py rename to src/verbecc/core/defs/types/conjugation/tense_conjugation.py index 4af05aa..d63f59c 100644 --- a/verbecc/src/defs/types/conjugation/tense_conjugation.py +++ b/src/verbecc/core/defs/types/conjugation/tense_conjugation.py @@ -1,9 +1,9 @@ -from typing import cast, Iterable, Iterator, List, Optional +from typing import cast, Iterable, Iterator, Optional -from verbecc.src.defs.types.tense import Tense -from verbecc.src.defs.types.conjugation.abstract_conjugation import AbstractConjugation -from verbecc.src.defs.types.conjugation.conjugation import Conjugation -from verbecc.src.defs.types.conjugation.tense_conjugation_data import ( +from verbecc.core.defs.types.tense import Tense +from verbecc.core.defs.types.conjugation.abstract_conjugation import AbstractConjugation +from verbecc.core.defs.types.conjugation.conjugation import Conjugation +from verbecc.core.defs.types.conjugation.tense_conjugation_data import ( TenseConjugationData, ) @@ -15,10 +15,10 @@ class TenseConjugation(AbstractConjugation): including alternate conjugations (if applicable). """ - def __init__(self, tense: Tense, data: Optional[List[Conjugation]] = None) -> None: + def __init__(self, tense: Tense, data: Optional[list[Conjugation]] = None) -> None: super().__init__() self._tense = tense - self._data: List[Conjugation] = [] + self._data: list[Conjugation] = [] if data is not None: for c in data: c.set_parent(self) diff --git a/src/verbecc/core/defs/types/conjugation/tense_conjugation_data.py b/src/verbecc/core/defs/types/conjugation/tense_conjugation_data.py new file mode 100644 index 0000000..6805fb7 --- /dev/null +++ b/src/verbecc/core/defs/types/conjugation/tense_conjugation_data.py @@ -0,0 +1,3 @@ +from verbecc.core.defs.types.conjugation.conjugation_data import ConjugationData + +TenseConjugationData = list[ConjugationData] diff --git a/verbecc/src/defs/types/conjugation/verb_info.py b/src/verbecc/core/defs/types/conjugation/verb_info.py similarity index 90% rename from verbecc/src/defs/types/conjugation/verb_info.py rename to src/verbecc/core/defs/types/conjugation/verb_info.py index ee4596a..69b8ec9 100644 --- a/verbecc/src/defs/types/conjugation/verb_info.py +++ b/src/verbecc/core/defs/types/conjugation/verb_info.py @@ -1,6 +1,6 @@ -from verbecc.src.defs.types.conjugation.abstract_conjugation import AbstractConjugation -from verbecc.src.defs.types.conjugation.verb_info_data import VerbInfoData -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 +from verbecc.core.defs.types.conjugation.abstract_conjugation import AbstractConjugation +from verbecc.core.defs.types.conjugation.verb_info_data import VerbInfoData +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 class VerbInfo(AbstractConjugation): @@ -63,7 +63,7 @@ def __hash__(self) -> int: ) def get_data(self) -> VerbInfoData: - ret = { + ret: VerbInfoData = { "infinitive": self.infinitive, "lang": self.lang, "predicted": self.predicted, @@ -84,5 +84,4 @@ def get_str_id(self) -> str: E.g. "fr:parler" """ # This singleton info node represents the root node, so it has no parent. - _str_id = "" return ":".join([str(self.lang), str(self.infinitive)]) diff --git a/src/verbecc/core/defs/types/conjugation/verb_info_data.py b/src/verbecc/core/defs/types/conjugation/verb_info_data.py new file mode 100644 index 0000000..2ba8223 --- /dev/null +++ b/src/verbecc/core/defs/types/conjugation/verb_info_data.py @@ -0,0 +1,3 @@ +from typing import Union + +VerbInfoData = dict[str, Union[str, bool, float]] # the "verb" section diff --git a/verbecc/src/defs/types/data/conjugation_template.py b/src/verbecc/core/defs/types/data/conjugation_template.py similarity index 58% rename from verbecc/src/defs/types/data/conjugation_template.py rename to src/verbecc/core/defs/types/data/conjugation_template.py index 122fc41..4995b57 100644 --- a/verbecc/src/defs/types/data/conjugation_template.py +++ b/src/verbecc/core/defs/types/data/conjugation_template.py @@ -1,9 +1,7 @@ -from typing import Dict - -from verbecc.src.defs.types.data.element import Element -from verbecc.src.defs.types.data.mood_template import MoodTemplate -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 as Lang -from verbecc.src.defs.types.mood import Mood +from verbecc.core.defs.types.data.element import Element +from verbecc.core.defs.types.data.mood_template import MoodTemplate +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 as Lang +from verbecc.core.defs.types.mood import Mood class ConjugationTemplate(Element): @@ -11,7 +9,7 @@ def __init__( self, lang: Lang, name: str, - mood_templates: Dict[Mood, MoodTemplate], + mood_templates: dict[Mood, MoodTemplate], modify_stem: str = "", ) -> None: self.lang = lang diff --git a/verbecc/src/defs/types/data/conjugations.py b/src/verbecc/core/defs/types/data/conjugations.py similarity index 63% rename from verbecc/src/defs/types/data/conjugations.py rename to src/verbecc/core/defs/types/data/conjugations.py index e9ceb82..e0732df 100644 --- a/verbecc/src/defs/types/data/conjugations.py +++ b/src/verbecc/core/defs/types/data/conjugations.py @@ -1,18 +1,18 @@ from bisect import bisect_left -from typing import List, Iterator +from typing import Iterator -from verbecc.src.defs.types.data.element import Element -from verbecc.src.defs.types.data.conjugation_template import ConjugationTemplate -from verbecc.src.defs.types.exceptions import TemplateNotFoundError -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 +from verbecc.core.defs.types.data.element import Element +from verbecc.core.defs.types.data.conjugation_template import ConjugationTemplate +from verbecc.core.defs.types.exceptions import TemplateNotFoundError +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 class Conjugations(Element): def __init__( - self, lang: LangCodeISO639_1, templates: List[ConjugationTemplate] + self, lang: LangCodeISO639_1, templates: list[ConjugationTemplate] ) -> None: self.lang = lang - self._templates: List[ConjugationTemplate] = templates + self._templates: list[ConjugationTemplate] = templates self._keys = [template.name for template in self._templates] def __len__(self) -> int: diff --git a/verbecc/src/defs/types/data/element.py b/src/verbecc/core/defs/types/data/element.py similarity index 100% rename from verbecc/src/defs/types/data/element.py rename to src/verbecc/core/defs/types/data/element.py diff --git a/src/verbecc/core/defs/types/data/mood_template.py b/src/verbecc/core/defs/types/data/mood_template.py new file mode 100644 index 0000000..e38c17d --- /dev/null +++ b/src/verbecc/core/defs/types/data/mood_template.py @@ -0,0 +1,19 @@ +from verbecc.core.defs.types.data.element import Element +from verbecc.core.defs.types.data.tense_template import TenseTemplate +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 as Lang +from verbecc.core.defs.types.mood import Mood +from verbecc.core.defs.types.tense import Tense + + +class MoodTemplate(Element): + def __init__( + self, lang: Lang, mood: Mood, tense_templates: dict[Tense, TenseTemplate] + ) -> None: + self.lang = lang + self.mood = mood + self.tense_templates = tense_templates + + def __repr__(self) -> str: + return ( + f"lang={self.lang} mood={self.mood} tense_templates={self.tense_templates}" + ) diff --git a/verbecc/src/defs/types/data/person_ending.py b/src/verbecc/core/defs/types/data/person_ending.py similarity index 72% rename from verbecc/src/defs/types/data/person_ending.py rename to src/verbecc/core/defs/types/data/person_ending.py index 8b0942b..81a0168 100644 --- a/verbecc/src/defs/types/data/person_ending.py +++ b/src/verbecc/core/defs/types/data/person_ending.py @@ -1,9 +1,9 @@ -from typing import List, Optional +from typing import Optional, cast -from verbecc.src.defs.types.data.element import Element -from verbecc.src.defs.types.person import Person -from verbecc.src.defs.types.number import Number -from verbecc.src.defs.types.gender import Gender +from verbecc.core.defs.types.data.element import Element +from verbecc.core.defs.types.person import Person +from verbecc.core.defs.types.number import Number +from verbecc.core.defs.types.gender import Gender class PersonEnding(Element): @@ -29,14 +29,14 @@ class PersonEnding(Element): def __init__( self, - person: Optional[Person], - number: Optional[Number], - gender: Optional[Gender], - endings: List[str], + person: Optional[Person | str], + number: Optional[Number | str], + gender: Optional[Gender | str], + endings: list[str], ) -> None: - self.person = person - self.number = number - self.gender = gender + self.person = cast(Optional[Person], person) + self.number = cast(Optional[Number], number) + self.gender = cast(Optional[Gender], gender) self.endings = endings def get_person(self) -> Optional[Person]: @@ -48,7 +48,7 @@ def get_number(self) -> Optional[Number]: def get_gender(self) -> Optional[Gender]: return self.gender - def get_endings(self) -> List[str]: + def get_endings(self) -> list[str]: return self.endings def get_ending(self) -> str: diff --git a/verbecc/src/defs/types/data/tense_template.py b/src/verbecc/core/defs/types/data/tense_template.py similarity index 51% rename from verbecc/src/defs/types/data/tense_template.py rename to src/verbecc/core/defs/types/data/tense_template.py index d2fb393..1740fdb 100644 --- a/verbecc/src/defs/types/data/tense_template.py +++ b/src/verbecc/core/defs/types/data/tense_template.py @@ -1,12 +1,10 @@ -from typing import List - -from verbecc.src.defs.types.data.element import Element -from verbecc.src.defs.types.data.person_ending import PersonEnding -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 as Lang -from verbecc.src.defs.types.mood import Mood -from verbecc.src.defs.types.tense import Tense -from verbecc.src.defs.types.person import Person -from verbecc.src.defs.types.number import Number +from verbecc.core.defs.types.data.element import Element +from verbecc.core.defs.types.data.person_ending import PersonEnding +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 as Lang +from verbecc.core.defs.types.mood import Mood +from verbecc.core.defs.types.tense import Tense +from verbecc.core.defs.types.person import Person +from verbecc.core.defs.types.number import Number class TenseTemplate(Element): @@ -14,16 +12,16 @@ class TenseTemplate(Element): def __init__( self, lang: Lang, - mood: Mood, - tense: Tense, - person_endings: List[PersonEnding], + mood: Mood | str, + tense: Tense | str, + person_endings: list[PersonEnding], ) -> None: self.lang = lang self.mood = mood self.tense = tense self.person_endings = person_endings - def get_person_ending(self, person: Person, number: Number) -> PersonEnding: + def get_person_ending(self, person: Person | str, number: Number | str) -> PersonEnding: for pe in self.person_endings: if pe.person == person and pe.number == number: return pe diff --git a/verbecc/src/defs/types/data/verb.py b/src/verbecc/core/defs/types/data/verb.py similarity index 69% rename from verbecc/src/defs/types/data/verb.py rename to src/verbecc/core/defs/types/data/verb.py index c762a88..4c0269f 100644 --- a/verbecc/src/defs/types/data/verb.py +++ b/src/verbecc/core/defs/types/data/verb.py @@ -1,5 +1,5 @@ -from verbecc.src.utils.string_utils import strip_accents -from verbecc.src.defs.types.data.element import Element +from verbecc.core.utils.string_utils import strip_accents +from verbecc.core.defs.types.data.element import Element class Verb(Element): @@ -15,7 +15,10 @@ def __init__( self.impersonal = False def __repr__(self) -> str: - return "infinitive={} infinitive_no_accents={} template={} translation_en={} impersonal={} predicted={} pred_score={}".format( + return ( + "infinitive={} infinitive_no_accents={} template={} translation_en={} " + "impersonal={} predicted={} pred_score={}" + ).format( self.infinitive, self.infinitive_no_accents, self.template, diff --git a/verbecc/src/defs/types/data/verbs.py b/src/verbecc/core/defs/types/data/verbs.py similarity index 82% rename from verbecc/src/defs/types/data/verbs.py rename to src/verbecc/core/defs/types/data/verbs.py index 9fd34ae..2a5ada2 100644 --- a/verbecc/src/defs/types/data/verbs.py +++ b/src/verbecc/core/defs/types/data/verbs.py @@ -1,19 +1,19 @@ from bisect import bisect_left -from typing import Iterator, List +from typing import Iterator -from verbecc.src.utils.logging_utils import LoggingUtils -from verbecc.src.defs.types.data.verb import Verb -from verbecc.src.defs.types.exceptions import VerbNotFoundError -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 -from verbecc.src.mlconjug.predictor import TemplatePredictor -from verbecc.src.utils import string_utils -from verbecc.src.utils.config.verbecc_config_util import VerbeccConfigUtil +from verbecc.core.utils.logging_utils import LoggingUtils +from verbecc.core.defs.types.data.verb import Verb +from verbecc.core.defs.types.exceptions import VerbNotFoundError +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 +from verbecc.core.mlconjug.predictor import TemplatePredictor +from verbecc.core.utils import string_utils +from verbecc.core.utils.config.verbecc_config_util import VerbeccConfigUtil config = VerbeccConfigUtil().load_config() class Verbs: - def __init__(self, lang: LangCodeISO639_1, verbs: List[Verb]) -> None: + def __init__(self, lang: LangCodeISO639_1, verbs: list[Verb]) -> None: self._logger = LoggingUtils.get_logger(self.__class__.__name__) self.lang = lang self._verbs = verbs @@ -69,8 +69,8 @@ def find_verb_by_infinitive(self, infinitive: str) -> Verb: else: raise VerbNotFoundError() - def get_verbs_that_start_with(self, pre: str, max_results: int = 10) -> List[str]: - ret: List[str] = [] + def get_verbs_that_start_with(self, pre: str, max_results: int = 10) -> list[str]: + ret: list[str] = [] pre_no_accents = string_utils.strip_accents(pre.lower()) for verb in self._verbs: if verb.infinitive_no_accents.startswith(pre_no_accents): diff --git a/src/verbecc/core/defs/types/data/xml_types.py b/src/verbecc/core/defs/types/data/xml_types.py new file mode 100644 index 0000000..99c6381 --- /dev/null +++ b/src/verbecc/core/defs/types/data/xml_types.py @@ -0,0 +1,14 @@ +from typing import TypeAlias +from lxml import etree + +""" +Type alias for an XML element, which is an instance of lxml.etree._Element. +This alias is used to provide type hints for functions that work with XML elements. +The XmlElement type is used throughout the codebase to represent XML elements in a type-safe manner +and to improve code readability. +The XmlElementTree type is an alias for lxml.etree._ElementTree, which represents an entire XML document tree. +""" + +XmlParser : TypeAlias = etree.XMLParser +XmlElement : TypeAlias = etree._Element # type: ignore +XmlElementTree : TypeAlias = etree._ElementTree # type: ignore diff --git a/src/verbecc/core/defs/types/exceptions/__init__.py b/src/verbecc/core/defs/types/exceptions/__init__.py new file mode 100644 index 0000000..30c3221 --- /dev/null +++ b/src/verbecc/core/defs/types/exceptions/__init__.py @@ -0,0 +1,9 @@ +from .conjugator_error import ConjugatorError # type: ignore +from .conjugations_parser_error import ConjugationsParserError # type: ignore +from .conjugation_template_error import ConjugationTemplateError # type: ignore +from .invalid_lang_error import InvalidLangError # type: ignore +from .invalid_mood_error import InvalidMoodError # type: ignore +from .invalid_tense_error import InvalidTenseError # type: ignore +from .template_not_found_error import TemplateNotFoundError # type: ignore +from .verb_not_found_error import VerbNotFoundError # type: ignore +from .verbs_parser_error import VerbsParserError # type: ignore \ No newline at end of file diff --git a/verbecc/src/defs/types/exceptions/conjugation_template_error.py b/src/verbecc/core/defs/types/exceptions/conjugation_template_error.py similarity index 100% rename from verbecc/src/defs/types/exceptions/conjugation_template_error.py rename to src/verbecc/core/defs/types/exceptions/conjugation_template_error.py diff --git a/verbecc/src/defs/types/exceptions/conjugations_parser_error.py b/src/verbecc/core/defs/types/exceptions/conjugations_parser_error.py similarity index 100% rename from verbecc/src/defs/types/exceptions/conjugations_parser_error.py rename to src/verbecc/core/defs/types/exceptions/conjugations_parser_error.py diff --git a/verbecc/src/defs/types/exceptions/conjugator_error.py b/src/verbecc/core/defs/types/exceptions/conjugator_error.py similarity index 100% rename from verbecc/src/defs/types/exceptions/conjugator_error.py rename to src/verbecc/core/defs/types/exceptions/conjugator_error.py diff --git a/verbecc/src/defs/types/exceptions/invalid_lang_error.py b/src/verbecc/core/defs/types/exceptions/invalid_lang_error.py similarity index 100% rename from verbecc/src/defs/types/exceptions/invalid_lang_error.py rename to src/verbecc/core/defs/types/exceptions/invalid_lang_error.py diff --git a/verbecc/src/defs/types/exceptions/invalid_mood_error.py b/src/verbecc/core/defs/types/exceptions/invalid_mood_error.py similarity index 100% rename from verbecc/src/defs/types/exceptions/invalid_mood_error.py rename to src/verbecc/core/defs/types/exceptions/invalid_mood_error.py diff --git a/verbecc/src/defs/types/exceptions/invalid_tense_error.py b/src/verbecc/core/defs/types/exceptions/invalid_tense_error.py similarity index 100% rename from verbecc/src/defs/types/exceptions/invalid_tense_error.py rename to src/verbecc/core/defs/types/exceptions/invalid_tense_error.py diff --git a/verbecc/src/defs/types/exceptions/template_not_found_error.py b/src/verbecc/core/defs/types/exceptions/template_not_found_error.py similarity index 100% rename from verbecc/src/defs/types/exceptions/template_not_found_error.py rename to src/verbecc/core/defs/types/exceptions/template_not_found_error.py diff --git a/verbecc/src/defs/types/exceptions/verb_not_found_error.py b/src/verbecc/core/defs/types/exceptions/verb_not_found_error.py similarity index 100% rename from verbecc/src/defs/types/exceptions/verb_not_found_error.py rename to src/verbecc/core/defs/types/exceptions/verb_not_found_error.py diff --git a/verbecc/src/defs/types/exceptions/verbs_parser_error.py b/src/verbecc/core/defs/types/exceptions/verbs_parser_error.py similarity index 100% rename from verbecc/src/defs/types/exceptions/verbs_parser_error.py rename to src/verbecc/core/defs/types/exceptions/verbs_parser_error.py diff --git a/verbecc/src/defs/types/gender.py b/src/verbecc/core/defs/types/gender.py similarity index 100% rename from verbecc/src/defs/types/gender.py rename to src/verbecc/core/defs/types/gender.py diff --git a/verbecc/src/defs/types/lang_code.py b/src/verbecc/core/defs/types/lang_code.py similarity index 100% rename from verbecc/src/defs/types/lang_code.py rename to src/verbecc/core/defs/types/lang_code.py diff --git a/src/verbecc/core/defs/types/lang_specific_options/__init__.py b/src/verbecc/core/defs/types/lang_specific_options/__init__.py new file mode 100644 index 0000000..668a31c --- /dev/null +++ b/src/verbecc/core/defs/types/lang_specific_options/__init__.py @@ -0,0 +1,3 @@ +from .lang_specific_options import LangSpecificOptions # type: ignore +from .lang_specific_options_factory import LangSpecificOptionsFactory # type: ignore + diff --git a/verbecc/src/defs/types/mood/lang/__init__.py b/src/verbecc/core/defs/types/lang_specific_options/lang/__init__.py similarity index 100% rename from verbecc/src/defs/types/mood/lang/__init__.py rename to src/verbecc/core/defs/types/lang_specific_options/lang/__init__.py diff --git a/src/verbecc/core/defs/types/lang_specific_options/lang/es/__init__.py b/src/verbecc/core/defs/types/lang_specific_options/lang/es/__init__.py new file mode 100644 index 0000000..736e962 --- /dev/null +++ b/src/verbecc/core/defs/types/lang_specific_options/lang/es/__init__.py @@ -0,0 +1,2 @@ +from .lang_specific_options_es import LangSpecificOptionsEs # type: ignore +from .voseo_options import VoseoOptions # type: ignore diff --git a/verbecc/src/defs/types/lang_specific_options/lang/es/lang_specific_options_es.py b/src/verbecc/core/defs/types/lang_specific_options/lang/es/lang_specific_options_es.py similarity index 70% rename from verbecc/src/defs/types/lang_specific_options/lang/es/lang_specific_options_es.py rename to src/verbecc/core/defs/types/lang_specific_options/lang/es/lang_specific_options_es.py index 55d5ba9..05b9606 100644 --- a/verbecc/src/defs/types/lang_specific_options/lang/es/lang_specific_options_es.py +++ b/src/verbecc/core/defs/types/lang_specific_options/lang/es/lang_specific_options_es.py @@ -1,7 +1,7 @@ -from verbecc.src.defs.types.lang_specific_options import ( +from verbecc.core.defs.types.lang_specific_options import ( LangSpecificOptions, ) -from verbecc.src.defs.types.lang_specific_options.lang.es.voseo_options import ( +from verbecc.core.defs.types.lang_specific_options.lang.es.voseo_options import ( VoseoOptions, ) diff --git a/verbecc/src/defs/types/lang_specific_options/lang/es/voseo_options.py b/src/verbecc/core/defs/types/lang_specific_options/lang/es/voseo_options.py similarity index 100% rename from verbecc/src/defs/types/lang_specific_options/lang/es/voseo_options.py rename to src/verbecc/core/defs/types/lang_specific_options/lang/es/voseo_options.py diff --git a/verbecc/src/defs/types/lang_specific_options/lang_specific_options.py b/src/verbecc/core/defs/types/lang_specific_options/lang_specific_options.py similarity index 100% rename from verbecc/src/defs/types/lang_specific_options/lang_specific_options.py rename to src/verbecc/core/defs/types/lang_specific_options/lang_specific_options.py diff --git a/verbecc/src/defs/types/lang_specific_options/lang_specific_options_factory.py b/src/verbecc/core/defs/types/lang_specific_options/lang_specific_options_factory.py similarity index 60% rename from verbecc/src/defs/types/lang_specific_options/lang_specific_options_factory.py rename to src/verbecc/core/defs/types/lang_specific_options/lang_specific_options_factory.py index 78138d5..c6b2ab0 100644 --- a/verbecc/src/defs/types/lang_specific_options/lang_specific_options_factory.py +++ b/src/verbecc/core/defs/types/lang_specific_options/lang_specific_options_factory.py @@ -1,10 +1,10 @@ from typing import Optional -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 -from verbecc.src.defs.types.lang_specific_options.lang_specific_options import ( +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 +from verbecc.core.defs.types.lang_specific_options.lang_specific_options import ( LangSpecificOptions, ) -from verbecc.src.defs.types.lang_specific_options.lang.es.lang_specific_options_es import ( +from verbecc.core.defs.types.lang_specific_options.lang.es import ( LangSpecificOptionsEs, ) diff --git a/src/verbecc/core/defs/types/mood/__init__.py b/src/verbecc/core/defs/types/mood/__init__.py new file mode 100644 index 0000000..3a68ff4 --- /dev/null +++ b/src/verbecc/core/defs/types/mood/__init__.py @@ -0,0 +1,3 @@ +from .mood import Mood # type: ignore +from .moods import Moods # type: ignore +from .mood_factory import MoodFactory # type: ignore diff --git a/verbecc/src/defs/types/pronoun/lang/__init__.py b/src/verbecc/core/defs/types/mood/lang/__init__.py similarity index 100% rename from verbecc/src/defs/types/pronoun/lang/__init__.py rename to src/verbecc/core/defs/types/mood/lang/__init__.py diff --git a/src/verbecc/core/defs/types/mood/lang/ca/__init__.py b/src/verbecc/core/defs/types/mood/lang/ca/__init__.py new file mode 100644 index 0000000..26df36b --- /dev/null +++ b/src/verbecc/core/defs/types/mood/lang/ca/__init__.py @@ -0,0 +1 @@ +from .mood_ca import MoodCa # type: ignore \ No newline at end of file diff --git a/verbecc/src/defs/types/mood/lang/mood_ca.py b/src/verbecc/core/defs/types/mood/lang/ca/mood_ca.py similarity index 81% rename from verbecc/src/defs/types/mood/lang/mood_ca.py rename to src/verbecc/core/defs/types/mood/lang/ca/mood_ca.py index 3d78100..9d1d458 100644 --- a/verbecc/src/defs/types/mood/lang/mood_ca.py +++ b/src/verbecc/core/defs/types/mood/lang/ca/mood_ca.py @@ -1,4 +1,4 @@ -from verbecc.src.defs.types.mood.mood import Mood +from verbecc.core.defs.types.mood import Mood class MoodCa(Mood): diff --git a/src/verbecc/core/defs/types/mood/lang/en/__init__.py b/src/verbecc/core/defs/types/mood/lang/en/__init__.py new file mode 100644 index 0000000..a8f31cc --- /dev/null +++ b/src/verbecc/core/defs/types/mood/lang/en/__init__.py @@ -0,0 +1 @@ +from .mood_en import MoodEn # type: ignore \ No newline at end of file diff --git a/verbecc/src/defs/types/mood/lang/mood_en.py b/src/verbecc/core/defs/types/mood/lang/en/mood_en.py similarity index 82% rename from verbecc/src/defs/types/mood/lang/mood_en.py rename to src/verbecc/core/defs/types/mood/lang/en/mood_en.py index 86acc11..67165fc 100644 --- a/verbecc/src/defs/types/mood/lang/mood_en.py +++ b/src/verbecc/core/defs/types/mood/lang/en/mood_en.py @@ -1,4 +1,4 @@ -from verbecc.src.defs.types.mood.mood import Mood +from verbecc.core.defs.types.mood import Mood class MoodEn(Mood): diff --git a/src/verbecc/core/defs/types/mood/lang/es/__init__.py b/src/verbecc/core/defs/types/mood/lang/es/__init__.py new file mode 100644 index 0000000..9884404 --- /dev/null +++ b/src/verbecc/core/defs/types/mood/lang/es/__init__.py @@ -0,0 +1 @@ +from .mood_es import MoodEs # type: ignore \ No newline at end of file diff --git a/verbecc/src/defs/types/mood/lang/mood_es.py b/src/verbecc/core/defs/types/mood/lang/es/mood_es.py similarity index 82% rename from verbecc/src/defs/types/mood/lang/mood_es.py rename to src/verbecc/core/defs/types/mood/lang/es/mood_es.py index 0bbc778..a27d776 100644 --- a/verbecc/src/defs/types/mood/lang/mood_es.py +++ b/src/verbecc/core/defs/types/mood/lang/es/mood_es.py @@ -1,4 +1,4 @@ -from verbecc.src.defs.types.mood.mood import Mood +from verbecc.core.defs.types.mood import Mood class MoodEs(Mood): diff --git a/src/verbecc/core/defs/types/mood/lang/fr/__init__.py b/src/verbecc/core/defs/types/mood/lang/fr/__init__.py new file mode 100644 index 0000000..98aaf04 --- /dev/null +++ b/src/verbecc/core/defs/types/mood/lang/fr/__init__.py @@ -0,0 +1 @@ +from .mood_fr import MoodFr # type: ignore \ No newline at end of file diff --git a/verbecc/src/defs/types/mood/lang/mood_fr.py b/src/verbecc/core/defs/types/mood/lang/fr/mood_fr.py similarity index 79% rename from verbecc/src/defs/types/mood/lang/mood_fr.py rename to src/verbecc/core/defs/types/mood/lang/fr/mood_fr.py index 9751109..352a12a 100644 --- a/verbecc/src/defs/types/mood/lang/mood_fr.py +++ b/src/verbecc/core/defs/types/mood/lang/fr/mood_fr.py @@ -1,4 +1,4 @@ -from verbecc.src.defs.types.mood.mood import Mood +from verbecc.core.defs.types.mood import Mood class MoodFr(Mood): diff --git a/src/verbecc/core/defs/types/mood/lang/it/__init__.py b/src/verbecc/core/defs/types/mood/lang/it/__init__.py new file mode 100644 index 0000000..1bc0a42 --- /dev/null +++ b/src/verbecc/core/defs/types/mood/lang/it/__init__.py @@ -0,0 +1 @@ +from .mood_it import MoodIt # type: ignore \ No newline at end of file diff --git a/verbecc/src/defs/types/mood/lang/mood_it.py b/src/verbecc/core/defs/types/mood/lang/it/mood_it.py similarity index 80% rename from verbecc/src/defs/types/mood/lang/mood_it.py rename to src/verbecc/core/defs/types/mood/lang/it/mood_it.py index 3d445c1..dd2c6c7 100644 --- a/verbecc/src/defs/types/mood/lang/mood_it.py +++ b/src/verbecc/core/defs/types/mood/lang/it/mood_it.py @@ -1,4 +1,4 @@ -from verbecc.src.defs.types.mood.mood import Mood +from verbecc.core.defs.types.mood import Mood class MoodIt(Mood): diff --git a/src/verbecc/core/defs/types/mood/lang/pt/__init__.py b/src/verbecc/core/defs/types/mood/lang/pt/__init__.py new file mode 100644 index 0000000..b142f1c --- /dev/null +++ b/src/verbecc/core/defs/types/mood/lang/pt/__init__.py @@ -0,0 +1 @@ +from .mood_pt import MoodPt # type: ignore \ No newline at end of file diff --git a/verbecc/src/defs/types/mood/lang/mood_pt.py b/src/verbecc/core/defs/types/mood/lang/pt/mood_pt.py similarity index 82% rename from verbecc/src/defs/types/mood/lang/mood_pt.py rename to src/verbecc/core/defs/types/mood/lang/pt/mood_pt.py index 183f019..011b8a2 100644 --- a/verbecc/src/defs/types/mood/lang/mood_pt.py +++ b/src/verbecc/core/defs/types/mood/lang/pt/mood_pt.py @@ -1,4 +1,4 @@ -from verbecc.src.defs.types.mood.mood import Mood +from verbecc.core.defs.types.mood import Mood class MoodPt(Mood): diff --git a/src/verbecc/core/defs/types/mood/lang/ro/__init__.py b/src/verbecc/core/defs/types/mood/lang/ro/__init__.py new file mode 100644 index 0000000..0ae7a40 --- /dev/null +++ b/src/verbecc/core/defs/types/mood/lang/ro/__init__.py @@ -0,0 +1 @@ +from .mood_ro import MoodRo # type: ignore \ No newline at end of file diff --git a/verbecc/src/defs/types/mood/lang/mood_ro.py b/src/verbecc/core/defs/types/mood/lang/ro/mood_ro.py similarity index 87% rename from verbecc/src/defs/types/mood/lang/mood_ro.py rename to src/verbecc/core/defs/types/mood/lang/ro/mood_ro.py index fd48b36..c42dc3f 100644 --- a/verbecc/src/defs/types/mood/lang/mood_ro.py +++ b/src/verbecc/core/defs/types/mood/lang/ro/mood_ro.py @@ -1,4 +1,4 @@ -from verbecc.src.defs.types.mood.mood import Mood +from verbecc.core.defs.types.mood import Mood class MoodRo(Mood): diff --git a/verbecc/src/defs/types/mood/mood.py b/src/verbecc/core/defs/types/mood/mood.py similarity index 100% rename from verbecc/src/defs/types/mood/mood.py rename to src/verbecc/core/defs/types/mood/mood.py diff --git a/verbecc/src/defs/types/mood/mood_factory.py b/src/verbecc/core/defs/types/mood/mood_factory.py similarity index 80% rename from verbecc/src/defs/types/mood/mood_factory.py rename to src/verbecc/core/defs/types/mood/mood_factory.py index 6e756c2..54987b1 100644 --- a/verbecc/src/defs/types/mood/mood_factory.py +++ b/src/verbecc/core/defs/types/mood/mood_factory.py @@ -1,5 +1,5 @@ -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 as Lang -from verbecc.src.defs.types.mood import Mood, Moods +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 as Lang +from verbecc.core.defs.types.mood import Mood, Moods class MoodFactory: diff --git a/src/verbecc/core/defs/types/mood/moods.py b/src/verbecc/core/defs/types/mood/moods.py new file mode 100644 index 0000000..328f357 --- /dev/null +++ b/src/verbecc/core/defs/types/mood/moods.py @@ -0,0 +1,17 @@ +from verbecc.core.defs.types.mood.lang.ca import MoodCa +from verbecc.core.defs.types.mood.lang.en import MoodEn +from verbecc.core.defs.types.mood.lang.es import MoodEs +from verbecc.core.defs.types.mood.lang.fr import MoodFr +from verbecc.core.defs.types.mood.lang.it import MoodIt +from verbecc.core.defs.types.mood.lang.pt import MoodPt +from verbecc.core.defs.types.mood.lang.ro import MoodRo + + +class Moods: + ca = MoodCa + en = MoodEn + es = MoodEs + fr = MoodFr + it = MoodIt + pt = MoodPt + ro = MoodRo diff --git a/verbecc/src/defs/types/number.py b/src/verbecc/core/defs/types/number.py similarity index 100% rename from verbecc/src/defs/types/number.py rename to src/verbecc/core/defs/types/number.py diff --git a/verbecc/src/defs/types/participle_inflection.py b/src/verbecc/core/defs/types/participle_inflection.py similarity index 70% rename from verbecc/src/defs/types/participle_inflection.py rename to src/verbecc/core/defs/types/participle_inflection.py index 8ccec6d..9c88bef 100644 --- a/verbecc/src/defs/types/participle_inflection.py +++ b/src/verbecc/core/defs/types/participle_inflection.py @@ -1,8 +1,7 @@ -import sys from enum import Enum -from verbecc.src.defs.types.gender import Gender -from verbecc.src.defs.types.number import Number +from verbecc.core.defs.types.gender import Gender +from verbecc.core.defs.types.number import Number class ParticipleInflection(Enum): diff --git a/verbecc/src/defs/types/person.py b/src/verbecc/core/defs/types/person.py similarity index 100% rename from verbecc/src/defs/types/person.py rename to src/verbecc/core/defs/types/person.py diff --git a/src/verbecc/core/defs/types/pronoun/__init__.py b/src/verbecc/core/defs/types/pronoun/__init__.py new file mode 100644 index 0000000..2d3cd6b --- /dev/null +++ b/src/verbecc/core/defs/types/pronoun/__init__.py @@ -0,0 +1,4 @@ +from .pronoun import Pronoun # type: ignore +from .pronouns import Pronouns # type: ignore +from .pronoun_factory import PronounFactory # type: ignore +from .lang import * \ No newline at end of file diff --git a/src/verbecc/core/defs/types/pronoun/lang/ca/__init__.py b/src/verbecc/core/defs/types/pronoun/lang/ca/__init__.py new file mode 100644 index 0000000..a0d35be --- /dev/null +++ b/src/verbecc/core/defs/types/pronoun/lang/ca/__init__.py @@ -0,0 +1 @@ +from .pronoun_ca import PronounCa # type: ignore \ No newline at end of file diff --git a/verbecc/src/defs/types/pronoun/lang/pronoun_ca.py b/src/verbecc/core/defs/types/pronoun/lang/ca/pronoun_ca.py similarity index 75% rename from verbecc/src/defs/types/pronoun/lang/pronoun_ca.py rename to src/verbecc/core/defs/types/pronoun/lang/ca/pronoun_ca.py index 834d4c5..cfcdb4d 100644 --- a/verbecc/src/defs/types/pronoun/lang/pronoun_ca.py +++ b/src/verbecc/core/defs/types/pronoun/lang/ca/pronoun_ca.py @@ -1,4 +1,4 @@ -from verbecc.src.defs.types.pronoun.pronoun import Pronoun +from verbecc.core.defs.types.pronoun.pronoun import Pronoun class PronounCa(Pronoun): diff --git a/src/verbecc/core/defs/types/pronoun/lang/en/__init__.py b/src/verbecc/core/defs/types/pronoun/lang/en/__init__.py new file mode 100644 index 0000000..20d5caa --- /dev/null +++ b/src/verbecc/core/defs/types/pronoun/lang/en/__init__.py @@ -0,0 +1 @@ +from .pronoun_en import PronounEn # type: ignore \ No newline at end of file diff --git a/verbecc/src/defs/types/pronoun/lang/pronoun_en.py b/src/verbecc/core/defs/types/pronoun/lang/en/pronoun_en.py similarity index 69% rename from verbecc/src/defs/types/pronoun/lang/pronoun_en.py rename to src/verbecc/core/defs/types/pronoun/lang/en/pronoun_en.py index 9d2af4d..9a83208 100644 --- a/verbecc/src/defs/types/pronoun/lang/pronoun_en.py +++ b/src/verbecc/core/defs/types/pronoun/lang/en/pronoun_en.py @@ -1,4 +1,4 @@ -from verbecc.src.defs.types.pronoun.pronoun import Pronoun +from verbecc.core.defs.types.pronoun.pronoun import Pronoun class PronounEn(Pronoun): diff --git a/src/verbecc/core/defs/types/pronoun/lang/es/__init__.py b/src/verbecc/core/defs/types/pronoun/lang/es/__init__.py new file mode 100644 index 0000000..b3ccfbf --- /dev/null +++ b/src/verbecc/core/defs/types/pronoun/lang/es/__init__.py @@ -0,0 +1 @@ +from .pronoun_es import PronounEs # type: ignore \ No newline at end of file diff --git a/verbecc/src/defs/types/pronoun/lang/pronoun_es.py b/src/verbecc/core/defs/types/pronoun/lang/es/pronoun_es.py similarity index 80% rename from verbecc/src/defs/types/pronoun/lang/pronoun_es.py rename to src/verbecc/core/defs/types/pronoun/lang/es/pronoun_es.py index 507deb1..c3cd8cc 100644 --- a/verbecc/src/defs/types/pronoun/lang/pronoun_es.py +++ b/src/verbecc/core/defs/types/pronoun/lang/es/pronoun_es.py @@ -1,4 +1,4 @@ -from verbecc.src.defs.types.pronoun.pronoun import Pronoun +from verbecc.core.defs.types.pronoun.pronoun import Pronoun class PronounEs(Pronoun): diff --git a/src/verbecc/core/defs/types/pronoun/lang/fr/__init__.py b/src/verbecc/core/defs/types/pronoun/lang/fr/__init__.py new file mode 100644 index 0000000..bd6ded8 --- /dev/null +++ b/src/verbecc/core/defs/types/pronoun/lang/fr/__init__.py @@ -0,0 +1 @@ +from .pronoun_fr import PronounFr # type: ignore \ No newline at end of file diff --git a/verbecc/src/defs/types/pronoun/lang/pronoun_fr.py b/src/verbecc/core/defs/types/pronoun/lang/fr/pronoun_fr.py similarity index 74% rename from verbecc/src/defs/types/pronoun/lang/pronoun_fr.py rename to src/verbecc/core/defs/types/pronoun/lang/fr/pronoun_fr.py index ebe0369..f023a52 100644 --- a/verbecc/src/defs/types/pronoun/lang/pronoun_fr.py +++ b/src/verbecc/core/defs/types/pronoun/lang/fr/pronoun_fr.py @@ -1,4 +1,4 @@ -from verbecc.src.defs.types.pronoun.pronoun import Pronoun +from verbecc.core.defs.types.pronoun.pronoun import Pronoun class PronounFr(Pronoun): diff --git a/src/verbecc/core/defs/types/pronoun/lang/it/__init__.py b/src/verbecc/core/defs/types/pronoun/lang/it/__init__.py new file mode 100644 index 0000000..b4d8204 --- /dev/null +++ b/src/verbecc/core/defs/types/pronoun/lang/it/__init__.py @@ -0,0 +1 @@ +from .pronoun_it import PronounIt # type: ignore \ No newline at end of file diff --git a/verbecc/src/defs/types/pronoun/lang/pronoun_it.py b/src/verbecc/core/defs/types/pronoun/lang/it/pronoun_it.py similarity index 69% rename from verbecc/src/defs/types/pronoun/lang/pronoun_it.py rename to src/verbecc/core/defs/types/pronoun/lang/it/pronoun_it.py index e50a06a..9ad353b 100644 --- a/verbecc/src/defs/types/pronoun/lang/pronoun_it.py +++ b/src/verbecc/core/defs/types/pronoun/lang/it/pronoun_it.py @@ -1,4 +1,4 @@ -from verbecc.src.defs.types.pronoun.pronoun import Pronoun +from verbecc.core.defs.types.pronoun.pronoun import Pronoun class PronounIt(Pronoun): diff --git a/src/verbecc/core/defs/types/pronoun/lang/pt/__init__.py b/src/verbecc/core/defs/types/pronoun/lang/pt/__init__.py new file mode 100644 index 0000000..8645c10 --- /dev/null +++ b/src/verbecc/core/defs/types/pronoun/lang/pt/__init__.py @@ -0,0 +1 @@ +from .pronoun_pt import PronounPt # type: ignore \ No newline at end of file diff --git a/verbecc/src/defs/types/pronoun/lang/pronoun_pt.py b/src/verbecc/core/defs/types/pronoun/lang/pt/pronoun_pt.py similarity index 77% rename from verbecc/src/defs/types/pronoun/lang/pronoun_pt.py rename to src/verbecc/core/defs/types/pronoun/lang/pt/pronoun_pt.py index 992b75c..56a623d 100644 --- a/verbecc/src/defs/types/pronoun/lang/pronoun_pt.py +++ b/src/verbecc/core/defs/types/pronoun/lang/pt/pronoun_pt.py @@ -1,4 +1,4 @@ -from verbecc.src.defs.types.pronoun.pronoun import Pronoun +from verbecc.core.defs.types.pronoun.pronoun import Pronoun class PronounPt(Pronoun): diff --git a/src/verbecc/core/defs/types/pronoun/lang/ro/__init__.py b/src/verbecc/core/defs/types/pronoun/lang/ro/__init__.py new file mode 100644 index 0000000..c5cedf7 --- /dev/null +++ b/src/verbecc/core/defs/types/pronoun/lang/ro/__init__.py @@ -0,0 +1 @@ +from .pronoun_ro import PronounRo # type: ignore \ No newline at end of file diff --git a/verbecc/src/defs/types/pronoun/lang/pronoun_ro.py b/src/verbecc/core/defs/types/pronoun/lang/ro/pronoun_ro.py similarity index 70% rename from verbecc/src/defs/types/pronoun/lang/pronoun_ro.py rename to src/verbecc/core/defs/types/pronoun/lang/ro/pronoun_ro.py index 74d6e8a..6cd2c5d 100644 --- a/verbecc/src/defs/types/pronoun/lang/pronoun_ro.py +++ b/src/verbecc/core/defs/types/pronoun/lang/ro/pronoun_ro.py @@ -1,4 +1,4 @@ -from verbecc.src.defs.types.pronoun.pronoun import Pronoun +from verbecc.core.defs.types.pronoun.pronoun import Pronoun class PronounRo(Pronoun): diff --git a/verbecc/src/defs/types/pronoun/pronoun.py b/src/verbecc/core/defs/types/pronoun/pronoun.py similarity index 100% rename from verbecc/src/defs/types/pronoun/pronoun.py rename to src/verbecc/core/defs/types/pronoun/pronoun.py diff --git a/verbecc/src/defs/types/pronoun/pronoun_factory.py b/src/verbecc/core/defs/types/pronoun/pronoun_factory.py similarity index 73% rename from verbecc/src/defs/types/pronoun/pronoun_factory.py rename to src/verbecc/core/defs/types/pronoun/pronoun_factory.py index fc71a47..ddb2a2b 100644 --- a/verbecc/src/defs/types/pronoun/pronoun_factory.py +++ b/src/verbecc/core/defs/types/pronoun/pronoun_factory.py @@ -1,6 +1,6 @@ -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 as Lang -from verbecc.src.defs.types.pronoun.pronoun import Pronoun -from verbecc.src.defs.types.pronoun.pronouns import Pronouns +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 as Lang +from verbecc.core.defs.types.pronoun.pronoun import Pronoun +from verbecc.core.defs.types.pronoun.pronouns import Pronouns class PronounFactory: diff --git a/src/verbecc/core/defs/types/pronoun/pronouns.py b/src/verbecc/core/defs/types/pronoun/pronouns.py new file mode 100644 index 0000000..763b2ba --- /dev/null +++ b/src/verbecc/core/defs/types/pronoun/pronouns.py @@ -0,0 +1,17 @@ +from verbecc.core.defs.types.pronoun.lang.ca import PronounCa +from verbecc.core.defs.types.pronoun.lang.en import PronounEn +from verbecc.core.defs.types.pronoun.lang.es import PronounEs +from verbecc.core.defs.types.pronoun.lang.fr import PronounFr +from verbecc.core.defs.types.pronoun.lang.it import PronounIt +from verbecc.core.defs.types.pronoun.lang.pt import PronounPt +from verbecc.core.defs.types.pronoun.lang.ro import PronounRo + + +class Pronouns: + ca = PronounCa + en = PronounEn + es = PronounEs + fr = PronounFr + it = PronounIt + pt = PronounPt + ro = PronounRo diff --git a/src/verbecc/core/defs/types/tense/__init__.py b/src/verbecc/core/defs/types/tense/__init__.py new file mode 100644 index 0000000..efd4ee1 --- /dev/null +++ b/src/verbecc/core/defs/types/tense/__init__.py @@ -0,0 +1,3 @@ +from .tense import Tense # type: ignore +from .tenses import Tenses # type: ignore +from .tense_factory import TenseFactory # type: ignore diff --git a/verbecc/src/defs/types/tense/lang/__init__.py b/src/verbecc/core/defs/types/tense/lang/__init__.py similarity index 100% rename from verbecc/src/defs/types/tense/lang/__init__.py rename to src/verbecc/core/defs/types/tense/lang/__init__.py diff --git a/src/verbecc/core/defs/types/tense/lang/ca/__init__.py b/src/verbecc/core/defs/types/tense/lang/ca/__init__.py new file mode 100644 index 0000000..c175773 --- /dev/null +++ b/src/verbecc/core/defs/types/tense/lang/ca/__init__.py @@ -0,0 +1 @@ +from .tense_ca import TenseCa # type: ignore \ No newline at end of file diff --git a/verbecc/src/defs/types/tense/lang/tense_ca.py b/src/verbecc/core/defs/types/tense/lang/ca/tense_ca.py similarity index 91% rename from verbecc/src/defs/types/tense/lang/tense_ca.py rename to src/verbecc/core/defs/types/tense/lang/ca/tense_ca.py index f620323..134a62c 100644 --- a/verbecc/src/defs/types/tense/lang/tense_ca.py +++ b/src/verbecc/core/defs/types/tense/lang/ca/tense_ca.py @@ -1,4 +1,4 @@ -from verbecc.src.defs.types.tense.tense import Tense +from verbecc.core.defs.types.tense import Tense class TenseCa(Tense): diff --git a/src/verbecc/core/defs/types/tense/lang/en/__init__.py b/src/verbecc/core/defs/types/tense/lang/en/__init__.py new file mode 100644 index 0000000..87e9828 --- /dev/null +++ b/src/verbecc/core/defs/types/tense/lang/en/__init__.py @@ -0,0 +1 @@ +from .tense_en import TenseEn # type: ignore \ No newline at end of file diff --git a/verbecc/src/defs/types/tense/lang/tense_en.py b/src/verbecc/core/defs/types/tense/lang/en/tense_en.py similarity index 92% rename from verbecc/src/defs/types/tense/lang/tense_en.py rename to src/verbecc/core/defs/types/tense/lang/en/tense_en.py index 86bf225..734f3ed 100644 --- a/verbecc/src/defs/types/tense/lang/tense_en.py +++ b/src/verbecc/core/defs/types/tense/lang/en/tense_en.py @@ -1,4 +1,4 @@ -from verbecc.src.defs.types.tense.tense import Tense +from verbecc.core.defs.types.tense import Tense class TenseEn(Tense): diff --git a/src/verbecc/core/defs/types/tense/lang/es/__init__.py b/src/verbecc/core/defs/types/tense/lang/es/__init__.py new file mode 100644 index 0000000..1e680d8 --- /dev/null +++ b/src/verbecc/core/defs/types/tense/lang/es/__init__.py @@ -0,0 +1 @@ +from .tense_es import TenseEs # type: ignore \ No newline at end of file diff --git a/verbecc/src/defs/types/tense/lang/tense_es.py b/src/verbecc/core/defs/types/tense/lang/es/tense_es.py similarity index 94% rename from verbecc/src/defs/types/tense/lang/tense_es.py rename to src/verbecc/core/defs/types/tense/lang/es/tense_es.py index 5bd3a2c..75ca480 100644 --- a/verbecc/src/defs/types/tense/lang/tense_es.py +++ b/src/verbecc/core/defs/types/tense/lang/es/tense_es.py @@ -1,4 +1,4 @@ -from verbecc.src.defs.types.tense.tense import Tense +from verbecc.core.defs.types.tense import Tense class TenseEs(Tense): diff --git a/src/verbecc/core/defs/types/tense/lang/fr/__init__.py b/src/verbecc/core/defs/types/tense/lang/fr/__init__.py new file mode 100644 index 0000000..8eb1e4e --- /dev/null +++ b/src/verbecc/core/defs/types/tense/lang/fr/__init__.py @@ -0,0 +1 @@ +from .tense_fr import TenseFr # type: ignore \ No newline at end of file diff --git a/verbecc/src/defs/types/tense/lang/tense_fr.py b/src/verbecc/core/defs/types/tense/lang/fr/tense_fr.py similarity index 91% rename from verbecc/src/defs/types/tense/lang/tense_fr.py rename to src/verbecc/core/defs/types/tense/lang/fr/tense_fr.py index 6767bed..8d135c4 100644 --- a/verbecc/src/defs/types/tense/lang/tense_fr.py +++ b/src/verbecc/core/defs/types/tense/lang/fr/tense_fr.py @@ -1,4 +1,4 @@ -from verbecc.src.defs.types.tense.tense import Tense +from verbecc.core.defs.types.tense import Tense class TenseFr(Tense): diff --git a/src/verbecc/core/defs/types/tense/lang/it/__init__.py b/src/verbecc/core/defs/types/tense/lang/it/__init__.py new file mode 100644 index 0000000..607c933 --- /dev/null +++ b/src/verbecc/core/defs/types/tense/lang/it/__init__.py @@ -0,0 +1 @@ +from .tense_it import TenseIt # type: ignore \ No newline at end of file diff --git a/verbecc/src/defs/types/tense/lang/tense_it.py b/src/verbecc/core/defs/types/tense/lang/it/tense_it.py similarity index 91% rename from verbecc/src/defs/types/tense/lang/tense_it.py rename to src/verbecc/core/defs/types/tense/lang/it/tense_it.py index 7cfd6b2..8809961 100644 --- a/verbecc/src/defs/types/tense/lang/tense_it.py +++ b/src/verbecc/core/defs/types/tense/lang/it/tense_it.py @@ -1,4 +1,4 @@ -from verbecc.src.defs.types.tense.tense import Tense +from verbecc.core.defs.types.tense import Tense class TenseIt(Tense): diff --git a/src/verbecc/core/defs/types/tense/lang/pt/__init__.py b/src/verbecc/core/defs/types/tense/lang/pt/__init__.py new file mode 100644 index 0000000..7552d6c --- /dev/null +++ b/src/verbecc/core/defs/types/tense/lang/pt/__init__.py @@ -0,0 +1 @@ +from .tense_pt import TensePt # type: ignore \ No newline at end of file diff --git a/verbecc/src/defs/types/tense/lang/tense_pt.py b/src/verbecc/core/defs/types/tense/lang/pt/tense_pt.py similarity index 95% rename from verbecc/src/defs/types/tense/lang/tense_pt.py rename to src/verbecc/core/defs/types/tense/lang/pt/tense_pt.py index facb96e..f2f961c 100644 --- a/verbecc/src/defs/types/tense/lang/tense_pt.py +++ b/src/verbecc/core/defs/types/tense/lang/pt/tense_pt.py @@ -1,4 +1,4 @@ -from verbecc.src.defs.types.tense.tense import Tense +from verbecc.core.defs.types.tense import Tense class TensePt(Tense): diff --git a/src/verbecc/core/defs/types/tense/lang/ro/__init__.py b/src/verbecc/core/defs/types/tense/lang/ro/__init__.py new file mode 100644 index 0000000..646341e --- /dev/null +++ b/src/verbecc/core/defs/types/tense/lang/ro/__init__.py @@ -0,0 +1 @@ +from .tense_ro import TenseRo # type: ignore \ No newline at end of file diff --git a/verbecc/src/defs/types/tense/lang/tense_ro.py b/src/verbecc/core/defs/types/tense/lang/ro/tense_ro.py similarity index 91% rename from verbecc/src/defs/types/tense/lang/tense_ro.py rename to src/verbecc/core/defs/types/tense/lang/ro/tense_ro.py index 94c705c..382ed1c 100644 --- a/verbecc/src/defs/types/tense/lang/tense_ro.py +++ b/src/verbecc/core/defs/types/tense/lang/ro/tense_ro.py @@ -1,4 +1,4 @@ -from verbecc.src.defs.types.tense.tense import Tense +from verbecc.core.defs.types.tense import Tense class TenseRo(Tense): diff --git a/verbecc/src/defs/types/tense/tense.py b/src/verbecc/core/defs/types/tense/tense.py similarity index 100% rename from verbecc/src/defs/types/tense/tense.py rename to src/verbecc/core/defs/types/tense/tense.py diff --git a/verbecc/src/defs/types/tense/tense_factory.py b/src/verbecc/core/defs/types/tense/tense_factory.py similarity index 74% rename from verbecc/src/defs/types/tense/tense_factory.py rename to src/verbecc/core/defs/types/tense/tense_factory.py index eb47afd..9ad9656 100644 --- a/verbecc/src/defs/types/tense/tense_factory.py +++ b/src/verbecc/core/defs/types/tense/tense_factory.py @@ -1,6 +1,6 @@ -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 as Lang -from verbecc.src.defs.types.tense.tense import Tense -from verbecc.src.defs.types.tense.tenses import Tenses +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 as Lang +from verbecc.core.defs.types.tense import Tense +from verbecc.core.defs.types.tense import Tenses class TenseFactory: diff --git a/src/verbecc/core/defs/types/tense/tenses.py b/src/verbecc/core/defs/types/tense/tenses.py new file mode 100644 index 0000000..5a94c1d --- /dev/null +++ b/src/verbecc/core/defs/types/tense/tenses.py @@ -0,0 +1,17 @@ +from verbecc.core.defs.types.tense.lang.ca import TenseCa +from verbecc.core.defs.types.tense.lang.en import TenseEn +from verbecc.core.defs.types.tense.lang.es import TenseEs +from verbecc.core.defs.types.tense.lang.fr import TenseFr +from verbecc.core.defs.types.tense.lang.it import TenseIt +from verbecc.core.defs.types.tense.lang.pt import TensePt +from verbecc.core.defs.types.tense.lang.ro import TenseRo + + +class Tenses: + ca = TenseCa + en = TenseEn + es = TenseEs + fr = TenseFr + it = TenseIt + pt = TensePt + ro = TenseRo diff --git a/src/verbecc/core/inflectors/__init__.py b/src/verbecc/core/inflectors/__init__.py new file mode 100644 index 0000000..e66b7e0 --- /dev/null +++ b/src/verbecc/core/inflectors/__init__.py @@ -0,0 +1 @@ +from .lang import * \ No newline at end of file diff --git a/verbecc/src/inflectors/inflector.py b/src/verbecc/core/inflectors/inflector.py similarity index 84% rename from verbecc/src/inflectors/inflector.py rename to src/verbecc/core/inflectors/inflector.py index e85b90f..dbc76af 100755 --- a/verbecc/src/inflectors/inflector.py +++ b/src/verbecc/core/inflectors/inflector.py @@ -1,25 +1,25 @@ from abc import ABC, abstractmethod -from typing import Dict, List, Tuple, Optional - -from verbecc.src.utils.logging_utils import LoggingUtils -from verbecc.src.conjugator.conjugation_object import ConjugationObjects -from verbecc.src.defs.constants.grammar_defines import PARTICIPLE_INFLECTIONS -from verbecc.src.defs.types.data.conjugation_template import ConjugationTemplate -from verbecc.src.defs.types.data.person_ending import PersonEnding -from verbecc.src.defs.types.data.tense_template import TenseTemplate -from verbecc.src.defs.types.data.verb import Verb -from verbecc.src.defs.types.data.verbs import Verbs -from verbecc.src.defs.types.exceptions import ConjugatorError -from verbecc.src.defs.types.gender import Gender -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 -from verbecc.src.defs.types.mood import Mood, Moods -from verbecc.src.defs.types.participle_inflection import ParticipleInflection -from verbecc.src.defs.types.person import Person -from verbecc.src.defs.types.number import Number -from verbecc.src.defs.types.tense import Tense, Tenses -from verbecc.src.defs.types.pronoun import Pronoun, Pronouns -from verbecc.src.parsers.conjugations_parser import ConjugationsParser -from verbecc.src.parsers.verbs_parser import VerbsParser +from typing import Tuple, Optional + +from verbecc.core.utils.logging_utils import LoggingUtils +from verbecc.core.conjugator.conjugation_object import ConjugationObjects +from verbecc.core.defs.constants.grammar_defines import PARTICIPLE_INFLECTIONS +from verbecc.core.defs.types.data.conjugation_template import ConjugationTemplate +from verbecc.core.defs.types.data.person_ending import PersonEnding +from verbecc.core.defs.types.data.tense_template import TenseTemplate +from verbecc.core.defs.types.data.verb import Verb +from verbecc.core.defs.types.data.verbs import Verbs +from verbecc.core.defs.types.exceptions import ConjugatorError +from verbecc.core.defs.types.gender import Gender +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 +from verbecc.core.defs.types.mood import Mood, Moods +from verbecc.core.defs.types.participle_inflection import ParticipleInflection +from verbecc.core.defs.types.person import Person +from verbecc.core.defs.types.number import Number +from verbecc.core.defs.types.tense import Tense, Tenses +from verbecc.core.defs.types.pronoun import Pronoun +from verbecc.core.parsers.conjugations_parser import ConjugationsParser +from verbecc.core.parsers.verbs_parser import VerbsParser class Inflector(ABC): @@ -39,16 +39,16 @@ def __init__(self) -> None: def get_lang(self) -> LangCodeISO639_1: raise NotImplementedError() - def get_verbs(self) -> List[Verb]: + def get_verbs(self) -> list[Verb]: return list(self._verbs) - def get_infinitives(self) -> List[str]: + def get_infinitives(self) -> list[str]: return self._verbs.infinitives - def get_templates(self) -> List[ConjugationTemplate]: + def get_templates(self) -> list[ConjugationTemplate]: return list(self._conjugations) - def get_template_names(self) -> List[str]: + def get_template_names(self) -> list[str]: return [t.name for t in self._conjugations] def find_verb_by_infinitive(self, infinitive: str) -> Verb: @@ -57,7 +57,7 @@ def find_verb_by_infinitive(self, infinitive: str) -> Verb: def find_template(self, name: str) -> ConjugationTemplate: return self._conjugations.find_template(name) - def get_verbs_that_start_with(self, query: str, max_results: int) -> List[str]: + def get_verbs_that_start_with(self, query: str, max_results: int) -> list[str]: return self._verbs.get_verbs_that_start_with(query.lower(), max_results) def get_verb_stem_from_template_name( @@ -77,7 +77,7 @@ def get_verb_stem_from_template_name( return infinitive[: len(infinitive) - len(template_ending)] def verb_can_be_reflexive(self, infinitive: str) -> bool: - return not self._is_impersonal_verb(infinitive) + return not self.private_is_impersonal_verb(infinitive) def split_reflexive(self, infinitive: str) -> Tuple[bool, str]: """ @@ -105,13 +105,13 @@ def split_reflexive(self, infinitive: str) -> Tuple[bool, str]: def add_reflexive_pronoun(self, s: str) -> str: return s - def add_subjunctive_relative_pronoun(self, s: str, tense: Tense) -> str: + def add_subjunctive_relative_pronoun(self, s: str, tense: Tense | str | None) -> str: return s def auxiliary_verb_uses_alternate_conjugation(self, tense: Tense) -> bool: return False - def get_tenses_conjugated_without_pronouns(self) -> List[Tense]: + def get_tenses_conjugated_without_pronouns(self) -> list[Tense]: return [] def get_auxiliary_verb( @@ -155,7 +155,7 @@ def get_alternate_hv_inflection(self, s: str) -> str: @abstractmethod def get_compound_conjugations_aux_verb_map( self, - ) -> Dict[Mood, Dict[Tense, Tuple[Mood, Tense]]]: + ) -> dict[Mood, dict[Tense, Tuple[Mood, Tense]]]: """Returns a map of the tense of the helping verb for each compound mood and tense""" raise NotImplementedError() @@ -192,7 +192,7 @@ def get_pronouns( number: Optional[Number] = None, gender: Optional[Gender] = None, imperative: bool = False, - ) -> List[Pronoun]: + ) -> list[Pronoun]: """ Returns a list of all pronouns matching the provided filters, in the typical order, with the default pronoun first. @@ -283,8 +283,8 @@ def compound_primary_verb_conjugation_uses_infinitive( return False def modify_aux_verb_conj_if_applicable( - self, aux_conj: List[str], mood: Mood, tense: Tense - ) -> List[str]: + self, aux_conj: list[str], mood: Mood, tense: Tense + ) -> list[str]: """ Hook for certain languages e.g. Romanian that use a different aux_conj for certain tenses @@ -345,5 +345,8 @@ def _get_pronoun_suffix( ) -> str: return " " + self.get_pronouns(person, number, gender)[0] - def _is_impersonal_verb(self, infinitive: str) -> bool: + def private_is_impersonal_verb(self, infinitive: str) -> bool: return False + + def _get_verbs(self) -> Verbs: + return self._verbs diff --git a/verbecc/src/inflectors/inflector_factory.py b/src/verbecc/core/inflectors/inflector_factory.py similarity index 58% rename from verbecc/src/inflectors/inflector_factory.py rename to src/verbecc/core/inflectors/inflector_factory.py index 872c46f..08ae75c 100644 --- a/verbecc/src/inflectors/inflector_factory.py +++ b/src/verbecc/core/inflectors/inflector_factory.py @@ -1,15 +1,15 @@ from typing import Optional -from verbecc.src.defs.types.lang_specific_options import LangSpecificOptions -from verbecc.src.defs.types.exceptions import InvalidLangError -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 -from verbecc.src.inflectors.inflector import Inflector -from verbecc.src.inflectors.lang.inflector_ca import InflectorCa -from verbecc.src.inflectors.lang.inflector_es import InflectorEs -from verbecc.src.inflectors.lang.inflector_fr import InflectorFr -from verbecc.src.inflectors.lang.inflector_it import InflectorIt -from verbecc.src.inflectors.lang.inflector_pt import InflectorPt -from verbecc.src.inflectors.lang.inflector_ro import InflectorRo +from verbecc.core.defs.types.lang_specific_options import LangSpecificOptions +from verbecc.core.defs.types.exceptions import InvalidLangError +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 +from verbecc.core.inflectors.inflector import Inflector +from verbecc.core.inflectors.lang.ca import InflectorCa +from verbecc.core.inflectors.lang.es import InflectorEs +from verbecc.core.inflectors.lang.fr import InflectorFr +from verbecc.core.inflectors.lang.it import InflectorIt +from verbecc.core.inflectors.lang.pt import InflectorPt +from verbecc.core.inflectors.lang.ro import InflectorRo class InflectorFactory: diff --git a/verbecc/src/inflectors/__init__.py b/src/verbecc/core/inflectors/lang/__init__.py similarity index 100% rename from verbecc/src/inflectors/__init__.py rename to src/verbecc/core/inflectors/lang/__init__.py diff --git a/src/verbecc/core/inflectors/lang/ca/__init__.py b/src/verbecc/core/inflectors/lang/ca/__init__.py new file mode 100644 index 0000000..ce5955b --- /dev/null +++ b/src/verbecc/core/inflectors/lang/ca/__init__.py @@ -0,0 +1 @@ +from .inflector_ca import InflectorCa # type: ignore \ No newline at end of file diff --git a/verbecc/src/inflectors/lang/inflector_ca.py b/src/verbecc/core/inflectors/lang/ca/inflector_ca.py similarity index 88% rename from verbecc/src/inflectors/lang/inflector_ca.py rename to src/verbecc/core/inflectors/lang/ca/inflector_ca.py index fa33554..2d37ef6 100755 --- a/verbecc/src/inflectors/lang/inflector_ca.py +++ b/src/verbecc/core/inflectors/lang/ca/inflector_ca.py @@ -1,19 +1,19 @@ -from typing import Dict, List, Optional, Tuple - -from verbecc.src.defs.types.gender import Gender -from verbecc.src.defs.types.person import Person -from verbecc.src.defs.types.number import Number -from verbecc.src.defs.types.mood import Mood, Moods -from verbecc.src.defs.types.tense import Tense, Tenses -from verbecc.src.defs.types import exceptions -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 -from verbecc.src.defs.types.lang_specific_options import ( +from typing import Optional, Tuple + +from verbecc.core.defs.types.gender import Gender +from verbecc.core.defs.types.person import Person +from verbecc.core.defs.types.number import Number +from verbecc.core.defs.types.mood import Mood, Moods +from verbecc.core.defs.types.tense import Tense, Tenses +from verbecc.core.defs.types import exceptions +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 +from verbecc.core.defs.types.lang_specific_options import ( LangSpecificOptions, ) -from verbecc.src.inflectors import inflector -from verbecc.src.utils.string_utils import get_common_letter_count, strip_accents -from verbecc.src.conjugator.conjugation_object import ConjugationObjects -from verbecc.src.defs.types.pronoun import Pronoun, Pronouns +from verbecc.core.inflectors import inflector +from verbecc.core.utils.string_utils import get_common_letter_count, strip_accents +from verbecc.core.conjugator.conjugation_object import ConjugationObjects +from verbecc.core.defs.types.pronoun import Pronoun, Pronouns class InflectorCa(inflector.Inflector): @@ -41,8 +41,8 @@ def get_pronouns( number: Optional[Number] = None, gender: Optional[Gender] = None, imperative: bool = False, - ) -> List[Pronoun]: - ret = [] + ) -> list[Pronoun]: + ret : list[Pronoun] = [] if (person is None or person == Person.First) and ( number is None or number == Number.Singular ): @@ -97,7 +97,7 @@ def make_pronoun_reflexive(self, pronoun: Pronoun) -> str: else: return pronoun + " se" - def get_tenses_conjugated_without_pronouns(self) -> List[Tense]: + def get_tenses_conjugated_without_pronouns(self) -> list[Tense]: return [ Tenses.ca.Participi, Tenses.ca.Gerundi, @@ -141,7 +141,7 @@ def get_alternate_hv_inflection(self, s: str) -> str: def get_compound_conjugations_aux_verb_map( self, - ) -> Dict[Mood, Dict[Tense, Tuple[Mood, Tense]]]: + ) -> dict[Mood, dict[Tense, Tuple[Mood, Tense]]]: """ TODO: Implement all these compound tenses (Spanish compound tenses in this commment, for reference) return { @@ -189,7 +189,7 @@ def get_verb_stem_from_template_name( _, template_ending = template_name.split(":") infinitive_no_accents = strip_accents(infinitive) template_ending_no_accents = strip_accents(infinitive) - infinitive_ending_no_accents = infinitive_no_accents[-len(template_ending) :] + infinitive_ending_no_accents = infinitive_no_accents[-len(template_ending):] if ( not infinitive_ending_no_accents == template_ending_no_accents and not infinitive_no_accents[1:] == template_ending_no_accents[1:] diff --git a/src/verbecc/core/inflectors/lang/es/__init__.py b/src/verbecc/core/inflectors/lang/es/__init__.py new file mode 100644 index 0000000..765bdf9 --- /dev/null +++ b/src/verbecc/core/inflectors/lang/es/__init__.py @@ -0,0 +1 @@ +from .inflector_es import InflectorEs # type: ignore \ No newline at end of file diff --git a/verbecc/src/inflectors/lang/inflector_es.py b/src/verbecc/core/inflectors/lang/es/inflector_es.py similarity index 63% rename from verbecc/src/inflectors/lang/inflector_es.py rename to src/verbecc/core/inflectors/lang/es/inflector_es.py index 647fed2..ebfd586 100755 --- a/verbecc/src/inflectors/lang/inflector_es.py +++ b/src/verbecc/core/inflectors/lang/es/inflector_es.py @@ -1,22 +1,22 @@ import copy -from typing import cast, Dict, List, Optional, Tuple - -from verbecc.src.conjugator.conjugation_object import ConjugationObjects -from verbecc.src.defs.types.data.person_ending import PersonEnding -from verbecc.src.defs.types.data.tense_template import TenseTemplate -from verbecc.src.defs.types.gender import Gender -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 -from verbecc.src.defs.types.lang_specific_options import LangSpecificOptions -from verbecc.src.defs.types.lang_specific_options import LangSpecificOptionsEs -from verbecc.src.defs.types.lang_specific_options import LangSpecificOptionsFactory -from verbecc.src.defs.types.lang_specific_options import VoseoOptions -from verbecc.src.defs.types.mood import Mood, Moods -from verbecc.src.defs.types.number import Number -from verbecc.src.defs.types.person import Person -from verbecc.src.defs.types.tense import Tense, Tenses -from verbecc.src.inflectors.inflector import Inflector -from verbecc.src.utils.string_utils import strip_accents -from verbecc.src.defs.types.pronoun import Pronoun, Pronouns +from typing import cast, Optional, Tuple + +from verbecc.core.conjugator.conjugation_object import ConjugationObjects +from verbecc.core.defs.types.data.person_ending import PersonEnding +from verbecc.core.defs.types.data.tense_template import TenseTemplate +from verbecc.core.defs.types.gender import Gender +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 +from verbecc.core.defs.types.lang_specific_options import LangSpecificOptions +from verbecc.core.defs.types.lang_specific_options.lang.es import LangSpecificOptionsEs +from verbecc.core.defs.types.lang_specific_options.lang.es import VoseoOptions +from verbecc.core.defs.types.lang_specific_options import LangSpecificOptionsFactory +from verbecc.core.defs.types.mood import Mood, Moods +from verbecc.core.defs.types.number import Number +from verbecc.core.defs.types.person import Person +from verbecc.core.defs.types.tense import Tense, Tenses +from verbecc.core.inflectors.inflector import Inflector +from verbecc.core.utils.string_utils import strip_accents +from verbecc.core.defs.types.pronoun import Pronoun, Pronouns class InflectorEs(Inflector): @@ -55,8 +55,8 @@ def get_pronouns( number: Optional[Number] = None, gender: Optional[Gender] = None, imperative: bool = False, - ) -> List[Pronoun]: - ret = [] + ) -> list[Pronoun]: + ret : list[Pronoun] = [] if (person is None or person == Person.First) and ( number is None or number == Number.Singular ): @@ -111,7 +111,7 @@ def make_pronoun_reflexive(self, pronoun: str) -> str: else: return pronoun + " se" - def get_tenses_conjugated_without_pronouns(self) -> List[Tense]: + def get_tenses_conjugated_without_pronouns(self) -> list[Tense]: return [ Tenses.es.Participo, Tenses.es.Gerundio, @@ -156,7 +156,7 @@ def get_alternate_hv_inflection(self, s: str) -> str: def get_compound_conjugations_aux_verb_map( self, - ) -> Dict[Mood, Dict[Tense, Tuple[Mood, Tense]]]: + ) -> dict[Mood, dict[Tense, Tuple[Mood, Tense]]]: return { Moods.es.Indicativo: { Tenses.es.PretéritoPerfectoCompuesto: ( @@ -236,71 +236,66 @@ def modify_person_ending_if_applicable( """ # only need to accent 'a', 'e' and 'i', AFAIK VOWEL_ACCENT_MAP = {"a": "á", "e": "é", "i": "í"} - if self.lang_specific_options is not None: + if ( + pronoun is not None + and pronoun == "vos" + and person_ending.person == Person.Second + and person_ending.number == Number.Singular + ): + if self.lang_specific_options.get_voseo_options() != VoseoOptions.VoseoTipo3: + # only voseo tipo 3 (voseo típico aka Rioplatense) is supported at the moment + raise NotImplementedError() + if ( - pronoun is not None - and pronoun == "vos" - and person_ending.person == Person.Second - and person_ending.number == Number.Singular + (mood == Moods.es.Indicativo and tense == Tenses.es.Presente) + or (mood == Moods.es.Subjuntivo and tense == Tenses.es.Presente) + or (mood == Moods.es.Imperativo and tense == Tenses.es.Afirmativo) ): - if ( - self.lang_specific_options is not None - and self.lang_specific_options.get_voseo_options() - != VoseoOptions.VoseoTipo3 - ): - # only voseo tipo 3 (voseo típico aka Rioplatense) is supported at the moment - raise NotImplementedError() - - if ( - (mood == Moods.es.Indicativo and tense == Tenses.es.Presente) - or (mood == Moods.es.Subjuntivo and tense == Tenses.es.Presente) - or (mood == Moods.es.Imperativo and tense == Tenses.es.Afirmativo) - ): - # first replace with given p2s (tú) ending(s) - # with the p2p (vosotros) ending(s) - replacement_person_ending = copy.deepcopy( - tense_template.get_person_ending(Person.Second, Number.Plural) - ) - # change replacement PersonEnding Person from second person plural to singular - replacement_person_ending.person = Person.Second - replacement_person_ending.number = Number.Singular - - # modify the endings for voseo to form the vos endings - for i, ending in enumerate(replacement_person_ending.get_endings()): - - if mood in (Moods.es.Indicativo, Moods.es.Subjuntivo): - # step one for indicativo and subjuntivo presente: - # remove 'i' in the second-to-last letter position - if ending[-2] == "i": - ending = ending[:-2] + ending[-1] - if mood == Moods.es.Imperativo: - # step one for imperativo: remove the trailing 'd' - if ending[-1] == "d": - ending = ending[:-1] - - if mood == Moods.es.Subjuntivo: - # step two for subjunctivo is to strip any accents from vowels - # e.g. vosotros seáis -> vos seas - ending = strip_accents(ending) - else: - # step two for indicativo and imperativo is to accent the vowel which - # is now in the second-to-last or last letter position (if not already accented) - - # accent second-to-last letter, if vowel - if len(ending) > 1: - if ending[-2] in VOWEL_ACCENT_MAP: - ending = ( - ending[:-2] - + VOWEL_ACCENT_MAP[ending[-2]] - + ending[-1] - ) - # accent last letter, if vowel - if ending[-1] in VOWEL_ACCENT_MAP: - ending = ending[:-1] + VOWEL_ACCENT_MAP[ending[-1]] - - # update the replacement person ending with the modified ending - replacement_person_ending.endings[i] = ending - return replacement_person_ending + # first replace with given p2s (tú) ending(s) + # with the p2p (vosotros) ending(s) + replacement_person_ending = copy.deepcopy( + tense_template.get_person_ending(Person.Second, Number.Plural) + ) + # change replacement PersonEnding Person from second person plural to singular + replacement_person_ending.person = Person.Second + replacement_person_ending.number = Number.Singular + + # modify the endings for voseo to form the vos endings + for i, ending in enumerate(replacement_person_ending.get_endings()): + + if mood in (Moods.es.Indicativo, Moods.es.Subjuntivo): + # step one for indicativo and subjuntivo presente: + # remove 'i' in the second-to-last letter position + if ending[-2] == "i": + ending = ending[:-2] + ending[-1] + if mood == Moods.es.Imperativo: + # step one for imperativo: remove the trailing 'd' + if ending[-1] == "d": + ending = ending[:-1] + + if mood == Moods.es.Subjuntivo: + # step two for subjunctivo is to strip any accents from vowels + # e.g. vosotros seáis -> vos seas + ending = strip_accents(ending) + else: + # step two for indicativo and imperativo is to accent the vowel which + # is now in the second-to-last or last letter position (if not already accented) + + # accent second-to-last letter, if vowel + if len(ending) > 1: + if ending[-2] in VOWEL_ACCENT_MAP: + ending = ( + ending[:-2] + + VOWEL_ACCENT_MAP[ending[-2]] + + ending[-1] + ) + # accent last letter, if vowel + if ending[-1] in VOWEL_ACCENT_MAP: + ending = ending[:-1] + VOWEL_ACCENT_MAP[ending[-1]] + + # update the replacement person ending with the modified ending + replacement_person_ending.endings[i] = ending + return replacement_person_ending return person_ending def split_reflexive(self, infinitive: str) -> Tuple[bool, str]: diff --git a/src/verbecc/core/inflectors/lang/fr/__init__.py b/src/verbecc/core/inflectors/lang/fr/__init__.py new file mode 100644 index 0000000..fb3bd0a --- /dev/null +++ b/src/verbecc/core/inflectors/lang/fr/__init__.py @@ -0,0 +1 @@ +from .inflector_fr import InflectorFr # type: ignore \ No newline at end of file diff --git a/verbecc/src/inflectors/lang/inflector_fr.py b/src/verbecc/core/inflectors/lang/fr/inflector_fr.py similarity index 90% rename from verbecc/src/inflectors/lang/inflector_fr.py rename to src/verbecc/core/inflectors/lang/fr/inflector_fr.py index 1083242..38666a0 100755 --- a/verbecc/src/inflectors/lang/inflector_fr.py +++ b/src/verbecc/core/inflectors/lang/fr/inflector_fr.py @@ -1,19 +1,19 @@ -from typing import Dict, List, Optional, Tuple - -from verbecc.src.conjugator.conjugation_object import ConjugationObjects -from verbecc.src.defs.types.gender import Gender -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 -from verbecc.src.defs.types.mood import Mood, Moods -from verbecc.src.defs.types.person import Person -from verbecc.src.defs.types.number import Number -from verbecc.src.defs.constants.grammar_defines import PERSONS -from verbecc.src.defs.types.tense import Tense, Tenses -from verbecc.src.defs.types.lang_specific_options import ( +from typing import Optional, Tuple + +from verbecc.core.conjugator.conjugation_object import ConjugationObjects +from verbecc.core.defs.types.gender import Gender +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 +from verbecc.core.defs.types.mood import Mood, Moods +from verbecc.core.defs.types.person import Person +from verbecc.core.defs.types.number import Number +from verbecc.core.defs.constants.grammar_defines import PERSONS +from verbecc.core.defs.types.tense import Tense, Tenses +from verbecc.core.defs.types.lang_specific_options import ( LangSpecificOptions, ) -from verbecc.src.inflectors.inflector import Inflector -from verbecc.src.utils import string_utils -from verbecc.src.defs.types.pronoun import Pronoun, Pronouns +from verbecc.core.inflectors.inflector import Inflector +from verbecc.core.utils import string_utils +from verbecc.core.defs.types.pronoun import Pronoun, Pronouns """ DR & MRS VANDERTRAMPP verbs @@ -60,7 +60,7 @@ def __init__( def get_lang(self) -> LangCodeISO639_1: return LangCodeISO639_1.fr - def get_verbs_that_start_with(self, query: str, max_results: int) -> List[str]: + def get_verbs_that_start_with(self, query: str, max_results: int) -> list[str]: query = query.lower() is_reflexive, query = self.split_reflexive(query) matches = self._verbs.get_verbs_that_start_with(query, max_results) @@ -74,7 +74,7 @@ def get_verbs_that_start_with(self, query: str, max_results: int) -> List[str]: def verb_can_be_reflexive(self, infinitive: str) -> bool: return ( - not self._is_impersonal_verb(infinitive) + not self.private_is_impersonal_verb(infinitive) and infinitive not in VERBS_THAT_CANNOT_BE_REFLEXIVE_OTHER_THAN_IMPERSONAL_VERBS ) @@ -100,7 +100,7 @@ def add_reflexive_pronoun(self, s: str) -> str: else: return "se " + s - def add_subjunctive_relative_pronoun(self, s: str, tense: Tense) -> str: + def add_subjunctive_relative_pronoun(self, s: str, tense: Tense | str | None) -> str: if string_utils.starts_with_vowel(s, h_is_vowel=True): return "qu'" + s else: @@ -119,13 +119,13 @@ def get_pronouns( number: Optional[Number] = None, gender: Optional[Gender] = None, imperative: bool = False, - ) -> List[Pronoun]: + ) -> list[Pronoun]: """ Returns a list of all pronouns matching the provided filters, in the typical order, with the default pronoun first. E.g. Person.Second, Number.Singular => ["tú", "vos"] """ - ret = [] + ret: list[Pronoun] = [] if (person is None or person == Person.First) and ( number is None or number == Number.Singular ): @@ -180,7 +180,7 @@ def make_pronoun_reflexive(self, pronoun: Pronoun) -> str: else: return pronoun + " se" - def get_tenses_conjugated_without_pronouns(self) -> List[Tense]: + def get_tenses_conjugated_without_pronouns(self) -> list[Tense]: return [ Tenses.fr.InfinitifPrésent, Tenses.fr.ParticipePresent, @@ -289,7 +289,7 @@ def compound_conjugation_not_applicable( def get_compound_conjugations_aux_verb_map( self, - ) -> Dict[Mood, Dict[Tense, Tuple[Mood, Tense]]]: + ) -> dict[Mood, dict[Tense, Tuple[Mood, Tense]]]: """ compound conjugations are formed using an auxiliary verb (aka helping verb) @@ -329,7 +329,7 @@ def _get_pronoun_suffix( ) -> str: return "-" + self.get_pronouns(person, number, gender)[0].replace("tu", "toi") - def _is_impersonal_verb(self, infinitive: str) -> bool: + def private_is_impersonal_verb(self, infinitive: str) -> bool: ret = False verb = self.find_verb_by_infinitive(infinitive) template = self.find_template(verb.template) diff --git a/src/verbecc/core/inflectors/lang/it/__init__.py b/src/verbecc/core/inflectors/lang/it/__init__.py new file mode 100644 index 0000000..dc9b184 --- /dev/null +++ b/src/verbecc/core/inflectors/lang/it/__init__.py @@ -0,0 +1 @@ +from .inflector_it import InflectorIt # type: ignore \ No newline at end of file diff --git a/verbecc/src/inflectors/lang/inflector_it.py b/src/verbecc/core/inflectors/lang/it/inflector_it.py similarity index 87% rename from verbecc/src/inflectors/lang/inflector_it.py rename to src/verbecc/core/inflectors/lang/it/inflector_it.py index 0b51604..b78670d 100755 --- a/verbecc/src/inflectors/lang/inflector_it.py +++ b/src/verbecc/core/inflectors/lang/it/inflector_it.py @@ -1,18 +1,18 @@ -from typing import Dict, List, Optional, Tuple - -from verbecc.src.defs.types.gender import Gender -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 -from verbecc.src.defs.types.mood import Mood, Moods -from verbecc.src.defs.types.person import Person -from verbecc.src.defs.types.number import Number -from verbecc.src.defs.types.tense import Tense, Tenses -from verbecc.src.defs.types.lang_specific_options import ( +from typing import Optional, Tuple + +from verbecc.core.defs.types.gender import Gender +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 +from verbecc.core.defs.types.mood import Mood, Moods +from verbecc.core.defs.types.person import Person +from verbecc.core.defs.types.number import Number +from verbecc.core.defs.types.tense import Tense, Tenses +from verbecc.core.defs.types.lang_specific_options import ( LangSpecificOptions, ) -from verbecc.src.conjugator.conjugation_object import ConjugationObjects -from verbecc.src.inflectors.inflector import Inflector -from verbecc.src.utils import string_utils -from verbecc.src.defs.types.pronoun import Pronoun, Pronouns +from verbecc.core.conjugator.conjugation_object import ConjugationObjects +from verbecc.core.inflectors.inflector import Inflector +from verbecc.core.utils import string_utils +from verbecc.core.defs.types.pronoun import Pronoun, Pronouns VERBS_CONJUGATED_WITH_ESSERE = [ "essere", @@ -73,7 +73,7 @@ def add_reflexive_pronoun(self, s: str) -> str: else: return "si " + s - def add_subjunctive_relative_pronoun(self, s: str, tense: Tense) -> str: + def add_subjunctive_relative_pronoun(self, s: str, tense: Tense | str | None) -> str: return "che " + s def get_pronoun_gender(self, pronoun: Pronoun) -> Optional[Gender]: @@ -89,8 +89,8 @@ def get_pronouns( number: Optional[Number] = None, gender: Optional[Gender] = None, imperative: bool = False, - ) -> List[Pronoun]: - ret = [] + ) -> list[Pronoun]: + ret: list[Pronoun] = [] if (person is None or person == Person.First) and ( number is None or number == Number.Singular ): @@ -140,7 +140,7 @@ def make_pronoun_reflexive(self, pronoun: Pronoun) -> str: else: return pronoun + " si" - def get_tenses_conjugated_without_pronouns(self) -> List[Tense]: + def get_tenses_conjugated_without_pronouns(self) -> list[Tense]: return [ Tenses.it.Affermativo, Tenses.it.negativo, @@ -181,7 +181,7 @@ def get_participle_tense(self) -> Tense: def get_compound_conjugations_aux_verb_map( self, - ) -> Dict[Mood, Dict[Tense, Tuple[Mood, Tense]]]: + ) -> dict[Mood, dict[Tense, Tuple[Mood, Tense]]]: return { Moods.it.Indicativo: { Tenses.it.PassatoProssimo: (Moods.it.Indicativo, Tenses.it.Presente), diff --git a/src/verbecc/core/inflectors/lang/pt/__init__.py b/src/verbecc/core/inflectors/lang/pt/__init__.py new file mode 100644 index 0000000..2acca73 --- /dev/null +++ b/src/verbecc/core/inflectors/lang/pt/__init__.py @@ -0,0 +1 @@ +from .inflector_pt import InflectorPt # type: ignore \ No newline at end of file diff --git a/verbecc/src/inflectors/lang/inflector_pt.py b/src/verbecc/core/inflectors/lang/pt/inflector_pt.py similarity index 92% rename from verbecc/src/inflectors/lang/inflector_pt.py rename to src/verbecc/core/inflectors/lang/pt/inflector_pt.py index bdd87c3..c42401e 100755 --- a/verbecc/src/inflectors/lang/inflector_pt.py +++ b/src/verbecc/core/inflectors/lang/pt/inflector_pt.py @@ -1,17 +1,17 @@ -from typing import Dict, List, Optional, Tuple - -from verbecc.src.conjugator.conjugation_object import ConjugationObjects -from verbecc.src.defs.types.gender import Gender -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 -from verbecc.src.defs.types.mood import Mood, Moods -from verbecc.src.defs.types.person import Person -from verbecc.src.defs.types.number import Number -from verbecc.src.defs.types.tense import Tense, Tenses -from verbecc.src.defs.types.lang_specific_options import ( +from typing import Optional, Tuple + +from verbecc.core.conjugator.conjugation_object import ConjugationObjects +from verbecc.core.defs.types.gender import Gender +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 +from verbecc.core.defs.types.mood import Mood, Moods +from verbecc.core.defs.types.person import Person +from verbecc.core.defs.types.number import Number +from verbecc.core.defs.types.tense import Tense, Tenses +from verbecc.core.defs.types.lang_specific_options import ( LangSpecificOptions, ) -from verbecc.src.inflectors.inflector import Inflector -from verbecc.src.defs.types.pronoun import Pronoun, Pronouns +from verbecc.core.inflectors.inflector import Inflector +from verbecc.core.defs.types.pronoun import Pronoun, Pronouns class InflectorPt(Inflector): @@ -26,7 +26,7 @@ def __init__( def get_lang(self) -> LangCodeISO639_1: return LangCodeISO639_1.pt - def add_subjunctive_relative_pronoun(self, s: str, tense: Tense) -> str: + def add_subjunctive_relative_pronoun(self, s: str, tense: Tense | str | None) -> str: if tense == Tenses.pt.Presente: return "que " + s elif tense == Tenses.pt.PretéritoImperfeito: @@ -85,8 +85,8 @@ def get_pronouns( number: Optional[Number] = None, gender: Optional[Gender] = None, imperative: bool = False, - ) -> List[Pronoun]: - ret = [] + ) -> list[Pronoun]: + ret : list[Pronoun] = [] if (person is None or person == Person.First) and ( number is None or number == Number.Singular ): @@ -153,7 +153,7 @@ def make_pronoun_reflexive(self, pronoun: Pronoun) -> str: else: return pronoun + " se" - def get_tenses_conjugated_without_pronouns(self) -> List[Tense]: + def get_tenses_conjugated_without_pronouns(self) -> list[Tense]: """ Many tenses conjugated without pronouns in Spanish are conjugated with pronouns in Portuguese. @@ -201,7 +201,7 @@ def get_participle_tense(self) -> Tense: def get_compound_conjugations_aux_verb_map( self, - ) -> Dict[Mood, Dict[Tense, Tuple[Mood, Tense]]]: + ) -> dict[Mood, dict[Tense, Tuple[Mood, Tense]]]: return { Moods.pt.Indicativo: { Tenses.pt.PretéritoPerfeitoComposto: ( @@ -293,7 +293,7 @@ def _get_pronoun_suffix( # e.g. "se eu me vestisse" # e.g. "quando eu me vestir" # also Imperativo Negativo (not currently supported) - def get_unhyphenated_reflexive_mood_tenses(self) -> List[Tuple[Mood, Tense]]: + def get_unhyphenated_reflexive_mood_tenses(self) -> list[Tuple[Mood, Tense]]: return [ (Moods.pt.Subjuntivo, Tenses.pt.Presente), (Moods.pt.Subjuntivo, Tenses.pt.PretéritoImperfeito), diff --git a/src/verbecc/core/inflectors/lang/ro/__init__.py b/src/verbecc/core/inflectors/lang/ro/__init__.py new file mode 100644 index 0000000..25ac28d --- /dev/null +++ b/src/verbecc/core/inflectors/lang/ro/__init__.py @@ -0,0 +1 @@ +from .inflector_ro import InflectorRo # type: ignore \ No newline at end of file diff --git a/verbecc/src/inflectors/lang/inflector_ro.py b/src/verbecc/core/inflectors/lang/ro/inflector_ro.py similarity index 92% rename from verbecc/src/inflectors/lang/inflector_ro.py rename to src/verbecc/core/inflectors/lang/ro/inflector_ro.py index 518de26..6ce01f6 100755 --- a/verbecc/src/inflectors/lang/inflector_ro.py +++ b/src/verbecc/core/inflectors/lang/ro/inflector_ro.py @@ -1,17 +1,17 @@ -from typing import Dict, List, Optional, Tuple - -from verbecc.src.conjugator.conjugation_object import ConjugationObjects -from verbecc.src.defs.types.gender import Gender -from verbecc.src.defs.types.person import Person -from verbecc.src.defs.types.number import Number -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 -from verbecc.src.defs.types.mood import Mood, Moods -from verbecc.src.defs.types.tense import Tense, Tenses -from verbecc.src.defs.types.lang_specific_options import ( +from typing import Optional, Tuple + +from verbecc.core.conjugator.conjugation_object import ConjugationObjects +from verbecc.core.defs.types.gender import Gender +from verbecc.core.defs.types.person import Person +from verbecc.core.defs.types.number import Number +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 +from verbecc.core.defs.types.mood import Mood, Moods +from verbecc.core.defs.types.tense import Tense, Tenses +from verbecc.core.defs.types.lang_specific_options import ( LangSpecificOptions, ) -from verbecc.src.inflectors.inflector import Inflector -from verbecc.src.defs.types.pronoun import Pronoun, Pronouns +from verbecc.core.inflectors.inflector import Inflector +from verbecc.core.defs.types.pronoun import Pronoun, Pronouns class InflectorRo(Inflector): @@ -23,7 +23,7 @@ def __init__( def get_lang(self) -> LangCodeISO639_1: return LangCodeISO639_1.ro - def add_subjunctive_relative_pronoun(self, s: str, tense: Tense) -> str: + def add_subjunctive_relative_pronoun(self, s: str, tense: Tense | str | None) -> str: """ :param s: a conjugation, perhaps with a pronoun e.g. "eu fac" :tense s: the verb tense @@ -48,7 +48,7 @@ def add_adverb_if_applicable(self, s: str, mood: Mood, tense: Tense) -> str: return "nu " + s return s - """TODO: There are two types of reflexive verbs in Romanian: + """TODO: There are two types of reflexive verbs in Romanian: preceded by the reflexive pronouns “se” (in the accusative) and “și” (in the dative). """ @@ -65,8 +65,8 @@ def get_pronouns( number: Optional[Number] = None, gender: Optional[Gender] = None, imperative: bool = False, - ) -> List[Pronoun]: - ret = [] + ) -> list[Pronoun]: + ret : list[Pronoun] = [] if (person is None or person == Person.First) and ( number is None or number == Number.Singular ): @@ -121,7 +121,7 @@ def make_pronoun_reflexive(self, pronoun: Pronoun) -> str: else: return pronoun + " se" - def get_tenses_conjugated_without_pronouns(self) -> List[Tense]: + def get_tenses_conjugated_without_pronouns(self) -> list[Tense]: return [ Tenses.ro.Participiu, Tenses.ro.Afirmativ, @@ -162,7 +162,7 @@ def get_participle_tense(self) -> Tense: def get_compound_conjugations_aux_verb_map( self, - ) -> Dict[Mood, Dict[Tense, Tuple[Mood, Tense]]]: + ) -> dict[Mood, dict[Tense, Tuple[Mood, Tense]]]: """ TODO: those last three don't actually use an auxiliary verb, refactor to make aux verb optional @@ -202,8 +202,8 @@ def compound_primary_verb_conjugation_uses_infinitive( return False def modify_aux_verb_conj_if_applicable( - self, aux_conj: List[str], mood: Mood, tense: Tense - ) -> List[str]: + self, aux_conj: list[str], mood: Mood, tense: Tense + ) -> list[str]: """E.g. for Romanian conditional present 'eu aş avea, tu ai avea, el ar avea, ...' and also the Romanian conditional present e.g. 'eu aş fi avut, tu ai fi avut, ...' although the ' fi' is added by add_compound_aux_verb_suffix_if_applicable diff --git a/verbecc/src/mlconjug/__init__.py b/src/verbecc/core/mlconjug/__init__.py similarity index 100% rename from verbecc/src/mlconjug/__init__.py rename to src/verbecc/core/mlconjug/__init__.py diff --git a/verbecc/src/mlconjug/data_set.py b/src/verbecc/core/mlconjug/data_set.py similarity index 81% rename from verbecc/src/mlconjug/data_set.py rename to src/verbecc/core/mlconjug/data_set.py index 80f69ba..2ea2a10 100644 --- a/verbecc/src/mlconjug/data_set.py +++ b/src/verbecc/core/mlconjug/data_set.py @@ -1,8 +1,7 @@ -from typing import Dict, List from collections import defaultdict import random -from verbecc.src.mlconjug.mltypes import VerbTemplatePair +from verbecc.core.mlconjug.mltypes import VerbTemplatePair class DataSet: @@ -11,7 +10,7 @@ class DataSet: | Defines helper methodss for managing Machine Learning tasks like constructing a training and testing set. """ - def __init__(self, verb_template_pairs: List[VerbTemplatePair]) -> None: + def __init__(self, verb_template_pairs: list[VerbTemplatePair]) -> None: self.verbs = [pair[0] for pair in verb_template_pairs] self.templates = sorted(set([pair[1] for pair in verb_template_pairs])) self.dict_conjug = self._construct_dict_conjug(verb_template_pairs) @@ -19,8 +18,8 @@ def __init__(self, verb_template_pairs: List[VerbTemplatePair]) -> None: return def _construct_dict_conjug( - self, verb_template_pairs: List[VerbTemplatePair] - ) -> Dict[str, List[str]]: + self, verb_template_pairs: list[VerbTemplatePair] + ) -> dict[str, list[str]]: """ | Populates the dictionary containing the conjugation templates. | Populates the lists containing the verbs and their templates. @@ -30,7 +29,7 @@ def _construct_dict_conjug( :return: defaultdict. defaultdict mapping each template to one or more verbs e.g. {'aim:er': ['abaisser', ...]} """ - ret = defaultdict(list) + ret: defaultdict[str, list[str]] = defaultdict(list) random.shuffle(verb_template_pairs) for verb, template in verb_template_pairs: ret[template].append(verb) @@ -55,8 +54,8 @@ def _split_test_train(self, threshold: int = 8, proportion: float = 0.5) -> None ) self.min_threshold = threshold self.split_proportion = proportion - train_set: List[VerbTemplatePair] = [] - test_set: List[VerbTemplatePair] = [] + train_set: list[VerbTemplatePair] = [] + test_set: list[VerbTemplatePair] = [] for template, lverbs in self.dict_conjug.items(): if len(lverbs) <= threshold: for verb in lverbs: @@ -69,11 +68,11 @@ def _split_test_train(self, threshold: int = 8, proportion: float = 0.5) -> None test_set.append((verb, template)) random.shuffle(train_set) random.shuffle(test_set) - self.train_input: List[str] = [elmt[0] for elmt in train_set] - self.train_labels: List[int] = [ + self.train_input: list[str] = [elmt[0] for elmt in train_set] + self.train_labels: list[int] = [ self.templates.index(elmt[1]) for elmt in train_set ] - self.test_input: List[str] = [elmt[0] for elmt in test_set] - self.test_labels: List[int] = [ + self.test_input: list[str] = [elmt[0] for elmt in test_set] + self.test_labels: list[int] = [ self.templates.index(elmt[1]) for elmt in test_set ] diff --git a/verbecc/src/mlconjug/feature_extract.py b/src/verbecc/core/mlconjug/feature_extract.py similarity index 93% rename from verbecc/src/mlconjug/feature_extract.py rename to src/verbecc/core/mlconjug/feature_extract.py index 71450f9..19ffb88 100644 --- a/verbecc/src/mlconjug/feature_extract.py +++ b/src/verbecc/core/mlconjug/feature_extract.py @@ -1,13 +1,13 @@ -from typing import List, Tuple +from typing import Tuple import re -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 -from verbecc.src.defs.constants.grammar_defines import ALPHABET +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 +from verbecc.core.defs.constants.grammar_defines import ALPHABET def extract_verb_features( verb: str, lang: LangCodeISO639_1, ngram_range: Tuple[int, int] -) -> List[str]: +) -> list[str]: """ | Custom Vectorizer optimized for extracting verbs features. | The Vectorizer subclasses sklearn.feature_extraction.text.CountVectorizer diff --git a/verbecc/src/mlconjug/mltypes.py b/src/verbecc/core/mlconjug/mltypes.py similarity index 100% rename from verbecc/src/mlconjug/mltypes.py rename to src/verbecc/core/mlconjug/mltypes.py diff --git a/verbecc/src/mlconjug/model.py b/src/verbecc/core/mlconjug/model.py similarity index 78% rename from verbecc/src/mlconjug/model.py rename to src/verbecc/core/mlconjug/model.py index 33449c7..69a6232 100644 --- a/verbecc/src/mlconjug/model.py +++ b/src/verbecc/core/mlconjug/model.py @@ -1,22 +1,21 @@ -from typing import List from functools import partial +from typing import Any, cast import numpy as np from sklearn.feature_selection import SelectFromModel -from sklearn.feature_extraction.text import CountVectorizer from sklearn.linear_model import SGDClassifier from sklearn.svm import LinearSVC from sklearn.pipeline import Pipeline -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 -from verbecc.src.mlconjug.mltypes import ( +from verbecc.core.mlconjug.mltypes import ( Classifier, Vectorizor, FeatureSelector, CountVectorizer, ) -from verbecc.src.mlconjug.feature_extract import extract_verb_features +from verbecc.core.mlconjug.feature_extract import extract_verb_features class Model: @@ -67,9 +66,12 @@ def __init__( return def __repr__(self) -> str: - return "{0}.{1}({2}, {3}, {4})".format(__name__, self.__class__.__name__, *sorted(self.pipeline.named_steps)) + step_names = ", ".join( + sorted(cast(dict[str, object], self.pipeline.named_steps).keys()) + ) + return f"{__name__}.{self.__class__.__name__}({step_names})" - def train(self, samples: List[str], labels: List[int]) -> None: + def train(self, samples: list[str], labels: list[int]) -> None: """ Trains the pipeline on the supplied samples and labels. @@ -79,10 +81,10 @@ def train(self, samples: List[str], labels: List[int]) -> None: List of verb template indices. """ - self.pipeline = self.pipeline.fit(samples, labels) + self.pipeline = cast(Any, self.pipeline).fit(samples, labels) return - def predict(self, verbs: List[str]) -> List[np.int64]: + def predict(self, verbs: list[str]) -> list[np.int64]: """ Predicts the conjugation class of the provided list of verbs. @@ -92,5 +94,5 @@ def predict(self, verbs: List[str]) -> List[np.int64]: List of incices of predicted conjugation templates """ - prediction = self.pipeline.predict(verbs) - return list(prediction) + prediction = cast(Any, self.pipeline).predict(verbs) + return cast(list[np.int64], list(prediction)) diff --git a/verbecc/src/mlconjug/model_utils.py b/src/verbecc/core/mlconjug/model_utils.py similarity index 89% rename from verbecc/src/mlconjug/model_utils.py rename to src/verbecc/core/mlconjug/model_utils.py index d6f227b..c2f1808 100644 --- a/verbecc/src/mlconjug/model_utils.py +++ b/src/verbecc/core/mlconjug/model_utils.py @@ -1,12 +1,12 @@ from typing import Optional -from importlib_resources import as_file, files +from importlib.resources import as_file, files import os import pickle from zipfile import ZipFile -from verbecc.src.utils.logging_utils import LoggingUtils -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 -from verbecc.src.mlconjug.model import Model +from verbecc.core.utils.logging_utils import LoggingUtils +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 +from verbecc.core.mlconjug.model import Model _logger = LoggingUtils.get_logger(__name__) diff --git a/verbecc/src/mlconjug/predictor.py b/src/verbecc/core/mlconjug/predictor.py similarity index 61% rename from verbecc/src/mlconjug/predictor.py rename to src/verbecc/core/mlconjug/predictor.py index 87e6965..d79f85d 100755 --- a/verbecc/src/mlconjug/predictor.py +++ b/src/verbecc/core/mlconjug/predictor.py @@ -1,18 +1,18 @@ -from typing import List, Tuple +from typing import Callable, Tuple, cast import numpy as np -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 -from verbecc.src.mlconjug.model import Model -from verbecc.src.mlconjug.model_utils import load_model, save_model -from verbecc.src.mlconjug.data_set import DataSet -from verbecc.src.mlconjug.mltypes import VerbTemplatePair -from verbecc.src.utils.logging_utils import LoggingUtils +from verbecc.core.mlconjug.model import Model +from verbecc.core.mlconjug.model_utils import load_model, save_model +from verbecc.core.mlconjug.data_set import DataSet +from verbecc.core.mlconjug.mltypes import VerbTemplatePair +from verbecc.core.utils.logging_utils import LoggingUtils class TemplatePredictor: def __init__( - self, verb_template_pairs: List[VerbTemplatePair], lang: LangCodeISO639_1 + self, verb_template_pairs: list[VerbTemplatePair], lang: LangCodeISO639_1 ) -> None: self._logger = LoggingUtils.get_logger(self.__class__.__name__) self.data_set = DataSet(verb_template_pairs) @@ -31,11 +31,15 @@ def __init__( return def predict(self, verb: str) -> Tuple[str, float]: - predict_results: List[np.int64] = self.model.predict([verb]) + predict_results: list[np.int64] = self.model.predict([verb]) if len(predict_results) == 0: raise Exception("Template prediction failed") prediction = predict_results[0] - predict_proba = self.model.pipeline.predict_proba([verb]) + predict_proba_fn = cast( + Callable[[list[str]], np.ndarray], + getattr(self.model.pipeline, "predict_proba"), + ) + predict_proba = predict_proba_fn([verb]) prediction_score = predict_proba[0][prediction] template = self.data_set.templates[prediction] return (template, prediction_score) diff --git a/verbecc/src/inflectors/lang/__init__.py b/src/verbecc/core/parsers/__init__.py similarity index 100% rename from verbecc/src/inflectors/lang/__init__.py rename to src/verbecc/core/parsers/__init__.py diff --git a/src/verbecc/core/parsers/conjugation_template_parser.py b/src/verbecc/core/parsers/conjugation_template_parser.py new file mode 100755 index 0000000..130a8bb --- /dev/null +++ b/src/verbecc/core/parsers/conjugation_template_parser.py @@ -0,0 +1,45 @@ +from typing import Optional + +from verbecc.core.defs.types.data.conjugation_template import ConjugationTemplate +from verbecc.core.defs.types.data.mood_template import MoodTemplate +from verbecc.core.defs.types.exceptions import ConjugationTemplateError +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 as Lang +from verbecc.core.defs.types.mood import Mood, MoodFactory +from verbecc.core.parsers.mood_template_parser import MoodTemplateParser +from verbecc.core.parsers.parser import Parser +from verbecc.core.defs.types.data.xml_types import XmlElement +from verbecc.core.utils.xml_utils import xml_element_get_attr, xml_element_get_tag, xml_element_to_string + +class ConjugationTemplateParser(Parser): + def __init__(self, lang: Lang) -> None: + self.lang = lang + + def parse(self, elem: Optional[XmlElement] = None) -> ConjugationTemplate: + if elem is None: + raise ValueError("elem must not be None") + tag = xml_element_get_tag(elem) + if tag != "template": + raise ConjugationTemplateError("Unexpected element") + try: + name_attrib = xml_element_get_attr(elem, "name", default=None) + name = str(name_attrib) + mood_templates: dict[Mood, MoodTemplate] = {} + for mood_elem in elem: + mood_template = MoodTemplateParser(lang=self.lang).parse(mood_elem) + mood = MoodFactory.from_string(self.lang, xml_element_get_tag(mood_elem).lower()) + mood_templates[mood] = mood_template + modify_stem = "" + modify_stem_attrib = xml_element_get_attr(elem, "modify-stem", default=None) + if modify_stem_attrib is not None: + modify_stem = str(modify_stem_attrib) + if modify_stem not in ("strip-accents"): + raise ConjugationTemplateError( + f"Invalid 'modify-stem' attribute value '{modify_stem}'" + ) + else: + modify_stem = "" + return ConjugationTemplate(self.lang, name, mood_templates, modify_stem) + except AttributeError as e: + raise ConjugationTemplateError( + "Error parsing {}: {}".format(xml_element_to_string(elem), str(e)) + ) diff --git a/verbecc/src/parsers/conjugations_parser.py b/src/verbecc/core/parsers/conjugations_parser.py similarity index 73% rename from verbecc/src/parsers/conjugations_parser.py rename to src/verbecc/core/parsers/conjugations_parser.py index f41746a..0bca1f7 100755 --- a/verbecc/src/parsers/conjugations_parser.py +++ b/src/verbecc/core/parsers/conjugations_parser.py @@ -1,39 +1,29 @@ -from __future__ import print_function - -from bisect import bisect_left - -# try: from lxml import etree -# except ImportError: -# import xml.etree.ElementTree as etree -from importlib_resources import as_file, files - -# import gzip -import os +from importlib.resources import as_file, files -# import tempfile -from typing import cast, List, Optional +from typing import cast, Optional -from verbecc.src.defs.types.data.conjugation_template import ConjugationTemplate -from verbecc.src.defs.types.data.conjugations import Conjugations -from verbecc.src.defs.types.exceptions import ConjugationsParserError -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 -from verbecc.src.parsers.conjugation_template_parser import ConjugationTemplateParser -from verbecc.src.parsers.parser import Parser +from verbecc.core.defs.types.data.conjugation_template import ConjugationTemplate +from verbecc.core.defs.types.data.conjugations import Conjugations +from verbecc.core.defs.types.data.xml_types import XmlElement +from verbecc.core.defs.types.exceptions import ConjugationsParserError +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 +from verbecc.core.parsers.conjugation_template_parser import ConjugationTemplateParser +from verbecc.core.parsers.parser import Parser class ConjugationsParser(Parser): def __init__(self, lang: LangCodeISO639_1 = LangCodeISO639_1.fr) -> None: self.lang = lang - def parse(self, elem: Optional[etree._Element] = None) -> Conjugations: + def parse(self, elem: Optional[XmlElement] = None) -> Conjugations: if elem is not None: # this is the the only Parser that doesn't use the elem argument, # of the Parser.parser() interface, so this method must implement # it even though it isn't used. raise ValueError("elem must be None") - templates: List[ConjugationTemplate] = [] + templates: list[ConjugationTemplate] = [] parser = etree.XMLParser( dtd_validation=True, encoding="utf-8", remove_blank_text=True, remove_comments=True # type: ignore ) @@ -75,7 +65,7 @@ def parse(self, elem: Optional[etree._Element] = None) -> Conjugations: if child.tag == "template": templates.append( ConjugationTemplateParser(lang=self.lang).parse( - cast(etree._Element, child) + cast(XmlElement, child) ) ) return Conjugations(self.lang, sorted(templates, key=lambda x: x.name)) diff --git a/src/verbecc/core/parsers/mood_template_parser.py b/src/verbecc/core/parsers/mood_template_parser.py new file mode 100755 index 0000000..5e6f54e --- /dev/null +++ b/src/verbecc/core/parsers/mood_template_parser.py @@ -0,0 +1,29 @@ +from typing import Optional + +from verbecc.core.defs.types.data.mood_template import MoodTemplate +from verbecc.core.defs.types.data.tense_template import TenseTemplate +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 as Lang +from verbecc.core.defs.types.mood import MoodFactory +from verbecc.core.defs.types.tense import TenseFactory +from verbecc.core.defs.types.tense import Tense +from verbecc.core.parsers.parser import Parser +from verbecc.core.parsers.tense_template_parser import TenseTemplateParser + +from verbecc.core.defs.types.data.xml_types import XmlElement +from verbecc.core.utils.xml_utils import xml_element_get_tag + +class MoodTemplateParser(Parser): + def __init__(self, lang: Lang) -> None: + self.lang = lang + + def parse(self, elem: Optional[XmlElement] = None) -> MoodTemplate: + if elem is None: + raise ValueError + mood = MoodFactory.from_string(self.lang, xml_element_get_tag(elem).lower()) + tense_templates: dict[Tense, TenseTemplate] = {} + for tense_elem in elem: + tense = TenseFactory.from_string(self.lang, xml_element_get_tag(tense_elem).lower()) + tense_templates[tense] = TenseTemplateParser( + lang=self.lang, mood=mood + ).parse(tense_elem) + return MoodTemplate(self.lang, mood, tense_templates) diff --git a/src/verbecc/core/parsers/parser.py b/src/verbecc/core/parsers/parser.py new file mode 100644 index 0000000..998542c --- /dev/null +++ b/src/verbecc/core/parsers/parser.py @@ -0,0 +1,11 @@ +from abc import ABC, abstractmethod +from typing import Optional + +from verbecc.core.defs.types.data.element import Element +from verbecc.core.defs.types.data.xml_types import XmlElement + +class Parser(ABC): + + @abstractmethod + def parse(self, elem: Optional[XmlElement] = None) -> Element: + pass diff --git a/verbecc/src/parsers/person_ending_parser.py b/src/verbecc/core/parsers/person_ending_parser.py similarity index 73% rename from verbecc/src/parsers/person_ending_parser.py rename to src/verbecc/core/parsers/person_ending_parser.py index a4f52bb..5adae9e 100755 --- a/verbecc/src/parsers/person_ending_parser.py +++ b/src/verbecc/core/parsers/person_ending_parser.py @@ -1,12 +1,13 @@ -from lxml import etree -from typing import List, Optional +from typing import Optional -from verbecc.src.utils.logging_utils import LoggingUtils -from verbecc.src.defs.types.data.person_ending import PersonEnding -from verbecc.src.defs.types.person import Person -from verbecc.src.defs.types.number import Number -from verbecc.src.defs.types.gender import Gender -from verbecc.src.parsers.parser import Parser +from verbecc.core.defs.types.data.xml_types import XmlElement +from verbecc.core.utils.logging_utils import LoggingUtils +from verbecc.core.defs.types.data.person_ending import PersonEnding +from verbecc.core.defs.types.person import Person +from verbecc.core.defs.types.number import Number +from verbecc.core.defs.types.gender import Gender +from verbecc.core.parsers.parser import Parser +from verbecc.core.utils.xml_utils import xml_element_findall, xml_element_get_text class PersonEndingParser(Parser): @@ -34,7 +35,7 @@ def __init__(self) -> None: def parse( self, - elem: Optional[etree._Element] = None, + elem: Optional[XmlElement] = None, person: Optional[Person] = None, number: Optional[Number] = None, gender: Optional[Gender] = None, @@ -60,13 +61,14 @@ def parse( """ if elem is None: raise ValueError("elem must not be None") - endings: List[str] = [] - i_elems = elem.findall("i", None) + endings: list[str] = [] + i_elems = xml_element_findall(elem, "i") if len(i_elems) == 0: self._logger.debug("Empty
element in conjugation template") for i_elem in i_elems: ending = str("") - if i_elem.text is not None: - ending += str(i_elem.text) + i_elem_text = xml_element_get_text(i_elem) + if i_elem_text is not None: + ending += i_elem_text endings.append(ending) return PersonEnding(person, number, gender, endings) diff --git a/verbecc/src/parsers/tense_template_parser.py b/src/verbecc/core/parsers/tense_template_parser.py similarity index 79% rename from verbecc/src/parsers/tense_template_parser.py rename to src/verbecc/core/parsers/tense_template_parser.py index b6f4cd7..6db565d 100755 --- a/verbecc/src/parsers/tense_template_parser.py +++ b/src/verbecc/core/parsers/tense_template_parser.py @@ -1,16 +1,17 @@ -from lxml import etree -from typing import List, Optional +from typing import Optional -from verbecc.src.utils.logging_utils import LoggingUtils -from verbecc.src.defs.constants import grammar_defines -from verbecc.src.defs.constants.localization import xmood -from verbecc.src.defs.types.data.person_ending import PersonEnding -from verbecc.src.defs.types.data.tense_template import TenseTemplate -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 as Lang -from verbecc.src.defs.types.mood import Mood, Moods -from verbecc.src.defs.types.tense import Tense, TenseFactory -from verbecc.src.parsers.parser import Parser -from verbecc.src.parsers.person_ending_parser import PersonEndingParser +from verbecc.core.defs.types.data.xml_types import XmlElement +from verbecc.core.utils.logging_utils import LoggingUtils +from verbecc.core.defs.constants import grammar_defines +from verbecc.core.defs.constants.localization import xmood +from verbecc.core.defs.types.data.person_ending import PersonEnding +from verbecc.core.defs.types.data.tense_template import TenseTemplate +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 as Lang +from verbecc.core.defs.types.mood import Mood, Moods +from verbecc.core.defs.types.tense import TenseFactory +from verbecc.core.parsers.parser import Parser +from verbecc.core.parsers.person_ending_parser import PersonEndingParser +from verbecc.core.utils.xml_utils import xml_element_get_tag, xml_element_to_string, xml_element_findall class TenseTemplateParser(Parser): @@ -41,7 +42,7 @@ def __init__(self, lang: Lang, mood: Mood) -> None: self.lang = lang self.mood = mood - def parse(self, elem: Optional[etree._Element] = None) -> TenseTemplate: + def parse(self, elem: Optional[XmlElement] = None) -> TenseTemplate: """ Normally each
elem defines six grammatical persons:
(see grammar_defines.PERSONS)
@@ -93,12 +94,12 @@ def parse(self, elem: Optional[etree._Element] = None) -> TenseTemplate:
"""
if elem is None:
raise ValueError("elem must not be None")
- self.tense = TenseFactory.from_string(self.lang, elem.tag)
- person_endings: List[PersonEnding] = []
+ self.tense = TenseFactory.from_string(self.lang, xml_element_get_tag(elem))
+ person_endings: list[PersonEnding] = []
person_num = 0
participle_inflections = grammar_defines.PARTICIPLE_INFLECTIONS[self.lang]
imperative_persons = grammar_defines.IMPERATIVE_PERSONS[self.lang]
- p_elems = elem.findall("p", namespaces=None)
+ p_elems = xml_element_findall(elem, "p")
for p_elem in p_elems:
gender = None
person = None
@@ -118,7 +119,7 @@ def parse(self, elem: Optional[etree._Element] = None) -> TenseTemplate:
self._logger.warning(
f"Unexpected number of participle inflections {len(p_elems)} "
+ f"on tense template for language {self.lang}: "
- + f"{[etree.tostring(p) for p in p_elems]}"
+ + f"{[xml_element_to_string(p) for p in p_elems]}"
)
elif self.mood == xmood(self.lang, Moods.en.Imperative):
if len(p_elems) == len(imperative_persons):
@@ -127,7 +128,7 @@ def parse(self, elem: Optional[etree._Element] = None) -> TenseTemplate:
self._logger.warning(
f"Unexpected number of imperative person inflections {len(p_elems)} "
+ f"on tense template for language {self.lang}: "
- + f"{[etree.tostring(p) for p in p_elems]}"
+ + f"{[xml_element_to_string(p) for p in p_elems]}"
)
else:
# normal case: all persons
diff --git a/src/verbecc/core/parsers/verb_parser.py b/src/verbecc/core/parsers/verb_parser.py
new file mode 100755
index 0000000..97e42ca
--- /dev/null
+++ b/src/verbecc/core/parsers/verb_parser.py
@@ -0,0 +1,42 @@
+from typing import Optional
+
+from verbecc.core.defs.types.data.verb import Verb
+from verbecc.core.defs.types.data.xml_types import XmlElement
+from verbecc.core.defs.types.exceptions import VerbsParserError
+from verbecc.core.parsers.parser import Parser
+from verbecc.core.utils.xml_utils import xml_element_get_tag, xml_element_find, xml_element_get_text, xml_element_to_string
+
+
+class VerbParser(Parser):
+ def __init__(self) -> None:
+ pass
+
+ def parse(self, elem: Optional[XmlElement] = None) -> Verb:
+ if elem is None:
+ raise ValueError("elem must not be None")
+ infinitive = ""
+ template = ""
+ translation_en = ""
+ if xml_element_get_tag(elem) != "v":
+ raise VerbsParserError("Unexpected element")
+ try:
+ infinitive : str = ""
+ e = xml_element_find(elem, "i")
+ if e is not None:
+ txt : str | None = xml_element_get_text(e)
+ infinitive = txt if txt is not None else ""
+ template : str = ""
+ e = xml_element_find(elem, "t")
+ if e is not None:
+ txt : str | None = xml_element_get_text(e)
+ template = txt if txt is not None else ""
+ translation_en : str = ""
+ e = xml_element_find(elem, "en")
+ if e is not None:
+ txt : str | None = xml_element_get_text(e)
+ translation_en = txt if txt is not None else ""
+ except AttributeError as e:
+ raise VerbsParserError(
+ "Error parsing {}: {}".format(xml_element_to_string(elem), str(e))
+ )
+ return Verb(infinitive, template, translation_en)
diff --git a/src/verbecc/core/parsers/verbs_parser.py b/src/verbecc/core/parsers/verbs_parser.py
new file mode 100755
index 0000000..c43d0dc
--- /dev/null
+++ b/src/verbecc/core/parsers/verbs_parser.py
@@ -0,0 +1,40 @@
+from io import BytesIO
+try:
+ # Python 3.11+
+ from importlib.resources.abc import Traversable # type: ignore
+except ImportError:
+ # Python 3.10 and earlier
+ from importlib.abc import Traversable # type: ignore
+from lxml import etree
+from importlib.resources import files
+
+
+from verbecc.core.defs.types.data.verb import Verb
+from verbecc.core.defs.types.data.verbs import Verbs
+from verbecc.core.defs.types.exceptions import VerbsParserError
+from verbecc.core.defs.types.lang_code import LangCodeISO639_1
+from verbecc.core.parsers.verb_parser import VerbParser
+
+
+class VerbsParser:
+ def __init__(self, lang: LangCodeISO639_1 = LangCodeISO639_1.fr) -> None:
+ self.lang = lang
+
+ def parse(self) -> Verbs:
+ ret: list[Verb] = []
+ parser = etree.XMLParser(encoding="utf-8", remove_blank_text=True, remove_comments=True) # type: ignore
+ source: Traversable = files("verbecc.data.xml.verbs").joinpath(
+ "verbs-{}.xml".format(self.lang)
+ )
+ with BytesIO(source.read_bytes()) as fp: # type: ignore
+ tree = etree.parse(fp, parser) # type: ignore
+ root = tree.getroot()
+ root_tag = "verbs-{}".format(self.lang)
+ if root.tag != root_tag:
+ raise VerbsParserError("Root XML Tag {} Not Found".format(root_tag))
+ for child in root:
+ if child.tag == "v":
+ ret.append(VerbParser().parse(child)) # type: ignore
+
+ ret = sorted(ret, key=lambda v: v.infinitive)
+ return Verbs(self.lang, ret)
diff --git a/verbecc/src/parsers/__init__.py b/src/verbecc/core/utils/__init__.py
similarity index 100%
rename from verbecc/src/parsers/__init__.py
rename to src/verbecc/core/utils/__init__.py
diff --git a/verbecc/src/utils/__init__.py b/src/verbecc/core/utils/config/__init__.py
similarity index 100%
rename from verbecc/src/utils/__init__.py
rename to src/verbecc/core/utils/config/__init__.py
diff --git a/verbecc/src/utils/config/base_config_util.py b/src/verbecc/core/utils/config/base_config_util.py
similarity index 54%
rename from verbecc/src/utils/config/base_config_util.py
rename to src/verbecc/core/utils/config/base_config_util.py
index 64c7858..cdc1da9 100644
--- a/verbecc/src/utils/config/base_config_util.py
+++ b/src/verbecc/core/utils/config/base_config_util.py
@@ -1,5 +1,11 @@
from abc import abstractmethod
-from importlib_resources import abc, as_file, files
+from importlib.resources import as_file, files
+try:
+ # Python 3.11+
+ from importlib.resources.abc import Traversable # type: ignore
+except ImportError:
+ # Python 3.10 and earlier
+ from importlib.abc import Traversable # type: ignore
from pathlib import Path
from typing import Optional, TextIO, TypeVar, Generic
@@ -21,24 +27,9 @@ def find_config_yaml_resource_path(self) -> None:
try:
# source path
self._yaml_resource_path = files("verbecc.config") / self.yaml_filename
- except KeyError as ex0:
+ except KeyError:
# unit-tests path
- try:
- self._yaml_resource_path = files("verbecc.verbecc.config") / self.yaml_filename
- except TypeError as ex1:
- # python <=3.9 hack
- try:
- dir_path = Path(__file__).parent.parent.parent
- self._yaml_resource_path = dir_path / "config" / self.yaml_filename
- while self._yaml_resource_path is None or not Path.exists(self._yaml_resource_path):
- self._yaml_resource_path = dir_path.parent / "config" / self.yaml_filename
-
- except Exception as ex2:
- msg = (
- "You are likely running an incompatible python version. "
- + f"_yaml_resource_path={self._yaml_resource_path} ex0={ex0} ex1={ex1} ex2={ex2}"
- )
- raise Exception(msg)
+ self._yaml_resource_path = files("verbecc.verbecc.config") / self.yaml_filename
def load_config(self) -> T:
"""Loads and returns the configuration."""
@@ -52,16 +43,10 @@ def _load_config_yaml_resource(self) -> T:
ret: Optional[T] = None
if self._yaml_resource_path is None:
raise Exception(f"Failed to load yaml config file {self.yaml_filename}")
- elif isinstance(self._yaml_resource_path, abc.Traversable): # type: ignore
- # python >= 3.10 code path:
+ elif isinstance(self._yaml_resource_path, Traversable): # type: ignore
with as_file(self._yaml_resource_path) as path:
with path.open("r", encoding="utf-8") as f:
ret = self._load_config_from_filestream(f)
- elif isinstance(self._yaml_resource_path, Path):
- # python <= 3.9 code path:
- path = self._yaml_resource_path
- with open(path, "r", encoding="utf-8") as f:
- ret = self._load_config_from_filestream(f)
if ret is not None:
return ret
else:
diff --git a/verbecc/src/utils/config/logging_config_util.py b/src/verbecc/core/utils/config/logging_config_util.py
similarity index 70%
rename from verbecc/src/utils/config/logging_config_util.py
rename to src/verbecc/core/utils/config/logging_config_util.py
index 011b3c0..b6e961f 100644
--- a/verbecc/src/utils/config/logging_config_util.py
+++ b/src/verbecc/core/utils/config/logging_config_util.py
@@ -1,13 +1,11 @@
from dataclasses import asdict
-from importlib_resources import abc, as_file, files
-from pathlib import Path
-from typing import Dict, Optional, TextIO
+from typing import Any, TextIO, cast
import logging
import logging.config
import yaml
-from verbecc.src.utils.config.base_config_util import BaseConfigUtil
-from verbecc.src.defs.types.config.logging.logging_config import (
+from verbecc.core.utils.config.base_config_util import BaseConfigUtil
+from verbecc.core.defs.types.config.logging.logging_config import (
LoggingConfig,
LoggerConfig,
FormatterConfig,
@@ -15,7 +13,7 @@
StreamHandlerConfig,
FileHandlerConfig,
)
-from verbecc.src.utils.dict_utils import DictUtils
+from verbecc.core.utils.dict_utils import DictUtils
class LoggingConfigUtil(BaseConfigUtil[LoggingConfig]):
@@ -35,7 +33,7 @@ def apply_config(self, logging_config: LoggingConfig) -> None:
try:
data = asdict(logging_config)
data = DictUtils.unmarshall_keys_recursive(data)
- logging.config.dictConfig(data)
+ logging.config.dictConfig(cast(dict[str, object], data))
except ValueError as ex:
raise ex
@@ -44,12 +42,17 @@ def _load_config_from_filestream(self, filestream: TextIO) -> LoggingConfig:
Manually convert the dictionary to our dataclass structure
This part can be simplified with libraries like `dacite` or `marshmallow-dataclass`
"""
- data = yaml.safe_load(filestream)
- data = DictUtils.marshall_keys_recursive(data, ["class"])
+ loaded_data = yaml.safe_load(filestream)
+ data = cast(dict[str, Any], loaded_data) if isinstance(loaded_data, dict) else {}
+ data = cast(
+ dict[str, Any], DictUtils.marshall_keys_recursive(data, ["class"])
+ )
+ formatters_data = cast(dict[str, dict[str, Any]], data.get("formatters", {}))
formatters = {
- name: FormatterConfig(**d) for name, d in data.get("formatters", {}).items()
+ name: FormatterConfig(**formatter_data)
+ for name, formatter_data in formatters_data.items()
}
- handlers: Dict[str, HandlerConfig] = {}
+ handlers: dict[str, HandlerConfig] = {}
for name, d in data.get("handlers", {}).items():
if name == "consoleHandler":
handlers[name] = StreamHandlerConfig(**d)
diff --git a/verbecc/src/utils/config/verbecc_config_util.py b/src/verbecc/core/utils/config/verbecc_config_util.py
similarity index 65%
rename from verbecc/src/utils/config/verbecc_config_util.py
rename to src/verbecc/core/utils/config/verbecc_config_util.py
index e4ea08b..fd410a1 100644
--- a/verbecc/src/utils/config/verbecc_config_util.py
+++ b/src/verbecc/core/utils/config/verbecc_config_util.py
@@ -1,7 +1,7 @@
from typing import TextIO
-from verbecc.src.utils.config.base_config_util import BaseConfigUtil
-from verbecc.src.defs.types.config.verbecc_config import VerbeccConfig
+from verbecc.core.utils.config.base_config_util import BaseConfigUtil
+from verbecc.core.defs.types.config.verbecc_config import VerbeccConfig
class VerbeccConfigUtil(BaseConfigUtil[VerbeccConfig]):
@@ -17,7 +17,9 @@ def __init__(self) -> None:
def _load_config_from_filestream(self, filestream: TextIO) -> VerbeccConfig:
ret = VerbeccConfig()
- data = VerbeccConfig.from_yaml(filestream)
+ data: VerbeccConfig | list[VerbeccConfig] = VerbeccConfig.from_yaml( # pyright: ignore[reportUnknownMemberType]
+ filestream
+ )
if isinstance(data, list):
ret = data[0]
else:
diff --git a/verbecc/src/utils/dict_utils.py b/src/verbecc/core/utils/dict_utils.py
similarity index 68%
rename from verbecc/src/utils/dict_utils.py
rename to src/verbecc/core/utils/dict_utils.py
index 7362d46..65c0b86 100644
--- a/verbecc/src/utils/dict_utils.py
+++ b/src/verbecc/core/utils/dict_utils.py
@@ -1,4 +1,4 @@
-from typing import cast, Dict, List, Any, Type
+from typing import Any, Type, cast
class DictUtils:
@@ -6,16 +6,16 @@ class DictUtils:
@staticmethod
def marshall_keys_recursive(
- data: Dict[str, Any],
- values_to_marshall: List[str],
+ data: Any,
+ values_to_marshall: list[str],
escape_str: str = DEFAULT_ESCAPE_STR,
- ) -> Dict[str, Any]:
+ ) -> dict[str, Any] | list[Any] | Any:
"""
Recursively appends escape_str to all keys matching values_to_marshall
"""
if isinstance(data, dict):
- new_data = {}
- for k, v in data.items():
+ new_data: dict[Any, Any] = {}
+ for k, v in cast(dict[Any, Any], data).items():
if k in values_to_marshall:
new_k = k + escape_str
new_data[new_k] = DictUtils.marshall_keys_recursive(
@@ -28,21 +28,22 @@ def marshall_keys_recursive(
return new_data
elif isinstance(data, list):
return [
- DictUtils.marshall_keys_recursive(v, values_to_marshall) for v in data
+ DictUtils.marshall_keys_recursive(v, values_to_marshall)
+ for v in cast(list[Any], data)
]
else:
return data
@staticmethod
def unmarshall_keys_recursive(
- data: Dict[str, Any], escape_str: str = DEFAULT_ESCAPE_STR
- ) -> Dict[str, Any]:
+ data: Any, escape_str: str = DEFAULT_ESCAPE_STR
+ ) -> dict[str, Any] | list[Any] | Any:
"""
Recursively strips trailing escape_str, if present, from all keys
"""
if isinstance(data, dict):
- new_data = {}
- for k, v in data.items():
+ new_data: dict[Any, Any] = {}
+ for k, v in cast(dict[Any, Any], data).items():
if k.endswith(escape_str):
new_k = k[:-1]
new_data[new_k] = DictUtils.unmarshall_keys_recursive(v)
@@ -50,24 +51,30 @@ def unmarshall_keys_recursive(
new_data[k] = DictUtils.unmarshall_keys_recursive(v)
return new_data
elif isinstance(data, list):
- return [DictUtils.unmarshall_keys_recursive(v) for v in data]
+ return [
+ DictUtils.unmarshall_keys_recursive(v)
+ for v in cast(list[Any], data)
+ ]
else:
return data
@staticmethod
- def cast_values_recursive(data: object, key: str, type: Type) -> object:
+ def cast_values_recursive(data: object, key: str, type: Type[Any]) -> object:
"""
Recursively casts values to the given type for all items with matching keys
"""
if isinstance(data, dict):
- new_data = {}
- for k, v in data.items():
+ new_data: dict[Any, Any] = {}
+ for k, v in cast(dict[Any, Any], data).items():
if k == key:
new_data[k] = type(v)
else:
new_data[k] = DictUtils.cast_values_recursive(v, key, type)
return new_data
elif isinstance(data, list):
- return [DictUtils.cast_values_recursive(v, key, type) for v in data]
+ return [
+ DictUtils.cast_values_recursive(v, key, type)
+ for v in cast(list[Any], data)
+ ]
else:
return data
diff --git a/verbecc/src/utils/jsbeautifier_utils.py b/src/verbecc/core/utils/jsbeautifier_utils.py
similarity index 91%
rename from verbecc/src/utils/jsbeautifier_utils.py
rename to src/verbecc/core/utils/jsbeautifier_utils.py
index 546e173..f86f27f 100644
--- a/verbecc/src/utils/jsbeautifier_utils.py
+++ b/src/verbecc/core/utils/jsbeautifier_utils.py
@@ -1,10 +1,9 @@
-import jsbeautifier
from dataclasses import fields
from typing import Optional
import jsbeautifier
-from verbecc.src.utils.config.verbecc_config_util import VerbeccConfigUtil
+from verbecc.core.utils.config.verbecc_config_util import VerbeccConfigUtil
class JSBeautifier:
diff --git a/verbecc/src/utils/json_utils.py b/src/verbecc/core/utils/json_utils.py
similarity index 84%
rename from verbecc/src/utils/json_utils.py
rename to src/verbecc/core/utils/json_utils.py
index 51a63f3..61164c6 100644
--- a/verbecc/src/utils/json_utils.py
+++ b/src/verbecc/core/utils/json_utils.py
@@ -2,8 +2,8 @@
from dataclasses import fields
import json
-from verbecc.src.utils.config.verbecc_config_util import VerbeccConfigUtil
-from verbecc.src.utils.jsbeautifier_utils import JSBeautifier
+from verbecc.core.utils.config.verbecc_config_util import VerbeccConfigUtil
+from verbecc.core.utils.jsbeautifier_utils import JSBeautifier
config = VerbeccConfigUtil().load_config()
@@ -29,7 +29,7 @@ def to_json(
json_opts.indent = indent
for field in fields(json_opts):
kwargs[field.name] = getattr(json_opts, field.name)
- ret = json.dumps(data, **kwargs)
+ ret = json.dumps(data, **kwargs) # type: ignore
if beautify:
ret = JSBeautifier.beautify(ret)
return ret
diff --git a/verbecc/src/utils/logging_utils.py b/src/verbecc/core/utils/logging_utils.py
similarity index 87%
rename from verbecc/src/utils/logging_utils.py
rename to src/verbecc/core/utils/logging_utils.py
index f12440c..c18566c 100644
--- a/verbecc/src/utils/logging_utils.py
+++ b/src/verbecc/core/utils/logging_utils.py
@@ -1,7 +1,7 @@
from typing import Optional
import logging
-from verbecc.src.utils.config.logging_config_util import LoggingConfigUtil
+from verbecc.core.utils.config.logging_config_util import LoggingConfigUtil
APP_NAME = "verbecc"
diff --git a/verbecc/src/utils/string_utils.py b/src/verbecc/core/utils/string_utils.py
similarity index 73%
rename from verbecc/src/utils/string_utils.py
rename to src/verbecc/core/utils/string_utils.py
index 2fdfd23..5c1fcd7 100755
--- a/verbecc/src/utils/string_utils.py
+++ b/src/verbecc/core/utils/string_utils.py
@@ -1,5 +1,4 @@
from collections import Counter
-from typing import Dict
import unicodedata
@@ -18,18 +17,10 @@ def starts_with_vowel(s: str, h_is_vowel: bool = False) -> bool:
return strip_accents(s)[0] in vowels
-def get_common_letters(s1: str, s2: str) -> Dict[str, int]:
+def get_common_letters(s1: str, s2: str) -> dict[str, int]:
common_letters = Counter(s1) & Counter(s2) # => {'q': 2, 'r': 1}
return common_letters
def get_common_letter_count(s1: str, s2: str) -> int:
return sum(get_common_letters(s1, s2).values())
-
-
-def unicodefix(s: str) -> str:
- # Fix Python 2.x.
- try:
- return s.decode("utf-8")
- except AttributeError:
- return s
diff --git a/verbecc/src/utils/utils.py b/src/verbecc/core/utils/utils.py
similarity index 82%
rename from verbecc/src/utils/utils.py
rename to src/verbecc/core/utils/utils.py
index adfea78..d81d803 100644
--- a/verbecc/src/utils/utils.py
+++ b/src/verbecc/core/utils/utils.py
@@ -1,5 +1,5 @@
-from verbecc.src.conjugator.complete_conjugator import CompleteConjugator
-from verbecc.src.defs.constants.grammar_defines import SUPPORTED_LANGUAGES
+from verbecc.core.conjugator.complete_conjugator import CompleteConjugator
+from verbecc.core.defs.constants.grammar_defines import SUPPORTED_LANGUAGES
def train_models() -> None:
diff --git a/src/verbecc/core/utils/xml_utils.py b/src/verbecc/core/utils/xml_utils.py
new file mode 100644
index 0000000..7c942b4
--- /dev/null
+++ b/src/verbecc/core/utils/xml_utils.py
@@ -0,0 +1,131 @@
+from pathlib import Path
+from typing import cast
+
+from lxml import etree
+from lxml import objectify
+
+from verbecc.core.defs.types.data.xml_types import XmlElement, XmlElementTree, XmlParser
+
+"""
+XML Utility functions for working with lxml.etree._Element objects in order
+to abstract away the dependency on lxml.etree, improving readability and maintainability.
+This module provides utility functions for converting XML elements to string representations.
+This also defines type aliases for XML elements and XML element trees to improve code readability
+and type safety.
+Type Aliases:
+ XmlElement: An alias for lxml.etree._Element, representing an XML element.
+ XmlElementTree: An alias for lxml.etree._ElementTree, representing an entire XML document tree.
+"""
+
+def xml_element_to_string(elem: XmlElement,
+ encoding: str="utf-8",
+ method: str="xml",
+ pretty_print: bool=True,
+ xml_declaration: bool=True) -> str:
+ """
+ Converts an XML element to a string representation.
+ Args:
+ elem (XmlElement): The XML element to convert.
+ Returns:
+ str: A string representation of the XML element."""
+ serialized = etree.tostring(cast(etree._Element, elem), encoding=encoding, method=method, xml_declaration=xml_declaration, pretty_print=pretty_print) # type: ignore
+ return serialized if isinstance(serialized, str) else serialized.decode(encoding)
+
+
+def xml_parse(path: Path, parser: XmlParser) -> XmlElementTree:
+ """
+ Parses an XML file and returns the corresponding XML element tree.
+ Args:
+ path (Path): The path to the XML file to parse.
+ parser (XmlParser): An instance of lxml.etree.XMLParser to use for parsing.
+ Returns:
+ XmlElementTree: The parsed XML element tree."""
+ return etree.parse(path, parser)
+
+
+def xml_element_deannotate(elem: XmlElement) -> None:
+ """
+ Removes annotations from an XML element and its descendants.
+ Args:
+ elem (XmlElement): The XML element to deannotate.
+ """
+ objectify.deannotate(elem, cleanup_namespaces=True)
+
+
+def xml_element_get_tag(elem: XmlElement) -> str:
+ """
+ Returns the tag name of an XML element.
+ Args:
+ elem (XmlElement): The XML element to get the tag name from.
+ Returns:
+ str: The tag name of the XML element."""
+ return cast(str, elem.tag) # type: ignore
+
+
+def xml_element_repr(elem: XmlElement) -> str:
+ return f"{xml_element_get_tag(elem)}: {elem} {xml_element_to_string(elem)}"
+
+
+def xml_element_xpath(elem: XmlElement, xpath_expr: str) -> list[XmlElement]:
+ """
+ Evaluates an XPath expression on an XML element and returns the matching elements.
+ Args:
+ elem (XmlElement): The XML element to evaluate the XPath expression on.
+ xpath_expr (str): The XPath expression to evaluate.
+ Returns:
+ list[XmlElement]: A list of matching XML elements."""
+ return cast(list[XmlElement], elem.xpath(xpath_expr)) # type: ignore
+
+
+def xml_element_remove(parent_elem: XmlElement, target_elem: XmlElement) -> None:
+ """
+ Removes an XML element from its parent.
+ Args:
+ parent_elem (XmlElement): The parent XML element.
+ target_elem (XmlElement): The target XML element to remove.
+ """
+ cast(etree._Element, parent_elem).remove(cast(etree._Element, target_elem)) # type: ignore
+
+
+def xml_element_get_attr(elem: XmlElement, attr_name: str, default: str | None = None) -> str | None:
+ """
+ Retrieves the value of an attribute from an XML element.
+ Args:
+ elem (XmlElement): The XML element to retrieve the attribute from.
+ attr_name (str): The name of the attribute to retrieve.
+ default (str, optional): The default value to return if the attribute is not found. Defaults to None.
+ Returns:
+ str: The value of the attribute, or the default value if not found."""
+ return cast(str, elem.get(attr_name, default=default)) # type: ignore
+
+
+def xml_element_find(elem: XmlElement, tag: str) -> XmlElement | None:
+ """
+ Finds a child element with a specific tag name.
+ Args:
+ elem (XmlElement): The XML element to search within.
+ tag (str): The tag name to search for.
+ Returns:
+ list[XmlElement]: A list of matching child XML elements."""
+ return cast(XmlElement | None, elem.find(tag)) # type: ignore
+
+
+def xml_element_findall(elem: XmlElement, tag: str) -> list[XmlElement]:
+ """
+ Finds all child elements with a specific tag name.
+ Args:
+ elem (XmlElement): The XML element to search within.
+ tag (str): The tag name to search for.
+ Returns:
+ list[XmlElement]: A list of matching child XML elements."""
+ return cast(list[XmlElement], elem.findall(tag)) # type: ignore
+
+
+def xml_element_get_text(elem: XmlElement) -> str | None:
+ """
+ Retrieves the text content of an XML element.
+ Args:
+ elem (XmlElement): The XML element to retrieve the text from.
+ Returns:
+ str: The text content of the XML element."""
+ return cast(str, elem.text) # type: ignore
\ No newline at end of file
diff --git a/verbecc/src/utils/yaml_utils.py b/src/verbecc/core/utils/yaml_utils.py
similarity index 86%
rename from verbecc/src/utils/yaml_utils.py
rename to src/verbecc/core/utils/yaml_utils.py
index 941f5dd..ec5d56a 100644
--- a/verbecc/src/utils/yaml_utils.py
+++ b/src/verbecc/core/utils/yaml_utils.py
@@ -1,8 +1,8 @@
import yaml
"""
-from verbecc.src.defs.types.person import Person
-from verbecc.src.defs.types.pronoun import Pronoun
+from verbecc.core.defs.types.person import Person
+from verbecc.core.defs.types.pronoun import Pronoun
class VerbeccYamlDumper(yaml.Dumper):
diff --git a/verbecc/data/models/dummy-file-because-github-doesnt-like-large-files.md b/src/verbecc/data/models/dummy-file-because-github-doesnt-like-large-files.md
similarity index 100%
rename from verbecc/data/models/dummy-file-because-github-doesnt-like-large-files.md
rename to src/verbecc/data/models/dummy-file-because-github-doesnt-like-large-files.md
diff --git a/verbecc/data/xml/conjugations/conjugations-ca.xml b/src/verbecc/data/xml/conjugations/conjugations-ca.xml
similarity index 100%
rename from verbecc/data/xml/conjugations/conjugations-ca.xml
rename to src/verbecc/data/xml/conjugations/conjugations-ca.xml
diff --git a/verbecc/data/xml/conjugations/conjugations-es.xml b/src/verbecc/data/xml/conjugations/conjugations-es.xml
similarity index 100%
rename from verbecc/data/xml/conjugations/conjugations-es.xml
rename to src/verbecc/data/xml/conjugations/conjugations-es.xml
diff --git a/verbecc/data/xml/conjugations/conjugations-fr.xml b/src/verbecc/data/xml/conjugations/conjugations-fr.xml
similarity index 100%
rename from verbecc/data/xml/conjugations/conjugations-fr.xml
rename to src/verbecc/data/xml/conjugations/conjugations-fr.xml
diff --git a/verbecc/data/xml/conjugations/conjugations-it.xml b/src/verbecc/data/xml/conjugations/conjugations-it.xml
similarity index 100%
rename from verbecc/data/xml/conjugations/conjugations-it.xml
rename to src/verbecc/data/xml/conjugations/conjugations-it.xml
diff --git a/verbecc/data/xml/conjugations/conjugations-pt.xml b/src/verbecc/data/xml/conjugations/conjugations-pt.xml
similarity index 100%
rename from verbecc/data/xml/conjugations/conjugations-pt.xml
rename to src/verbecc/data/xml/conjugations/conjugations-pt.xml
diff --git a/verbecc/data/xml/conjugations/conjugations-ro.xml b/src/verbecc/data/xml/conjugations/conjugations-ro.xml
similarity index 100%
rename from verbecc/data/xml/conjugations/conjugations-ro.xml
rename to src/verbecc/data/xml/conjugations/conjugations-ro.xml
diff --git a/verbecc/data/xml/verbs/verbs-ca.xml b/src/verbecc/data/xml/verbs/verbs-ca.xml
similarity index 100%
rename from verbecc/data/xml/verbs/verbs-ca.xml
rename to src/verbecc/data/xml/verbs/verbs-ca.xml
diff --git a/verbecc/data/xml/verbs/verbs-es.xml b/src/verbecc/data/xml/verbs/verbs-es.xml
similarity index 100%
rename from verbecc/data/xml/verbs/verbs-es.xml
rename to src/verbecc/data/xml/verbs/verbs-es.xml
diff --git a/verbecc/data/xml/verbs/verbs-fr.xml b/src/verbecc/data/xml/verbs/verbs-fr.xml
similarity index 100%
rename from verbecc/data/xml/verbs/verbs-fr.xml
rename to src/verbecc/data/xml/verbs/verbs-fr.xml
diff --git a/verbecc/data/xml/verbs/verbs-it.xml b/src/verbecc/data/xml/verbs/verbs-it.xml
similarity index 100%
rename from verbecc/data/xml/verbs/verbs-it.xml
rename to src/verbecc/data/xml/verbs/verbs-it.xml
diff --git a/verbecc/data/xml/verbs/verbs-pt.xml b/src/verbecc/data/xml/verbs/verbs-pt.xml
similarity index 100%
rename from verbecc/data/xml/verbs/verbs-pt.xml
rename to src/verbecc/data/xml/verbs/verbs-pt.xml
diff --git a/verbecc/data/xml/verbs/verbs-ro.xml b/src/verbecc/data/xml/verbs/verbs-ro.xml
similarity index 100%
rename from verbecc/data/xml/verbs/verbs-ro.xml
rename to src/verbecc/data/xml/verbs/verbs-ro.xml
diff --git a/src/verbecc/py.typed b/src/verbecc/py.typed
new file mode 100644
index 0000000..e69de29
diff --git a/src/verbecc/resources/fonts/Spectral-Bold.ttf b/src/verbecc/resources/fonts/Spectral-Bold.ttf
new file mode 100644
index 0000000..5019e08
Binary files /dev/null and b/src/verbecc/resources/fonts/Spectral-Bold.ttf differ
diff --git a/src/verbecc/resources/icons/README.md b/src/verbecc/resources/icons/README.md
new file mode 100644
index 0000000..5ed5848
--- /dev/null
+++ b/src/verbecc/resources/icons/README.md
@@ -0,0 +1,42 @@
+# Verbecc Icons
+
+> ⚠️
+> **Developer Only:** This section is intended exclusively for package maintainers and developers. Regular users can safely skip these instructions.
+
+### (Linux) commands used to convert SVG to PNG
+
+Best option is to install the TTF font, since inkscape and imagemagick don't support relative imports
+
+```bash
+# Install Spectral TTF font
+mkdir -p ~/.local/share/fonts
+cp ../fonts/Spectral-Bold.ttf ~/.local/share/fonts/
+fc-cache -f -v
+
+# Verify that font was installed (verify installed font name/style)
+$ fc-match "Spectral"
+Spectral-Bold.ttf: "Spectral" "Bold"
+$ fc-match "Spectral Bold"
+NotoSans-Regular.ttf: "Noto Sans" "Regular"
+$ fc-list | grep -i spectral
+/home/brett/.local/share/fonts/Spectral-Bold.ttf: Spectral:style=Bold
+
+# Convert logo SVG to PNG (32-bit, with transparent background)
+# 32-bit PNG (preserves the 24-bit RGB true color channels plus an 8-bit alpha transparency channel)
+magick -background none -size 512x512 -depth 8 -define png:color-type=6 logo.svg logo.png
+
+# Convert feature graphic SVG to PNG (24-bit, with white background)
+# 24-bit PNG (no-alpha)
+# -flatten: Tells ImageMagick to merge the transparent layers of the SVG onto that background color, completely removing the alpha channel.
+magick -background white -size 1024x500 -depth 8 -define png:color-type=2 feature-graphic.svg -flatten feature-graphic.png
+
+# Convert text elements to path and scale to 200x200 for android compatibility
+inkscape logo.svg --export-type=svg --export-text-to-path --export-width=200 --export-height=200 -o logo-android.svg
+
+```
+
+### About the Spectral Font
+
+> Spectral is an open-source, contemporary serif typeface commissioned by Google Fonts and designed by Production Type, a digital type foundry based in Paris led by Jean-Baptiste Levée.
+
+> Spectral (designed by Production Type) was designated as the official secondary typeface in the French government design system (Système de Design de l'État).
diff --git a/src/verbecc/resources/icons/feature-graphic.png b/src/verbecc/resources/icons/feature-graphic.png
new file mode 100644
index 0000000..e4c8ebe
Binary files /dev/null and b/src/verbecc/resources/icons/feature-graphic.png differ
diff --git a/src/verbecc/resources/icons/feature-graphic.svg b/src/verbecc/resources/icons/feature-graphic.svg
new file mode 100644
index 0000000..8d7ac01
--- /dev/null
+++ b/src/verbecc/resources/icons/feature-graphic.svg
@@ -0,0 +1,29 @@
+
diff --git a/src/verbecc/resources/icons/logo-android.svg b/src/verbecc/resources/icons/logo-android.svg
new file mode 100644
index 0000000..b8a7bbc
--- /dev/null
+++ b/src/verbecc/resources/icons/logo-android.svg
@@ -0,0 +1,55 @@
+
+
diff --git a/src/verbecc/resources/icons/logo.png b/src/verbecc/resources/icons/logo.png
new file mode 100644
index 0000000..9fd6d1c
Binary files /dev/null and b/src/verbecc/resources/icons/logo.png differ
diff --git a/src/verbecc/resources/icons/logo.svg b/src/verbecc/resources/icons/logo.svg
new file mode 100644
index 0000000..16930b8
--- /dev/null
+++ b/src/verbecc/resources/icons/logo.svg
@@ -0,0 +1,15 @@
+
diff --git a/tests/common.py b/tests/common.py
index f596c0a..1830701 100644
--- a/tests/common.py
+++ b/tests/common.py
@@ -1,4 +1,5 @@
import json
+from typing import Any
def assert_json_str_equal(s1: str, s2: str):
@@ -6,8 +7,8 @@ def assert_json_str_equal(s1: str, s2: str):
ss1_original = json.loads(s1)
ss2_original = json.loads(s2)
- ss1_type = type(ss1_original)
- ss2_type = type(ss2_original)
+ ss1_type: type[Any] = type(ss1_original) # type: ignore
+ ss2_type: type[Any] = type(ss2_original) # type: ignore
# check type first, we don't want to recurse if for example one is Dict and the other is List
is_type_match = ss1_type == ss2_type
@@ -25,9 +26,9 @@ def assert_json_str_equal(s1: str, s2: str):
for index, _ in enumerate(ss1):
ss1_child_value = ss1[index]
ss2_child_value = ss2[index]
- ss1_child_type = type(ss1_child_value)
- ss2_child_type = type(ss2_child_value)
- RECURSE_TYPES = [
+ ss1_child_type: type[Any] = type(ss1_child_value) # type: ignore
+ ss2_child_type: type[Any] = type(ss2_child_value) # type: ignore
+ RECURSE_TYPES: list[type[Any]] = [
type(tuple),
type(list),
type(dict),
diff --git a/tests/scripts/test_xml_modifier.py b/tests/scripts/test_xml_modifier.py
index 53b7a11..693834a 100644
--- a/tests/scripts/test_xml_modifier.py
+++ b/tests/scripts/test_xml_modifier.py
@@ -1,10 +1,14 @@
+from pathlib import Path
+
import pytest
+from lxml import etree
from scripts import xml_modifier
+from verbecc.core.utils.xml_utils import xml_element_to_string
"""
The "tests" in this module are for development purposes only
-and will normally be marked skip but may be unmarked skip
+and will normally be marked skip but may be unmarked skip
and ran with dry_run=True (test) or dry_run=False (do)
"""
@@ -15,8 +19,8 @@ def test_or_do_spanish_conjugation_xml_mods():
This is just a unit-test.
(unless I change dry_run to False, that is)
"""
- INPUT_PATH = "verbecc/data/xml/conjugations/conjugations-es.xml"
- OUTPUT_PATH = "verbecc/data/xml/conjugations/conjugations-es.mod.xml"
+ INPUT_PATH = Path("src/verbecc/data/xml/conjugations/conjugations-es.xml")
+ OUTPUT_PATH = Path("src/verbecc/data/xml/conjugations/conjugations-es.mod.xml")
xml_modifier.do_spanish_mods(INPUT_PATH, OUTPUT_PATH, dry_run=True)
@@ -26,6 +30,28 @@ def test_or_do_portuguese_conjugation_xml_mods():
This is just a unit-test.
(unless I change dry_run to False, that is)
"""
- INPUT_PATH = "verbecc/data/xml/conjugations/conjugations-pt.xml"
- OUTPUT_PATH = "verbecc/data/xml/conjugations/conjugations-pt.mod.xml"
+ INPUT_PATH = Path("src/verbecc/data/xml/conjugations/conjugations-pt.xml")
+ OUTPUT_PATH = Path("src/verbecc/data/xml/conjugations/conjugations-pt.mod.xml")
xml_modifier.do_portuguese_mods(INPUT_PATH, OUTPUT_PATH, dry_run=True)
+
+
+@pytest.mark.parametrize("encoding", ["utf-8", "iso-8859-1", "unicode"])
+def test_xml_element_to_string_decodes_serialized_xml(encoding):
+ elem = etree.fromstring(" ai as a avons avez ont ai as a avons avez ont eu eus eue eues
eu
+eus
+eue
+eues
+ """, parser=None, ) tense_template = TenseTemplateParser(Lang.fr, mood).parse(tense_elem) - tc = tcg._tense_conjugator_simple._conjugate_simple_mood_tense( + tc = tcg._get_tense_conjugator_simple().conjugate_simple_mood_tense( co.verb_stem, mood, tense, @@ -690,20 +696,20 @@ def test_inflector_fr_conjugate_simple_avoir_participe_participe_passé(tcg): ) -def test_inflector_fr_conjugate_simple_avoir_particpe_participe_présent(tcg): +def test_inflector_fr_conjugate_simple_avoir_particpe_participe_présent(tcg: TenseConjugator): infinitive = "avoir" - co = tcg._get_conj_obs(infinitive) + co = tcg._get_conj_objs(infinitive) assert co.verb_stem == "" mood = Moods.fr.Participe tense = Tenses.fr.ParticipePresent tense_elem = etree.fromstring( """ayant
-ayant
+ """, parser=None, ) tense_template = TenseTemplateParser(Lang.fr, mood).parse(tense_elem) - tc = tcg._tense_conjugator_simple._conjugate_simple_mood_tense( + tc = tcg._get_tense_conjugator_simple().conjugate_simple_mood_tense( co.verb_stem, mood, tense, @@ -720,24 +726,24 @@ def test_inflector_fr_conjugate_simple_avoir_particpe_participe_présent(tcg): ) -def test_inflector_fr_conjugate_simple_avoir_infinitif_présent(tcg): +def test_inflector_fr_conjugate_simple_avoir_infinitif_présent(tcg: TenseConjugator): """ Test infinitif because it's the only one with neither person, number, gender nor pronoun. """ infinitive = "avoir" - co = tcg._get_conj_obs(infinitive) + co = tcg._get_conj_objs(infinitive) assert co.verb_stem == "" mood = Moods.fr.Infinitif tense = Tenses.fr.InfinitifPrésent tense_elem = etree.fromstring( """avoir
-avoir
+ """, parser=None, ) tense_template = TenseTemplateParser(Lang.fr, mood).parse(tense_elem) - tc = tcg._tense_conjugator_simple._conjugate_simple_mood_tense( + tc = tcg._get_tense_conjugator_simple().conjugate_simple_mood_tense( co.verb_stem, mood, tense, @@ -754,22 +760,22 @@ def test_inflector_fr_conjugate_simple_avoir_infinitif_présent(tcg): ) -def test_inflector_fr_conjugate_simple_avoir_imperatif_présent(tcg): +def test_inflector_fr_conjugate_simple_avoir_imperatif_présent(tcg: TenseConjugator): infinitive = "avoir" - co = tcg._get_conj_obs(infinitive) + co = tcg._get_conj_objs(infinitive) assert co.verb_stem == "" mood = Moods.fr.Imperatif tense = Tenses.fr.ImperatifPrésent tense_elem = etree.fromstring( """aie
-ayons
-ayez
-aie
+ayons
+ayez
+ """, parser=None, ) tense_template = TenseTemplateParser(Lang.fr, mood).parse(tense_elem) - tc = tcg._tense_conjugator_simple._conjugate_simple_mood_tense( + tc = tcg._get_tense_conjugator_simple().conjugate_simple_mood_tense( co.verb_stem, mood, tense, @@ -790,7 +796,7 @@ def test_inflector_fr_conjugate_simple_avoir_imperatif_présent(tcg): assert tc == expected_value -def test_combine_pronoun_and_conj(ccg): +def test_combine_pronoun_and_conj(ccg: CompleteConjugator): """ E.g. "je" + "mange" = "je mange" E.g. "elle" + "a " = "elle a" @@ -801,31 +807,31 @@ def test_combine_pronoun_and_conj(ccg): E.g. "ils se" = "habillent" = "ils s'habillent" E.g. "ils se" + "étaient" = "ils s'étaient """ - assert ccg._inflector.combine_pronoun_and_conj("je", "mange") == "je mange" - assert ccg._inflector.combine_pronoun_and_conj("elle", "a") == "elle a" - assert ccg._inflector.combine_pronoun_and_conj("je", "ai") == "j'ai" - assert ccg._inflector.combine_pronoun_and_conj("je me", "habille") == "je m'habille" + assert ccg._get_inflector().combine_pronoun_and_conj("je", "mange") == "je mange" + assert ccg._get_inflector().combine_pronoun_and_conj("elle", "a") == "elle a" + assert ccg._get_inflector().combine_pronoun_and_conj("je", "ai") == "j'ai" + assert ccg._get_inflector().combine_pronoun_and_conj("je me", "habille") == "je m'habille" assert ( - ccg._inflector.combine_pronoun_and_conj("tu te", "habilles") == "tu t'habilles" + ccg._get_inflector().combine_pronoun_and_conj("tu te", "habilles") == "tu t'habilles" ) - assert ccg._inflector.combine_pronoun_and_conj("il se", "habille") == "il s'habille" + assert ccg._get_inflector().combine_pronoun_and_conj("il se", "habille") == "il s'habille" assert ( - ccg._inflector.combine_pronoun_and_conj("elle se", "habille") + ccg._get_inflector().combine_pronoun_and_conj("elle se", "habille") == "elle s'habille" ) assert ( - ccg._inflector.combine_pronoun_and_conj("ils se", "habille") == "ils s'habille" + ccg._get_inflector().combine_pronoun_and_conj("ils se", "habille") == "ils s'habille" ) assert ( - ccg._inflector.combine_pronoun_and_conj("elles se", "habille") + ccg._get_inflector().combine_pronoun_and_conj("elles se", "habille") == "elles s'habille" ) - assert ccg._inflector.combine_pronoun_and_conj("je", "étais") == "j'étais" - assert ccg._inflector.combine_pronoun_and_conj("il", "était") == "il était" - assert ccg._inflector.combine_pronoun_and_conj("elle", "était") == "elle était" - assert ccg._inflector.combine_pronoun_and_conj("elle se", "était") == "elle s'était" + assert ccg._get_inflector().combine_pronoun_and_conj("je", "étais") == "j'étais" + assert ccg._get_inflector().combine_pronoun_and_conj("il", "était") == "il était" + assert ccg._get_inflector().combine_pronoun_and_conj("elle", "était") == "elle était" + assert ccg._get_inflector().combine_pronoun_and_conj("elle se", "était") == "elle s'était" assert ( - ccg._inflector.combine_pronoun_and_conj("ils se", "étaient") == "ils s'étaient" + ccg._get_inflector().combine_pronoun_and_conj("ils se", "étaient") == "ils s'étaient" ) diff --git a/tests/test_inflectors/test_inflector_fr_to_json.py b/tests/test_inflectors/test_inflector_fr_to_json.py index 85f56cd..8e6b3f6 100644 --- a/tests/test_inflectors/test_inflector_fr_to_json.py +++ b/tests/test_inflectors/test_inflector_fr_to_json.py @@ -1,12 +1,19 @@ import pytest import json +import sys +from pathlib import Path +from typing import Any -from tests.common import assert_json_str_equal +try: + from tests.common import assert_json_str_equal +except ModuleNotFoundError: + sys.path.insert(0, str(Path(__file__).resolve().parents[1])) + from common import assert_json_str_equal -from verbecc.src.conjugator.complete_conjugator import CompleteConjugator -from verbecc.src.conjugator.mood_conjugator import MoodConjugator -from verbecc.src.conjugator.tense_conjugator import TenseConjugator -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 as Lang +from verbecc.core.conjugator.complete_conjugator import CompleteConjugator +from verbecc.core.conjugator.mood_conjugator import MoodConjugator +from verbecc.core.conjugator.tense_conjugator import TenseConjugator +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 as Lang @pytest.fixture(scope="module") @@ -27,7 +34,7 @@ def tcg(): yield tcg -expected_value_conj_manger = { +expected_value_conj_manger: dict[str, dict[str, Any]] = { "moods": { "conditionnel": { "passé": [ @@ -414,7 +421,7 @@ def tcg(): }, } -expected_value_conj_pouvoir = { +expected_value_conj_pouvoir: dict[str, dict[str, Any]] = { "moods": { "conditionnel": { "passé": [ @@ -686,7 +693,7 @@ def tcg(): } -expected_value_conj_pleuvoir = { +expected_value_conj_pleuvoir: dict[str, dict[str, Any]] = { "moods": { "conditionnel": { "passé": [ @@ -881,7 +888,7 @@ def tcg(): } -expected_value_conj_se_lever = { +expected_value_conj_se_lever: dict[str, dict[str, Any]] = { "moods": { "conditionnel": { "passé": [ @@ -1565,8 +1572,8 @@ def tcg(): python -m pytest . -vv -k test_conjugate[Se lever-expected_value4] I think this pattern of -many "def test_yez
ientyent
""" - tense_elem: etree._Element = etree.fromstring(tense_elem_str) + tense_elem: XmlElement = etree.fromstring(tense_elem_str) tense_template = TenseTemplateParser(Lang.fr, mood).parse(tense_elem) assert tense_template.mood == mood assert tense_template.tense == tense diff --git a/tests/test_parser/test_verb_parser.py b/tests/test_parser/test_verb_parser.py index 680a09c..36f17ad 100644 --- a/tests/test_parser/test_verb_parser.py +++ b/tests/test_parser/test_verb_parser.py @@ -1,14 +1,13 @@ -from unittest.mock import patch +from unittest.mock import MagicMock, patch import pytest -from verbecc.src.parsers.verb_parser import VerbParser -from verbecc.src.defs.types.exceptions import VerbsParserError -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 as Lang +from verbecc.core.parsers.verb_parser import VerbParser +from verbecc.core.defs.types.exceptions import VerbsParserError @patch("lxml.etree._Element") -def test_verb_invalid_xml(mock_v_elem): +def test_verb_invalid_xml(mock_v_elem: MagicMock): v = VerbParser() mock_v_elem.tag.return_value = "not-v" with pytest.raises(VerbsParserError): diff --git a/tests/test_parser/test_verbs_parser.py b/tests/test_parser/test_verbs_parser.py index df44eab..c8aee90 100755 --- a/tests/test_parser/test_verbs_parser.py +++ b/tests/test_parser/test_verbs_parser.py @@ -1,5 +1,5 @@ -from verbecc.src.parsers.verbs_parser import VerbsParser -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 as Lang +from verbecc.core.parsers.verbs_parser import VerbsParser +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 as Lang def test_verbs_parser(): diff --git a/tests/test_public_api.py b/tests/test_public_api.py new file mode 100644 index 0000000..9c6917b --- /dev/null +++ b/tests/test_public_api.py @@ -0,0 +1,16 @@ +from verbecc import CompleteConjugator +from verbecc.core import CompleteConjugator as CoreCompleteConjugator +from verbecc.core.conjugator import CompleteConjugator as PackageCompleteConjugator +from verbecc.core.conjugator.complete_conjugator import CompleteConjugator as ImplementationCompleteConjugator +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 as Lang + + +def test_complete_conjugator_re_exports() -> None: + assert CompleteConjugator is CoreCompleteConjugator + assert CompleteConjugator is PackageCompleteConjugator + assert CompleteConjugator is ImplementationCompleteConjugator + + +def test_public_complete_conjugator_conjugates() -> None: + conjugator = CompleteConjugator(lang=Lang.fr) + assert conjugator.conjugate("parler") diff --git a/tests/test_string_utils.py b/tests/test_string_utils.py index 157c7df..eb4ec9d 100755 --- a/tests/test_string_utils.py +++ b/tests/test_string_utils.py @@ -1,9 +1,8 @@ -from verbecc.src.utils.string_utils import ( +from verbecc.core.utils.string_utils import ( get_common_letters, get_common_letter_count, starts_with_vowel, strip_accents, - unicodefix, ) @@ -30,7 +29,3 @@ def test_get_common_letters_count(): assert get_common_letter_count("brett", "tolbert") == 5 assert get_common_letter_count("çar", "cer") == 1 assert get_common_letter_count(strip_accents("çar"), "cer") == 2 - - -def test_unicodefix(): - assert unicodefix("éparpiller") == "éparpiller" diff --git a/tests/test_to_json.py b/tests/test_to_json.py index 4d18819..adf5663 100644 --- a/tests/test_to_json.py +++ b/tests/test_to_json.py @@ -1,9 +1,9 @@ import pytest -from verbecc.src.conjugator.tense_conjugator import TenseConjugator -from verbecc.src.defs.types.tense import Tenses -from verbecc.src.defs.types.mood import Moods -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 as Lang +from verbecc.core.conjugator.tense_conjugator import TenseConjugator +from verbecc.core.defs.types.tense import Tenses +from verbecc.core.defs.types.mood import Moods +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 as Lang @pytest.fixture(scope="module") @@ -12,7 +12,7 @@ def tcg(): yield tcg -def test_ensure_ascii(tcg): +def test_ensure_ascii(tcg: TenseConjugator) -> None: """ Test to ensure json.dumps is being called with ensure_ascii=True diff --git a/tests/test_types/test_verbs.py b/tests/test_types/test_verbs.py index a35118f..41de5f2 100644 --- a/tests/test_types/test_verbs.py +++ b/tests/test_types/test_verbs.py @@ -1,27 +1,27 @@ -from unittest.mock import patch +from typing import Generator import pytest -from verbecc.src.parsers.verbs_parser import VerbsParser -from verbecc.src.defs.types.data.verbs import Verbs -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 as Lang +from verbecc.core.defs.types.data.verbs import Verbs +from verbecc.core.parsers.verbs_parser import VerbsParser +from verbecc.core.defs.types.lang_code import LangCodeISO639_1 as Lang @pytest.fixture(scope="module") -def verbs(): +def verbs() -> Generator[Verbs, None, None]: vp = VerbsParser(Lang.fr) verbs = vp.parse() yield verbs -def test_verb(verbs): +def test_verb(verbs: Verbs) -> None: verb = verbs.find_verb_by_infinitive("manger") assert verb.infinitive == "manger" assert verb.template == "man:ger" assert verb.translation_en == "eat" -def test_verb_two(verbs): +def test_verb_two(verbs: Verbs) -> None: verb = verbs.find_verb_by_infinitive("abattre") assert verb.infinitive == "abattre" assert verb.template == "bat:tre" @@ -35,6 +35,6 @@ def test_verb_two(verbs): ("Mang", ["mangeotter", "manger"]), ], ) -def test_get_verbs_that_start_with(query, expected_matches, verbs): +def test_get_verbs_that_start_with(query: str, expected_matches: list[str], verbs: Verbs) -> None: matches = verbs.get_verbs_that_start_with(query) assert matches == expected_matches diff --git a/tox.ini b/tox.ini deleted file mode 100755 index 8714106..0000000 --- a/tox.ini +++ /dev/null @@ -1,11 +0,0 @@ -[tox] -envlist = py312 - -[testenv] -deps = - -r{toxinidir}/requirements.txt - pytest-cov==4.1.0 - setuptools==69.0.3 -commands = - pip install -e . - python -m pytest --cov-report xml:coverage.xml --cov=verbecc . diff --git a/typings/jsbeautifier/__init__.pyi b/typings/jsbeautifier/__init__.pyi new file mode 100644 index 0000000..67f7eb5 --- /dev/null +++ b/typings/jsbeautifier/__init__.pyi @@ -0,0 +1,20 @@ +from typing import Any, TextIO + + +class BeautifierOptions: + def __init__(self, options: Any = ...) -> None: ... + + +def default_options() -> BeautifierOptions: ... + + +def beautify(string: str, opts: BeautifierOptions = ...) -> str: ... + + +def beautify_file(file_name: str, opts: BeautifierOptions = ...) -> str: ... + + +def usage(stream: TextIO = ...) -> int: ... + + +def main() -> None: ... \ No newline at end of file diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..0858358 --- /dev/null +++ b/uv.lock @@ -0,0 +1,1153 @@ +version = 1 +revision = 5 +requires-python = ">=3.10" +resolution-markers = [ + "python_full_version >= '3.12'", + "python_full_version == '3.11.*'", + "python_full_version < '3.11'", +] + +[[package]] +name = "backports-strenum" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/35/c7/2ed54c32fed313591ffb21edbd48db71e68827d43a61938e5a0bc2b6ec91/backports_strenum-1.3.1.tar.gz", hash = "sha256:77c52407342898497714f0596e86188bb7084f89063226f4ba66863482f42414", size = 7257, upload-time = "2023-12-09T14:36:40.937Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d6/50/56cf20e2ee5127b603b81d5a69580a1a325083e2b921aa8f067da83927c0/backports_strenum-1.3.1-py3-none-any.whl", hash = "sha256:cdcfe36dc897e2615dc793b7d3097f54d359918fc448754a517e6f23044ccf83", size = 8304, upload-time = "2023-12-09T14:36:39.905Z" }, +] + +[[package]] +name = "cloudpickle" +version = "3.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/27/fb/576f067976d320f5f0114a8d9fa1215425441bb35627b1993e5afd8111e5/cloudpickle-3.1.2.tar.gz", hash = "sha256:7fda9eb655c9c230dab534f1983763de5835249750e85fbcef43aaa30a9a2414", size = 22330, upload-time = "2025-11-03T09:25:26.604Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl", hash = "sha256:9acb47f6afd73f60dc1df93bb801b472f05ff42fa6c84167d25cb206be1fbf4a", size = 22228, upload-time = "2025-11-03T09:25:25.534Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +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/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 = "cython" +version = "3.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/99/ca/18e324972e5cac914816fdd7bb03e19a455b90039c277a538f7781b50c85/cython-3.3.1.tar.gz", hash = "sha256:e0e45989e821bef6aa9ae15c7d583ab5e055f7406c4b3624e49e06d24e90375a", size = 3743354, upload-time = "2026-11-01T20:12:04.773Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/c6/52279cc4cea73ba4ee0a8076514bac97abd8b9ed0276f34e1d19cd3f4c2a/cython-3.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7c1f05344b32ecbb83e3bbd3586282ac1f4aedeb8025cc6e13f22a6d4e2b4222", size = 3142271, upload-time = "2026-11-01T20:12:21.147Z" }, + { url = "https://files.pythonhosted.org/packages/db/8c/79770fcd3d80f40d0ef2b38cbeb66686f19c8a9b23061c05cd3f4b43b1ff/cython-3.3.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08ef3dcd3070959983a15e82bbfd56edb13cbe75b14043665c76ee4425140eaf", size = 3350594, upload-time = "2026-11-01T20:12:23.088Z" }, + { url = "https://files.pythonhosted.org/packages/82/33/e8d7d8d8e6165416689763d8675872d01b6c1c08fd2312db7b8e68ed0edb/cython-3.3.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14bd1521a14d98bed4ae791ace5e830055ffc45a8cbb09f22adf90ee7dca3409", size = 3482473, upload-time = "2026-11-01T20:12:25.212Z" }, + { url = "https://files.pythonhosted.org/packages/6a/1d/b86524bee9f664b61608757456fe47e0d4cc5f4bf02802ca03fcbcf7d72f/cython-3.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:747dade0373011034645ace4e7eb3a54102c52524fc0675dea76e655e9c1dcff", size = 2861943, upload-time = "2026-11-01T20:12:26.931Z" }, + { url = "https://files.pythonhosted.org/packages/14/e1/bad59c9ce7931f5c2b7cd9d5228d16926373267bb841aa8a4b29a1ab3c3a/cython-3.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0ce9efd76bfbf7b67be0da80d450231e1c1bdd5e755d7a8dc10ffc2669fc5edf", size = 3135399, upload-time = "2026-11-01T20:12:28.657Z" }, + { url = "https://files.pythonhosted.org/packages/21/33/cb2588a238d862ebc5e973acc3504ec28764bcc4273828f8e0915354415f/cython-3.3.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:43b16388665cb829c265060705900db8e26e9c3c04cc91f28af38c905d12293f", size = 3351071, upload-time = "2026-11-01T20:12:31.078Z" }, + { url = "https://files.pythonhosted.org/packages/5f/78/1e8562e6dc57f6b9398bc754dcaf574f71762a5a637bb6525ae06cdc7f91/cython-3.3.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:26a28e0ca5dffe9c7d69d1e3a0f78cb74f41b2b6b40771f620262a5d04862a00", size = 3483723, upload-time = "2026-11-01T20:12:33.044Z" }, + { url = "https://files.pythonhosted.org/packages/de/44/55cfaaba499dcd06fb998bf64d3839f7208e80b2acb1dabcdec515d26bf9/cython-3.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:298d3e46d1d4e2f4405d2c934b51899482101a0b0dc43b1b13b2e38f87addf52", size = 2866366, upload-time = "2026-11-01T20:12:35.09Z" }, + { url = "https://files.pythonhosted.org/packages/40/3f/362d57b505de56a3a24f84a94b2e09772ebbc9d05402e9c3bbe7b1b780a5/cython-3.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:744bb804252cf204e6bc9b0fac06b3bad7bb14258cefb9f321c59c4c59e9bc17", size = 3145239, upload-time = "2026-11-01T20:12:37.11Z" }, + { url = "https://files.pythonhosted.org/packages/4f/9d/016dfaefc1a10e182fd770e6c331ebf79df88a527883b4ecbdd74abb9969/cython-3.3.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f08b3eaa639005bea6ab119ebbd6e30656e448981e7a124d80b409760d06c15", size = 3262357, upload-time = "2026-11-01T20:12:38.861Z" }, + { url = "https://files.pythonhosted.org/packages/4a/c6/51ffdd996a1e6836792061ebe7ecf40480f1bd5693a721cea0ad4a689a81/cython-3.3.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:215669fd0ce792080cd4d0748db7e1e31f424b6706a6220d08339895e6a3a03a", size = 3418124, upload-time = "2026-11-01T20:12:41.076Z" }, + { url = "https://files.pythonhosted.org/packages/4c/6b/de4b5b3f43bccd82ef48071a33c48315098867eafe6ae3a39f1064f8d331/cython-3.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:fd81cfc6e94c43c5c0fe50439c11b90dc89cc6b323f92b37edc6a951d0a619d7", size = 2875470, upload-time = "2026-11-01T20:12:43.169Z" }, + { url = "https://files.pythonhosted.org/packages/4c/c1/15881737c54e90c83ff314998b363a2069ec184bf642f2cce9222dc631c8/cython-3.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6156be528b46e820ba834449716690d5065049ff355f261a8600f7da6b436d96", size = 3136530, upload-time = "2026-11-01T20:12:44.807Z" }, + { url = "https://files.pythonhosted.org/packages/64/db/73a6f5f560b7f77fa5f2b5dca15f761f0598776f47951356449e162a4514/cython-3.3.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d0f2610ce850d264e29a87b3d9b8ec4f0f2dec5bc1dce0398294251f09b149df", size = 3257359, upload-time = "2026-11-01T20:12:46.783Z" }, + { url = "https://files.pythonhosted.org/packages/a3/04/5445c845d08948b4006c72b5bc202b63f108ff0b87161a993dc5922106a0/cython-3.3.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85be5442e8f465c7c5e80837ac2a85a2ce04034e616445113092e85b65d0ab94", size = 3413336, upload-time = "2026-11-01T20:12:48.701Z" }, + { url = "https://files.pythonhosted.org/packages/e2/2d/8afe74009f266c43033dc54d851f31edadc414842cc061bd2762ffc9737f/cython-3.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:0f7d52979bf7730351cf9ca2e9257d4b80f729053b521159bab8666e6be7e3bd", size = 2869329, upload-time = "2026-11-01T20:12:50.577Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f4/2892e59c7e75e75766021c40c165a30edbbfdae4efb6e10cb3fd23486b66/cython-3.3.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3370326802b82cc7cb7df65e605e1acfebdce193077e27ed5734b9bc3f7c6ad0", size = 3188251, upload-time = "2026-11-01T20:12:52.507Z" }, + { url = "https://files.pythonhosted.org/packages/8d/94/dad3d60dcbf22616ee6564456ffc3b6594d5cac9b91735f34ab90633326c/cython-3.3.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0eac1184dd57591a8f3d25691c7a6bf7db030f515b210691bd251772a7e70a4", size = 3335776, upload-time = "2026-11-01T20:12:54.507Z" }, + { url = "https://files.pythonhosted.org/packages/07/d4/6cb0c23f8f3e7081c3af03ccf685a73cfa86af85725b9f4c44040e5f8858/cython-3.3.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7a6c191617853f2e0d5936c73f5d5cd096548f4d9e0fa37612ef721591c42cb3", size = 3459005, upload-time = "2026-11-01T20:12:56.224Z" }, + { url = "https://files.pythonhosted.org/packages/82/69/8efe9179f9f139d4fbe367e5e76e40673c87450f3f4ed1a5c1350be365bf/cython-3.3.1-cp314-cp314-win_amd64.whl", hash = "sha256:7bcc6de1603d8180667b40f4014be142d7d62cfc10af0184ad8d6a83847a2ced", size = 2928989, upload-time = "2026-11-01T20:12:58.247Z" }, + { url = "https://files.pythonhosted.org/packages/cb/37/231f00ec8f6a56519aea9cef921ae9c5d4c39edd8b5557d0de9048211004/cython-3.3.1-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:a1bfd7511fe8d83f5e681876df22878efac5cd5b2c174f272e6bf018c8fd4a91", size = 3179367, upload-time = "2026-11-01T20:12:59.906Z" }, + { url = "https://files.pythonhosted.org/packages/3c/b1/a0ed5165b268fe2d52929e08e9e89278b6f2eeee1c49c9976ba64ef194b7/cython-3.3.1-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bce8f37f50add0432ac802cfc34e5bd16395f2918ad1eaeb50b26d02c9001014", size = 3331494, upload-time = "2026-11-01T20:13:01.774Z" }, + { url = "https://files.pythonhosted.org/packages/63/e4/4ef74af67d86067258187a24764df2d9d9bf9adb0b78712862dea051eaff/cython-3.3.1-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fcb6c86dddaedd1da5d77ba2469c1a4bea52442e02d8f0653ff78667fbaaa8d9", size = 3456176, upload-time = "2026-11-01T20:13:03.833Z" }, + { url = "https://files.pythonhosted.org/packages/a2/0e/0458355eb10a33315ede98d91a40b5848f3302cf4e9b44c70211a592ae3a/cython-3.3.1-cp315-cp315-win_amd64.whl", hash = "sha256:45dd533a87c9629d02d77c9a5b48cf399907a99e4bb556aebafd2ac4b68580d2", size = 2927687, upload-time = "2026-11-01T20:13:05.712Z" }, + { url = "https://files.pythonhosted.org/packages/d7/4e/548df758dbbea481ab054e062933252753b8db86757894bbb1fa84bd9292/cython-3.3.1-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c4e4132b03a6c6c11541f7498441224f55a9e101c615d49494983d2b10dd7669", size = 3066885, upload-time = "2026-11-01T20:13:07.719Z" }, + { url = "https://files.pythonhosted.org/packages/87/55/61840ec209f861887ca547c75c401a493be6c034c1d9ad8f9b628b607054/cython-3.3.1-cp39-abi3-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:226d791808ce95f20ab1b3589082be604b5b5b31e670bf773ef9c312d2f0a8c2", size = 3361449, upload-time = "2026-11-01T20:13:09.398Z" }, + { url = "https://files.pythonhosted.org/packages/96/b1/16e743c3fbfa6424d9c94430934b5bde3a696e7b72c1476e284fdcd1210f/cython-3.3.1-cp39-abi3-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4d1f9d6fad7a8d9750b641a941cd841ec43740a375cb2fdb934329a17fa88b36", size = 3044439, upload-time = "2026-11-01T20:13:11.239Z" }, + { url = "https://files.pythonhosted.org/packages/59/4d/5e19712c074564e696731df56242c7626001b5695d09798115d788cbd771/cython-3.3.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:73f6f40f9308e77cbdb3259155d793ac189ead6687b9a432f1b4503170cb9a13", size = 3157847, upload-time = "2026-11-01T20:13:12.87Z" }, + { url = "https://files.pythonhosted.org/packages/39/16/d6517f078e69f0e5b224b0f1109851408f240af70982d1ef61c53f3a2df9/cython-3.3.1-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:801730e5714a40dbab8a373af36110de8ff161ec056c855a9627cf05fbc8a6d1", size = 3049217, upload-time = "2026-11-01T20:13:14.506Z" }, + { url = "https://files.pythonhosted.org/packages/78/5c/539b55fa787a427b0dd0e2ba805c04acb108fa65c69ff76e901d44e4a2d2/cython-3.3.1-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:a2bdb50e9fe8974447b68edc5b0201573b06d2c5683f472a5fc08e1792051277", size = 3376191, upload-time = "2026-11-01T20:13:16.383Z" }, + { url = "https://files.pythonhosted.org/packages/8d/dc/ca2ea10c22499e00d366a9252177ec9039b8d786c85fd28260d41ec2dda5/cython-3.3.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5febfc8c52aced0cf9360e6f2304428a5fa0e66fd9aa7338d5c41f0ce26dd104", size = 3267528, upload-time = "2026-11-01T20:13:18.074Z" }, + { url = "https://files.pythonhosted.org/packages/66/89/b2fdb92a7ccedff602f362bdf3fe38d67016de8c6655bc60bffce98b923a/cython-3.3.1-cp39-abi3-win32.whl", hash = "sha256:b0265a0e186af3c38339c561507e98e2e3a0d377cdb2b0427f980138ceddd4af", size = 2590014, upload-time = "2026-11-01T20:13:19.925Z" }, + { url = "https://files.pythonhosted.org/packages/9f/d8/3d620697d89110b58937b1297dfdafbbfec4415b11b845b46ec9a04b52b5/cython-3.3.1-cp39-abi3-win_arm64.whl", hash = "sha256:8b4391d39260efedeff2e3914e958b9ed75cb2b40f10b62bb0e9ca002658563a", size = 2693762, upload-time = "2026-11-01T20:13:21.506Z" }, + { url = "https://files.pythonhosted.org/packages/9d/55/088578d75bc8dbcbc535af04b1d596ff227ca756dd74f9d3c1c526f955d0/cython-3.3.1-py3-none-any.whl", hash = "sha256:61abc7feedd20dac6c4ff7ab3a30e17136a067b242ab9253e2b4a6d9a72c2b61", size = 1352000, upload-time = "2026-11-01T20:12:01.888Z" }, +] + +[[package]] +name = "dataclass-wizard" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/9d/465deff762411b97cc37fdd475402484724f695af042fa89ff221f725172/dataclass_wizard-1.0.0.tar.gz", hash = "sha256:d458e6a97585377337f1633e5738ee1c051e84ca7726276ecde78d6534e485b5", size = 449143, upload-time = "2026-07-03T03:21:14.302Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2d/8b/d4db2e85e6f0a5dd2e590eb646aea1cabbf3c4629aec2bc5a5540c7a4250/dataclass_wizard-1.0.0-py3-none-any.whl", hash = "sha256:0dc53acbfed4ca5fe6bbdc517003959afbd50c0794dec1f8405d3c4d8ae6690c", size = 305849, upload-time = "2026-07-03T03:21:12.252Z" }, +] + +[package.optional-dependencies] +yaml = [ + { name = "pyyaml" }, +] + +[[package]] +name = "editorconfig" +version = "0.17.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/88/3a/a61d9a1f319a186b05d14df17daea42fcddea63c213bcd61a929fb3a6796/editorconfig-0.17.1.tar.gz", hash = "sha256:23c08b00e8e08cc3adcddb825251c497478df1dada6aefeb01e626ad37303745", size = 14695, upload-time = "2025-06-09T08:21:37.097Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/96/fd/a40c621ff207f3ce8e484aa0fc8ba4eb6e3ecf52e15b42ba764b457a9550/editorconfig-0.17.1-py3-none-any.whl", hash = "sha256:1eda9c2c0db8c16dbd50111b710572a5e6de934e39772de1959d41f64fc17c82", size = 16360, upload-time = "2025-06-09T08:21:35.654Z" }, +] + +[[package]] +name = "exceptiongroup" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, +] + +[[package]] +name = "importlib-resources" +version = "7.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/06/b56dfa750b44e86157093bc8fca0ab81dccbf5260510de4eaf1cb69b5b99/importlib_resources-7.1.0.tar.gz", hash = "sha256:0722d4c6212489c530f2a145a34c0a7a3b4721bc96a15fada5930e2a0b760708", size = 44985, upload-time = "2026-04-12T16:36:09.232Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/db/55a262f3606bebcae07cc14095338471ad7c0bbcaa37707e6f0ee49725b7/importlib_resources-7.1.0-py3-none-any.whl", hash = "sha256:1bd7b48b4088eddb2cd16382150bb515af0bd2c70128194392725f82ad2c96a1", size = 37232, upload-time = "2026-04-12T16:36:08.219Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/e1/2069291243c926a2ff1cd706c7f3eeb9b62144bf60f77c9fb9ff2fb26bd3/iniconfig-2.3.1.tar.gz", hash = "sha256:67f4b9c50da0dedf52af349e7749a80a9057a5031199791b906c3bb3ae878960", size = 21209, upload-time = "2026-10-06T22:48:38.076Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/43/4ca9e49d27a1fcf6bece6f6aec0ea46bb9112489b93d4b688fb415457bdb/iniconfig-2.3.1-py3-none-any.whl", hash = "sha256:9121e2c1fdb355232495be3194c8dfe87ccc2d5dee45947b78e68f499790d7a7", size = 7552, upload-time = "2026-10-06T22:48:36.959Z" }, +] + +[[package]] +name = "joblib" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cloudpickle" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d5/1d/537ab090f302b838943a1b56497dd53059b9a9b46a074936470173a2e207/joblib-1.6.0.tar.gz", hash = "sha256:2ccc96785b12046c08fd6d55839c12857831b54a3c1673ffadd2f04bfc4eda03", size = 327903, upload-time = "2026-08-31T09:39:04.122Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/53/84099323c2ec4be98d935f63c033ac4151ee83836ca1050ede3b3aadf155/joblib-1.6.0-py3-none-any.whl", hash = "sha256:3dbbf9f6e4b592a2357b854608e980fe6390d131d7a82f011a377ef2ebef7aba", size = 306115, upload-time = "2026-08-31T09:39:02.298Z" }, +] + +[[package]] +name = "jsbeautifier" +version = "1.15.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "editorconfig" }, + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ea/98/d6cadf4d5a1c03b2136837a435682418c29fdeb66be137128544cecc5b7a/jsbeautifier-1.15.4.tar.gz", hash = "sha256:5bb18d9efb9331d825735fbc5360ee8f1aac5e52780042803943aa7f854f7592", size = 75257, upload-time = "2025-02-27T17:53:53.252Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2d/14/1c65fccf8413d5f5c6e8425f84675169654395098000d8bddc4e9d3390e1/jsbeautifier-1.15.4-py3-none-any.whl", hash = "sha256:72f65de312a3f10900d7685557f84cb61a9733c50dcc27271a39f5b0051bf528", size = 94707, upload-time = "2025-02-27T17:53:46.152Z" }, +] + +[[package]] +name = "lxml" +version = "6.1.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/23/ad/28ecd7cb894d172f3c9c80a075eeeb2017ac62e3632cee05a5f9493547eb/lxml-6.1.3.tar.gz", hash = "sha256:45222d94ddd511536f3b2f7d9deae3b2339b4ce0f075f1ca25703b07cad9dd21", size = 4211198, upload-time = "2026-09-02T14:48:02.287Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/29/6b/a7d5c08e19a8e69887ed722fffaefdbaffc8959d5ef5c370a65e52c895ac/lxml-6.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:40bcbd9f94166ffe925811e730607385cec959f42fb1bb7dad83748680465221", size = 8575497, upload-time = "2026-09-02T14:46:05.131Z" }, + { url = "https://files.pythonhosted.org/packages/96/dd/c25a32f9f6039a96cfd52296a4630075868aa16e71858b3076699a059201/lxml-6.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:05f5bce9af14fd1506997594bd81cee6d9c6b58ea80a39c058327aa6371ed9e9", size = 4619233, upload-time = "2026-09-02T14:46:08.898Z" }, + { url = "https://files.pythonhosted.org/packages/3e/f0/d49375a47644369d84f90a9fe4ff1924faad58d4f95563831eca84ca29ae/lxml-6.1.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ff88a92cafde90888511242d1c54afcc1a8adbb6dc0a88fa7f87e29e92400d4a", size = 5015387, upload-time = "2026-09-02T14:46:10.797Z" }, + { url = "https://files.pythonhosted.org/packages/76/0f/d1b1f52925442f7b4b1abd81a41905987322f6df6a5dd42fab8579415828/lxml-6.1.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c00e26288784460885fe76e4d4b293573e0f791f52e6d60e27b42edf005922eb", size = 5168571, upload-time = "2026-09-02T14:46:12.989Z" }, + { url = "https://files.pythonhosted.org/packages/b2/13/e5d8291a68a27e564e4e1eefba08c3844c6800bcb43f3e72a32b20971132/lxml-6.1.3-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:773062aec2f2e56b2b22d37054123f0de8a22a4688a0c3376c3fe42685f975cf", size = 5068024, upload-time = "2026-09-02T14:46:15.325Z" }, + { url = "https://files.pythonhosted.org/packages/a1/ce/dbea34cd115ae9b8ef53816daa912563615adf4daed42531878a2fb29c77/lxml-6.1.3-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f6449672f9c93316deb5e2839e18931f468670e44d5bd9b1301a5a9655d45c07", size = 5296830, upload-time = "2026-09-02T14:46:17.52Z" }, + { url = "https://files.pythonhosted.org/packages/20/f6/12a2ab6e8c8afecb82a3f0e9a518952b6a1cddf405ad8542883bd71e6096/lxml-6.1.3-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:ec295280f4b37769256da025acf5890370355ac589c27e89caae0b5e9eedc702", size = 5424696, upload-time = "2026-09-02T14:46:19.706Z" }, + { url = "https://files.pythonhosted.org/packages/02/3f/5670e198266c764595687a234fdaed33837f487b95a596262b2548e48933/lxml-6.1.3-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:5929d9df5e7e3379183be0e21f7d559618a5b61cb63280df6164019242e337ed", size = 4783635, upload-time = "2026-09-02T14:46:21.63Z" }, + { url = "https://files.pythonhosted.org/packages/70/24/007ce6b7bffb61a6ca88c3a8f21b26f3f0aa3b3f6bb648a56e328c994a14/lxml-6.1.3-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6e1eb8a4cbffd5553680ad96be6680e364710656eced73d1dc90ec489df599a3", size = 5373212, upload-time = "2026-09-02T14:46:23.572Z" }, + { url = "https://files.pythonhosted.org/packages/4e/00/cf09f38cf9005bd5cfa4fd452b03b290b1c48c403fe0319a8013f4b3cae0/lxml-6.1.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:16148acd77ed1d8836a56db883af2f5eed720f9723088110b16a0d08582130a6", size = 5116476, upload-time = "2026-09-02T14:46:26.262Z" }, + { url = "https://files.pythonhosted.org/packages/15/83/eb021e5db4336f0bb1438cba6f053ea135aa00b9f4ef0439473d6b986308/lxml-6.1.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:23c366231259cd75ad06495174701afb3fcb36a92917fa47de2d1f1bd9d95739", size = 4814172, upload-time = "2026-09-02T14:46:28.3Z" }, + { url = "https://files.pythonhosted.org/packages/c8/4e/147b6f9088cc191713249ac547b0af2fece489c8cdff1f2801ab47dda8a9/lxml-6.1.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:da85db328e507da922d586c3c7416ec360ec22e9cd9e0700691afacde0c81f53", size = 5361711, upload-time = "2026-09-02T14:46:31.035Z" }, + { url = "https://files.pythonhosted.org/packages/b7/d9/8cfdac0d7d771e25af2c1f4bc874032f025a4b59e0b6917c3c7858070795/lxml-6.1.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0f17d83c48ee9dfd96abae3ac3e2108c76d2fc86ce96355e37b8da9f7f4ecc08", size = 5321598, upload-time = "2026-09-02T14:46:33.165Z" }, + { url = "https://files.pythonhosted.org/packages/f3/5b/d2413c71f312dccdd07ed985be356657fc624d822ba7e2c87e8722646156/lxml-6.1.3-cp310-cp310-win32.whl", hash = "sha256:7dd624c1eaa629ad44b59a1a0145fdf2d67895592dce94c9358b938b3d075e65", size = 3604471, upload-time = "2026-09-02T14:46:35.245Z" }, + { url = "https://files.pythonhosted.org/packages/7a/bf/74b6785beac6488fd395e78796339bc197fbad6fd6103b41b15a4009dc4b/lxml-6.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:18a4db52b5a7b53a3540b0b0f4123319334621ee8083d496de314d0bf06ff59a", size = 4029086, upload-time = "2026-09-02T14:46:37.744Z" }, + { url = "https://files.pythonhosted.org/packages/f9/a5/ddf6e1744cd76fc9f0ce11cb16b117d6eaac46ebaeca01968e9014e8770c/lxml-6.1.3-cp310-cp310-win_arm64.whl", hash = "sha256:0feebef8d0521188d0157f758356072e840173aa61ca45b8b3f87959ac283dd5", size = 3674608, upload-time = "2026-09-02T14:46:39.802Z" }, + { url = "https://files.pythonhosted.org/packages/96/f1/95133bde7af7afb1f5ba6090b674d826b7a518318bba54bbbb633b27865a/lxml-6.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c66f858b82497173f73366795fc6ee8171620e75a338506d6b2e7bc16f5fca11", size = 8563141, upload-time = "2026-09-02T14:46:42.334Z" }, + { url = "https://files.pythonhosted.org/packages/80/54/5a79ee2181ac773ee13e48205411845feec69e1c3d097e985c1343171712/lxml-6.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:032a0a97eed428bd143c75a11118238546424ceb2fa311cca5f073aa44658dc4", size = 4613690, upload-time = "2026-09-02T14:46:45.253Z" }, + { url = "https://files.pythonhosted.org/packages/ab/29/8c24672f56807f119312f073f24204368574bd16b384ede861b5104b3a2b/lxml-6.1.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4a579dfb9c835f8ab47f4b8ed33440cbc75b806b73297208e6ec2a33e903740b", size = 4935630, upload-time = "2026-09-02T14:46:48.071Z" }, + { url = "https://files.pythonhosted.org/packages/71/69/ce2436d854c848c19fc9287143991f3fc76b8b4e9a0dbba8452e51dff264/lxml-6.1.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:49fbc2682a9306135b7ec49e93f97f9c26689b9b7f96ed2742d8d6497e994d13", size = 5079033, upload-time = "2026-09-02T14:46:50.483Z" }, + { url = "https://files.pythonhosted.org/packages/91/ec/b66f66f6499ad800265d57540b51e6632e3232d3526f42f2f8fd4b14e0ea/lxml-6.1.3-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ea2c01cdb16dc12156e455007c406dfaaece0c89aa4ba0e3b47586779f951d41", size = 5012298, upload-time = "2026-09-02T14:46:52.603Z" }, + { url = "https://files.pythonhosted.org/packages/94/2a/25d128872f4d51753542bfc3feb482c2ea7c8a2d6d81a0bc5c6a00779ed4/lxml-6.1.3-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:527195c188d7d0af748cd48d220ab8cdc5cb99be3d49ac4d9be7324d8abf9bc0", size = 5211431, upload-time = "2026-09-02T14:46:54.722Z" }, + { url = "https://files.pythonhosted.org/packages/75/b2/0a41bbef074a556110f84fafb6d8c2998293c7d3bfbe1ce74515bc65393b/lxml-6.1.3-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:20384c2bbcbf87180c8c61eb60869699c1ec0cd09b62cfd13804022d860b0867", size = 5343417, upload-time = "2026-09-02T14:46:57.46Z" }, + { url = "https://files.pythonhosted.org/packages/7b/cd/16116c3f91791aeeeab1cbe6e7eb6e646f127be7b0158b262eb526a21a0c/lxml-6.1.3-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:424aa5657141d306ba9ad1baab4b2c0a0719040075ee6c66aee9bb2dea2b5054", size = 4673219, upload-time = "2026-09-02T14:46:59.604Z" }, + { url = "https://files.pythonhosted.org/packages/dd/bb/4dff849f443ef70221676aec938bc41e8bae6430aa2ca13b041319e14b98/lxml-6.1.3-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4736e6c87e603146d8949d8501da621ad20c31015060d3fcf95ace2859f3e3e6", size = 5281246, upload-time = "2026-09-02T14:47:02.375Z" }, + { url = "https://files.pythonhosted.org/packages/9f/ac/4aa7dd059420bfd35278c7fe819e9d319ee36a0453b7bbde1907a7832d91/lxml-6.1.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6374e9e382e5a98c9c5e66d41b357b470da1c54bce30f17f9dc4bcc58436cc1c", size = 5055451, upload-time = "2026-09-02T14:47:05.883Z" }, + { url = "https://files.pythonhosted.org/packages/de/44/20d90cf6f4234de9cd9eeb4f519419885fdb087fa80d073c7b57be342021/lxml-6.1.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:22eec57e26c418cde02c051ce9914a365e52a7f135a565c6f0480242aeebab48", size = 4722694, upload-time = "2026-09-02T14:47:08.461Z" }, + { url = "https://files.pythonhosted.org/packages/f0/0e/6bee12325e53dd6613fe1e107def07583b6182ade03e94bfef8976622e44/lxml-6.1.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:8753b8d51dbc86fd335ee31fcf7f3658e9f5c016d4edfb23f76ad295f4b8c9d0", size = 5269179, upload-time = "2026-09-02T14:47:10.647Z" }, + { url = "https://files.pythonhosted.org/packages/e4/5d/54d269ce5cd0787c0424d9cef449ee794d4097725d13dd2acd6181c44e9c/lxml-6.1.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:207dfc3d47cf0e575e643bbc140dacc8863b39abaa1e5307cd64c7f2365b8a12", size = 5235559, upload-time = "2026-09-02T14:47:13.932Z" }, + { url = "https://files.pythonhosted.org/packages/e4/f7/5a3095f187f1bec293591616a1677781acc265c5b313c009f8a19c471a09/lxml-6.1.3-cp311-cp311-win32.whl", hash = "sha256:18293f8a8d8b6a8e71ef37706b659e3846a4261232158167b1ddf35f6994f633", size = 3600377, upload-time = "2026-09-02T14:47:15.957Z" }, + { url = "https://files.pythonhosted.org/packages/45/5a/15531a0d307c96282fe8b639b3d74e8bd783e4ab4cb2b0781146ac4161b8/lxml-6.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:7ae4949f212a53b007dbc355884fda122545c5764a54256c9217e419a62a6559", size = 4032700, upload-time = "2026-09-02T14:47:18.566Z" }, + { url = "https://files.pythonhosted.org/packages/12/f9/8de76314955545ceaaa7c0305017b8aaa217905dee59c62c0e2c1e44a68f/lxml-6.1.3-cp311-cp311-win_arm64.whl", hash = "sha256:2123e5aa075ac20d23c7af489255efd129cbfe190dbe88fd42598cc9df3199b6", size = 3674431, upload-time = "2026-09-02T14:47:22.186Z" }, + { url = "https://files.pythonhosted.org/packages/dd/1f/a180b57d9eeabaab77f9d5aa30356898ea749c4795596a8f66d1eb6bef2e/lxml-6.1.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c0710ac085a157b593c38fbcacd950f15c4afa8e2057527185875ab302752bc", size = 8602094, upload-time = "2026-09-02T14:47:26.054Z" }, + { url = "https://files.pythonhosted.org/packages/a8/25/070c92013a1c029a602b03560d68772313d918268667fa993da7961759c9/lxml-6.1.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:623c8799c17128753c65699f1c3aa32402657393a9ad6db09ed8b98ddf76611d", size = 4638308, upload-time = "2026-09-02T14:47:29.587Z" }, + { url = "https://files.pythonhosted.org/packages/1e/1c/722e88883173097a1a375153e3c2447eba3060d0231522cf6596e99f4195/lxml-6.1.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f683dc6300317700025e41d89a43e0276692ded16113a3c43eab704d605c58e5", size = 4939696, upload-time = "2026-09-02T14:47:32.997Z" }, + { url = "https://files.pythonhosted.org/packages/db/36/aa413bc214dc4f785ad2b2ddd8cc99aae7062d49ab155e91e6011af00daf/lxml-6.1.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:379f8a75cf6eb7eef0af074b55f49ab73b868388a98de14646abcdfa4564bb11", size = 5105247, upload-time = "2026-09-02T14:47:36.734Z" }, + { url = "https://files.pythonhosted.org/packages/a3/a0/a1f7f1313795bfec67b77f01ef3b1128d49f2d7f66a8413fa55d47f4e25f/lxml-6.1.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b37772102d44bb6628186accca3a121b1fa3a6b3d97518a8c29a5229ca4c0d0a", size = 5011915, upload-time = "2026-09-02T14:47:39.846Z" }, + { url = "https://files.pythonhosted.org/packages/b9/78/840e7e3f1d0cc7a5cfac5d8505b97e25b6427fd774ac4bae672aaebfb4b5/lxml-6.1.3-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ddcf547bea2aee967d6a77779376a45e77e610e8465147a1f3d7e20d539d6e32", size = 5638175, upload-time = "2026-09-02T14:47:43.644Z" }, + { url = "https://files.pythonhosted.org/packages/0a/20/e022dbc6b4753a9bc9fc5fb28a27163430c1731b9913997f6544c1b2518c/lxml-6.1.3-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:909f4e927bb051f7740d6367285fc60cdcfdaf0258c2dba4ff5ba7eadadc250c", size = 5244675, upload-time = "2026-09-02T14:47:47.635Z" }, + { url = "https://files.pythonhosted.org/packages/99/83/82cde81d2b5eb38d1539fdfdf318abdd014a7e604f4df01c9cd3deb18f2a/lxml-6.1.3-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:a5c18810318303ce9afb3f95e2ddb54834f96fa699a8600433fd5a93dcf44c56", size = 5358205, upload-time = "2026-09-02T14:47:50.306Z" }, + { url = "https://files.pythonhosted.org/packages/d2/a1/f3b057371c8cb29f2a9c9c44ea320592446e40b74a4b0af68c3d8e65bc73/lxml-6.1.3-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:3e42265103fb385d8642a78672edf376c6f7e1d3598a7a4f9cb1278f2f6b5f6f", size = 4704495, upload-time = "2026-09-02T14:47:53.251Z" }, + { url = "https://files.pythonhosted.org/packages/1a/a4/230eb28be5d412152ffc3c679b51fe1aeede5a53f3a8eb6e9748f2f4754f/lxml-6.1.3-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:21402998e4b78e7cce237d2788841aaa21ac9a4d1574d04dc2d12ee41ae807b5", size = 5255117, upload-time = "2026-09-02T14:47:55.963Z" }, + { url = "https://files.pythonhosted.org/packages/a3/18/1969f56763af24ce42ea156007b0b2d73fddea552e283b2010416394f0f4/lxml-6.1.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:38fc4e4e4e084e0bd491949482527d406788045c546d4f8789e93fc527b91385", size = 5054424, upload-time = "2026-09-02T14:47:58.131Z" }, + { url = "https://files.pythonhosted.org/packages/f4/d4/2a90acc1f6fabaa3a8db9340437822bd8d041b205d626a4b3e8621aaa390/lxml-6.1.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5609efdb0d3c95499c00046bc53648b3482ec2175b5503d6e611b3f0555dc71d", size = 4785572, upload-time = "2026-09-02T14:48:01.029Z" }, + { url = "https://files.pythonhosted.org/packages/a5/1e/b90e845b1dcd0f2f3f26b98283d857f25909223aacd265eee032c34ab8b1/lxml-6.1.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:97ce49699d87ebf8aad631b55d65b33219a4f1bfefbbf5bff19dc9af160aeaf9", size = 5656516, upload-time = "2026-09-02T14:48:03.419Z" }, + { url = "https://files.pythonhosted.org/packages/eb/ab/0a1b802c57f3fba5c4efd77d5c6b78adaa8f7b681f0c90456b140fe8bf6c/lxml-6.1.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:48542c9acba9ff9450bd18d871d2c2c8787fdb283572b623d206f1b927cd7d9e", size = 5245982, upload-time = "2026-09-02T14:48:06.109Z" }, + { url = "https://files.pythonhosted.org/packages/da/ee/2c016fbceb3778137459292538d9dfa7e3ad9070fe409c15254ddd90d2cc/lxml-6.1.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c55e71a9b1db1f107efb60da49c093689b74c5c31a708e5379e2fd9439d4fbb5", size = 5267340, upload-time = "2026-09-02T14:48:08.374Z" }, + { url = "https://files.pythonhosted.org/packages/9c/b1/736d18fd6f0835761923b7bac1f0c27d60c1200384e9093f05d8c5100525/lxml-6.1.3-cp312-cp312-win32.whl", hash = "sha256:b3ff39654f0ce6ebd4db154211136dbe7e8157bcc3bed2344c87f32c7c6ecb6c", size = 3602606, upload-time = "2026-09-02T14:48:10.384Z" }, + { url = "https://files.pythonhosted.org/packages/3a/5b/6ed903e4e6278a020c8a6f0dbbe78030d041840a6b4a64ea441a1e414077/lxml-6.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:3e9a00d1c2c30936f7add097c41afc5da6556c580909104aafd382cac92a855c", size = 4005999, upload-time = "2026-09-02T14:48:12.51Z" }, + { url = "https://files.pythonhosted.org/packages/e4/1b/7bcebb7b6332cb3ae85e9c13b139adb6f23f75c71d84041c56a5005d9a29/lxml-6.1.3-cp312-cp312-win_arm64.whl", hash = "sha256:1aeca87830c4fe649dcf93fe2b059525b71c72587f21be4ae4af7103082a79fa", size = 3666631, upload-time = "2026-09-02T14:48:14.567Z" }, + { url = "https://files.pythonhosted.org/packages/52/05/3ef45db776baea068044c799bbba68f3ca00a440c0e930a17c572f3d9639/lxml-6.1.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:3a48093cdb058a93af842ede9703520e810b05dcd0fc6d7190a06376c3bfb6bd", size = 8590357, upload-time = "2026-09-02T14:48:17.413Z" }, + { url = "https://files.pythonhosted.org/packages/8c/a5/eee2fc77eee5ea68e4a4334b1def1781a3beaeefd3d98e81b4a38dc447b7/lxml-6.1.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:887c021d9a977cff89cb273047c1352997b772a8908a25c21836861f69b92be1", size = 4632616, upload-time = "2026-09-02T14:48:20.745Z" }, + { url = "https://files.pythonhosted.org/packages/35/42/df27b56848acd29d8a720acc28977911aab36f2a09df4208d5502e887415/lxml-6.1.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:611a51e61c92f62345a50b0035df6fc0d678f9299f33728826d831598862f59d", size = 4936186, upload-time = "2026-09-02T14:48:22.94Z" }, + { url = "https://files.pythonhosted.org/packages/ab/8d/8a7b91df0b54d09d25f5f44885d6b3e0a6d6643a8c070191580318d20c42/lxml-6.1.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b477912f42c5c33405a10c759d22f80cf5af043ae02d95b9d8e5e5bc555739ed", size = 5093324, upload-time = "2026-09-02T14:48:25.132Z" }, + { url = "https://files.pythonhosted.org/packages/c6/7e/8f340ddcd43790332fb0de8a26628d571a492da3300cd191821698407c96/lxml-6.1.3-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5cffe18571ccc51d742cd08cbb3f8b756de9311d18c7ea98f5d92f37b8fb60c2", size = 4998850, upload-time = "2026-09-02T14:48:27.394Z" }, + { url = "https://files.pythonhosted.org/packages/c5/c1/9c5bb572f1f09ec9e4322bd4a4e9f4ad48347fc56ef94cf4df58a5279dc8/lxml-6.1.3-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:75cc6569e86be5785b6188ef1642670c6adbc984e81ec35e224842ecd9eefcc8", size = 5626813, upload-time = "2026-09-02T14:48:29.61Z" }, + { url = "https://files.pythonhosted.org/packages/ac/7d/8bf1fd8bae8247743968bb76d027a1ac5bd2c4b44495fba6a71b30d10706/lxml-6.1.3-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d85dfab42dd672f87a7f76e9de7172962aee69fa12044f0d6e1a23cbd53fb80e", size = 5232385, upload-time = "2026-09-02T14:48:31.969Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2e/6cef69ed81cb7df0d03b0dd09d08e6e2cf5061a743ff6f42f0b741548e9b/lxml-6.1.3-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:42632b4024ab24a6b488f559ac851312509888b6b80ae2aa11cf29a646a0d245", size = 5347088, upload-time = "2026-09-02T14:48:34.13Z" }, + { url = "https://files.pythonhosted.org/packages/5f/e1/8e5fd8ddc8c7d685badb0f2db149e3c9da84eefc2827c01c658df2c4e3cb/lxml-6.1.3-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:febd35ef45f603c2d74b74655efdbf45e14f55fc0aef4ac82b663ca829b283e0", size = 4707227, upload-time = "2026-09-02T14:48:36.62Z" }, + { url = "https://files.pythonhosted.org/packages/7a/7e/00041382a11be40a88bf405ebff11c8efabd3de79f2691e1638b1c47a8a0/lxml-6.1.3-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a43b3bdf11e477dc7770609d3477316f974354dfc8425d596f64f471cc8daf6e", size = 5240208, upload-time = "2026-09-02T14:48:38.893Z" }, + { url = "https://files.pythonhosted.org/packages/fd/fe/316538b5cff0936fa63d45d421c655730fcbb5a28dcac728c175083002bc/lxml-6.1.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d582042c69857c364e8153de6e18e0da9b7b515a6a8113caf69a6ec8e0520f2", size = 5050271, upload-time = "2026-09-02T14:48:41.213Z" }, + { url = "https://files.pythonhosted.org/packages/c9/91/455bcccb3ac725373007344d351151810cd19762d1673b64b811f4359a42/lxml-6.1.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:8e49a646acfab83c68974f4aa1d0a2acca9e88d7d627ae0fc13201b14b76d310", size = 4780433, upload-time = "2026-09-02T14:48:43.779Z" }, + { url = "https://files.pythonhosted.org/packages/cb/f6/580440e2f52cf00bba5c5e1080bfa88cdfcde73be71a11d95170ddbb663f/lxml-6.1.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0dee106e9aa97fb00541b1ed7827070564d0549c3d3fba8920e6b20fd980f748", size = 5645928, upload-time = "2026-09-02T14:48:46.187Z" }, + { url = "https://files.pythonhosted.org/packages/f6/dc/d123c1f244306543d545f62443f794959e4f1ea709fe100f8740d514e74a/lxml-6.1.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:dd5e90f34cffcfed97f36cf066325773d2b6021c60c29942e53a18b028501b1d", size = 5231184, upload-time = "2026-09-02T14:48:48.691Z" }, + { url = "https://files.pythonhosted.org/packages/c3/3c/fe55b2bd5c6113c906511cd88f6a470195c5fbff1124f19970ab706c3477/lxml-6.1.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d9b3e7d71bf6acff341233417abbdface29c647e3113892d9aaedc02eb4aa2bc", size = 5255814, upload-time = "2026-09-02T14:48:50.948Z" }, + { url = "https://files.pythonhosted.org/packages/e7/a7/485df55acf55dc35e4ca89d2f48f03889e5a3241826b18b85102b32ce9d8/lxml-6.1.3-cp313-cp313-win32.whl", hash = "sha256:160fcf381f76c3aeac28a756bec44f48942a8f7245a87aa28e3a523b4d90cd87", size = 3602214, upload-time = "2026-09-02T14:48:53.236Z" }, + { url = "https://files.pythonhosted.org/packages/c0/28/e46a7702bd95e9043291f7c3539b6184cba66f96cea9936f20939b284eeb/lxml-6.1.3-cp313-cp313-win_amd64.whl", hash = "sha256:e477aca0bc0d19f3b4ae9e4f2a1cfd687c31bf772d78734910658186b40b2477", size = 4004091, upload-time = "2026-09-02T14:48:55.699Z" }, + { url = "https://files.pythonhosted.org/packages/8a/1d/154c78e20479a43916e63f19cb720d83f44f024b03228be44c92d9a97b24/lxml-6.1.3-cp313-cp313-win_arm64.whl", hash = "sha256:b1cc980905221a5d8b3c476330730b3adb40ff80add71ffbdb6215ba055656f1", size = 3665468, upload-time = "2026-09-02T14:48:57.703Z" }, + { url = "https://files.pythonhosted.org/packages/0c/15/fc75a70b0af6021d0ea16811f1fc71cc42cd06ce90fe10f007a69b2eed84/lxml-6.1.3-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:2bec13085dc8ef48a3fe62f7dfcacfeda2c785cdf19cc8eeda2bb9ed081da165", size = 8609725, upload-time = "2026-09-02T14:49:00.156Z" }, + { url = "https://files.pythonhosted.org/packages/84/ef/398fcf9018f881ec9aeaafae1ddd6586dfb13314a35d35e899de373dcae0/lxml-6.1.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:4f4db7c7e954d289d71878938348b3d91b904a3e8210a11939359fb758a58e7d", size = 4639629, upload-time = "2026-09-02T14:49:02.81Z" }, + { url = "https://files.pythonhosted.org/packages/a7/2d/49b6a6ad7ce8f64b07b9fe852ff0c6d3fcbb26db61bee4f63d4120180a1c/lxml-6.1.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2cae5d5c90a62d9139c512a0cb1aad1d182b022b5740daea2617eb5bf7fc658e", size = 4965074, upload-time = "2026-09-02T14:49:05.133Z" }, + { url = "https://files.pythonhosted.org/packages/66/bc/6230cf80e4331c33383b0b6b73dc31a393dd76edd4cb73d761de5123034d/lxml-6.1.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c6c0c13128a32eb04a51357e56a094e13aa8e6d3d1884de2e9ae923f6915e1a8", size = 5099355, upload-time = "2026-09-02T14:49:07.343Z" }, + { url = "https://files.pythonhosted.org/packages/ac/cf/d1143d9b7717e07a82f158a1fc9ce6e581fdad1226734950af869e3ffde4/lxml-6.1.3-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2221e88679d1351e9a40aaee54bc65679b9795bbd0160bc3d5e36b163344eb75", size = 5036795, upload-time = "2026-09-02T14:49:09.65Z" }, + { url = "https://files.pythonhosted.org/packages/31/6f/194bb00ffb89712c30f5a7e1b8e685590e140fad6c8261fec172c09a3dc0/lxml-6.1.3-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cfb398886a7eb4c719161c3efcff2a1248febc53a4d8e5072d2d8a87fed84ac9", size = 5658740, upload-time = "2026-09-02T14:49:11.9Z" }, + { url = "https://files.pythonhosted.org/packages/e9/44/27e3cee3dcdb3b7bc09727b642bdbfcd098490ea77df04611db9060d7722/lxml-6.1.3-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a7eb78ba28b187e1e9203a55c60fcf70df2d22cb205fe6d51b9383d6097419f0", size = 5245991, upload-time = "2026-09-02T14:49:14.154Z" }, + { url = "https://files.pythonhosted.org/packages/ca/e9/8312560579fc980bbd2233a8a673cc46f7d613d3633f2bf08a21e8f4ad13/lxml-6.1.3-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:ea6b1e9105b4b24a34c722432d9fb578f9ed83af21fa1abda639011e0f22bbb6", size = 5354136, upload-time = "2026-09-02T14:49:16.459Z" }, + { url = "https://files.pythonhosted.org/packages/74/d8/eda60f4f73a9c780b5d6e1175484f66e6c81a2c93346e2906a1fec9c7a02/lxml-6.1.3-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:e8b17e23df3e827a69d25af70990ca2420e92668aaffaeeb3cd2351d7916a023", size = 4704379, upload-time = "2026-09-02T14:49:19.032Z" }, + { url = "https://files.pythonhosted.org/packages/ba/c8/c9cc60057be78ac34bd2b842e45e6e88edbfe5e532e82c3b82381b7aab49/lxml-6.1.3-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1b7c37339d7e75cab9a123a04248e243cefefb302ad6db566ea0c77cbcde421e", size = 5258676, upload-time = "2026-09-02T14:49:21.306Z" }, + { url = "https://files.pythonhosted.org/packages/41/7b/66894008fee8d1785b8db129747ae963fd427b68f456918df7f2f24a8b98/lxml-6.1.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:83e3a51e7933db700a0da0db31849db3a24022d9970da9bb73001e1d0326fd92", size = 5090069, upload-time = "2026-09-02T14:49:23.562Z" }, + { url = "https://files.pythonhosted.org/packages/8b/31/c1b60404859f4c3cd1f41f29c65a24e25cea78fde822d9574a21f66810be/lxml-6.1.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:9bde9ae026a55b9a192078dfa6e27dd0ca4a050171ab6272e92f97b757dfdf48", size = 4741958, upload-time = "2026-09-02T14:49:26.037Z" }, + { url = "https://files.pythonhosted.org/packages/23/b8/6285f0cf546f14da2554cabdeaf7c2c2ff3190c74807f0de2e8810a786f9/lxml-6.1.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:1a635e837b50a1819bebfedaac5916498ea024120969da8790500148fb0a894d", size = 5683245, upload-time = "2026-09-02T14:49:28.438Z" }, + { url = "https://files.pythonhosted.org/packages/d3/f6/2168cab44336dcb15fed0f0b78577225b83297cdf0dee349c95420c3dcb0/lxml-6.1.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:d0c5c362bc94f1929dc7e96e715bbe7bd17037f802e6d8f0d1545df9133c0559", size = 5246087, upload-time = "2026-09-02T14:49:30.955Z" }, + { url = "https://files.pythonhosted.org/packages/f5/89/32f5de69a0a31f30e6164981851f87b37ecb2c4ee838e504b88d49d4818e/lxml-6.1.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c59e4265608da6a041f54646ecc0c9ecdbb19aaf14c4c684bb6c2114998cc415", size = 5269352, upload-time = "2026-09-02T14:49:33.502Z" }, + { url = "https://files.pythonhosted.org/packages/a2/a1/741d952ed3a7ef7a50055c6415aec3f067015e97f72f4389ce77b09657ba/lxml-6.1.3-cp314-cp314-win32.whl", hash = "sha256:2e62c569ec7531b679b184cbfe335c501c1d13c4b363560013019962eb630e6d", size = 3662783, upload-time = "2026-09-02T14:50:23.751Z" }, + { url = "https://files.pythonhosted.org/packages/0f/bc/5811cc73cac05e324e05ba9b0924e1a163a317a167ede8a9c748b11db30a/lxml-6.1.3-cp314-cp314-win_amd64.whl", hash = "sha256:66299564c046bc7e0cc5de5106601eae907e9fa5904cd68a323380a8502f7861", size = 4073951, upload-time = "2026-09-02T14:50:26.348Z" }, + { url = "https://files.pythonhosted.org/packages/92/18/3768c8b01ac3a9bed1914715e6011711b00e2a11628ffa6f7fa37f8e0269/lxml-6.1.3-cp314-cp314-win_arm64.whl", hash = "sha256:ebd054ad1737a68fb7c5c073d405cef2b88bb824e294de3b4a4e995b47f0e376", size = 3749279, upload-time = "2026-09-02T14:50:28.749Z" }, + { url = "https://files.pythonhosted.org/packages/72/38/84684784738d9451db2b330de2483f496690c3a5c642071df24135739b37/lxml-6.1.3-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:5a143e6207579de8baeded4eaac9134413200359f1969d636f0bfb98ee8c3c8f", size = 8860296, upload-time = "2026-09-02T14:49:36.346Z" }, + { url = "https://files.pythonhosted.org/packages/24/b7/fc4c50bb1b38e864010ea396046cabe85129bf9e65b11edcfbc37d356241/lxml-6.1.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:a1cec0f99b9b914d39176347a93b7610dc09324491aee1cbc57cd291a41a1d55", size = 4755190, upload-time = "2026-09-02T14:49:39.872Z" }, + { url = "https://files.pythonhosted.org/packages/94/e2/ee9aa6ed2b666b2db1f6f7fd48964ff9da39ebe827ef5eac0ab881f639d9/lxml-6.1.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f6b9d2aad499c769ee8287609ab0e6de99d8bcea99c6e6c2e64945259fd52fb2", size = 4979517, upload-time = "2026-09-02T14:49:42.153Z" }, + { url = "https://files.pythonhosted.org/packages/29/e3/e7763d1661b283ddd4fa36f91b9a497db6b8d2aff55028b16c7f642e0755/lxml-6.1.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a23fefdb345b2d4d0ff2860571b5ff9a89a28b6a120f720e8fb0324d346626", size = 5115270, upload-time = "2026-09-02T14:49:44.493Z" }, + { url = "https://files.pythonhosted.org/packages/2d/cd/22205d5b4d177e3f4156f780412426ee7c7f8107809f119f0dcc40fa51e3/lxml-6.1.3-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:545ccc14fb05485f48b4439ec35beb16d5b5280eb6c81c658bd4707a2a119414", size = 5032449, upload-time = "2026-09-02T14:49:46.841Z" }, + { url = "https://files.pythonhosted.org/packages/da/43/06a4626c3bb79ef8c501b674afab8100d64e798665bb2a97d1c960636a49/lxml-6.1.3-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:93476b6514b373fc6ca67d26c442784f7807c86f00635bfe79f935c3eab2af17", size = 5603325, upload-time = "2026-09-02T14:49:49.664Z" }, + { url = "https://files.pythonhosted.org/packages/d0/9c/733682a0c2de9f5779ba207bbb3f3f6be8c6bda863fc01739b186b38783a/lxml-6.1.3-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8db38ff3fb7aee7d6a82ae4da2eef1178656fe1216841fbd24870062a9d60473", size = 5229023, upload-time = "2026-09-02T14:49:52.447Z" }, + { url = "https://files.pythonhosted.org/packages/c6/8a/e69cdaca3fd33a647942925664f01b20908d41a6968c182305be9c38fb11/lxml-6.1.3-cp314-cp314t-manylinux_2_28_i686.whl", hash = "sha256:25f4118c438f96bb466e83108506d03d5c31b1bd2387e83e5b070bda6ded9c37", size = 5317811, upload-time = "2026-09-02T14:49:55.25Z" }, + { url = "https://files.pythonhosted.org/packages/2e/b2/0c397588174403c2ab68fc464abf97e03e7324f9c6cb6a99023104707195/lxml-6.1.3-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:1beb0f9909b26cee938df9ba56b15252a84429b1fc30ce6fca161390b9789a70", size = 4646516, upload-time = "2026-09-02T14:49:57.761Z" }, + { url = "https://files.pythonhosted.org/packages/56/7e/cfea25afafbe49db8b225764f7f74bb37c2a7f5e717d917d3d4a5e098ed4/lxml-6.1.3-cp314-cp314t-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3a27ac6c780c8b8a1cd231b58407634cafc1c4cc28cd6c7141362df0f36351e7", size = 5240626, upload-time = "2026-09-02T14:50:00.279Z" }, + { url = "https://files.pythonhosted.org/packages/a1/75/7a587771bb52ebb0e2c57b6dbe9fd96a70fbb54d72ddd97d54c5f8ec18d5/lxml-6.1.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a1932d7ce78a561367512c594fe66eac2b2ec9b9264cfd9b5f950622f4a116e2", size = 5086619, upload-time = "2026-09-02T14:50:03.245Z" }, + { url = "https://files.pythonhosted.org/packages/1e/01/94c0ebe6d831861542d251e038052e52bf6d33f1d18f1cfffdc82851065a/lxml-6.1.3-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:7d0f5976aa2701996f759b30172925829867547bb073af0ae67d1307a0f0262c", size = 4758828, upload-time = "2026-09-02T14:50:05.873Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f1/938d67bd0e5b1fdfa52be28aefdffbad57e1f6b8e921c2aab88542c75f40/lxml-6.1.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:c5e7ce578aa8a80910a72a8ca0bbea3baae10100827249001999726a788456d8", size = 5627083, upload-time = "2026-09-02T14:50:08.555Z" }, + { url = "https://files.pythonhosted.org/packages/d8/65/4e51522f6c214650db0abb7b16ccd11b1238b8a05a8d59aa4ebed59c9f67/lxml-6.1.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:d97c5227621af74b111882a290b10f371780a38eef9d9e730408fba2259b52fb", size = 5235170, upload-time = "2026-09-02T14:50:11.255Z" }, + { url = "https://files.pythonhosted.org/packages/92/c2/e73d19365665f6b16ef84df21199befc3b06e4c539046ad2d9595f6fb9ea/lxml-6.1.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:da707f14ea3c35ee463d50acd596d6488e4b2b4ae7cf77a5bf93f55c023d63e8", size = 5252273, upload-time = "2026-09-02T14:50:13.782Z" }, + { url = "https://files.pythonhosted.org/packages/48/a9/7f386c84c9fe2854e1ca6e231c285e1c8f392971ac353c6865e6ec49faff/lxml-6.1.3-cp314-cp314t-win32.whl", hash = "sha256:9efe56a68179f3adc4de41861c9358931db03837c48dd5e1c78077b84dd07f3a", size = 3902712, upload-time = "2026-09-02T14:50:16.171Z" }, + { url = "https://files.pythonhosted.org/packages/82/a6/8a3eb793f7900ef01c7f99e6f5fcbcfbdff35251cfaef66b32a4c16352d6/lxml-6.1.3-cp314-cp314t-win_amd64.whl", hash = "sha256:c9389b3784b56c58d933b5e0aecdf28f901b073ff385358d8a7d40907f6e14b2", size = 4400979, upload-time = "2026-09-02T14:50:18.621Z" }, + { url = "https://files.pythonhosted.org/packages/cc/c4/3807bea283b4fe9e9d9f5dde46a73df91178472b335d2778e10b2a37aa22/lxml-6.1.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32a409be3190b088f960ac92bfedfbef2f86c49ff940765e1548177592d20026", size = 3823401, upload-time = "2026-09-02T14:50:21.119Z" }, + { url = "https://files.pythonhosted.org/packages/e1/8e/4614fcd65496054cfb7172662f3576a59200278739506433b8c241ea422a/lxml-6.1.3-cp315-cp315-macosx_10_15_universal2.whl", hash = "sha256:6ea2f13dce778ca072ccee598bca46a092ce192e8fd907b6c1f0e52c800529a0", size = 8609378, upload-time = "2026-09-02T14:50:31.772Z" }, + { url = "https://files.pythonhosted.org/packages/f2/51/2cdce3c65fa99a6195dd8fbd512d33407c1000ad99f63e0a285b63d7a8eb/lxml-6.1.3-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:c581b1d68b3845fb86c6b2983e755b29bf001461c59fa411d2c26a911b6559a9", size = 4640022, upload-time = "2026-09-02T14:50:34.41Z" }, + { url = "https://files.pythonhosted.org/packages/52/09/0b30084e9eb1c546a4be3d9c56df70058d116b1a320400a59b0f7da87bf0/lxml-6.1.3-cp315-cp315-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e01125896585139453cab8cb235893644d8815d7509520da95ae3ee8d1c1f79", size = 5037928, upload-time = "2026-09-02T14:50:37.007Z" }, + { url = "https://files.pythonhosted.org/packages/b8/0e/5c37275a3e361f6138dc06db748ea565c1fe8a5f4ee5e2ddd80047c81a89/lxml-6.1.3-cp315-cp315-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:290f66b97ede0e552e1cb44a0fd8a74f9753ee635b50830a0b122fb72788d015", size = 5661932, upload-time = "2026-09-02T14:50:39.777Z" }, + { url = "https://files.pythonhosted.org/packages/70/c5/b71ffb289b15e2642e2a3cf6d468c44da39ea119061a99e5b05e3d10f217/lxml-6.1.3-cp315-cp315-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:73fc05988ed20809450474ba760a87c8ad4e455fc09783c02195e56ec634b41a", size = 5249209, upload-time = "2026-09-02T14:50:42.141Z" }, + { url = "https://files.pythonhosted.org/packages/81/ea/9910da149a23932f9301652e57661cd9e42b0df18f12be21159b7255f92b/lxml-6.1.3-cp315-cp315-manylinux_2_31_armv7l.whl", hash = "sha256:dc3a44689eea43eab836e5c98a8ab015dc2419987d1ea6eafc7c590cdff86bed", size = 4704543, upload-time = "2026-09-02T14:50:44.634Z" }, + { url = "https://files.pythonhosted.org/packages/76/07/9290329cd188c62e22021f79df04ee0cc33d9a93b0d38bd65ccd452ad9d0/lxml-6.1.3-cp315-cp315-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:209c3ccbfe35a04ac6d24f0611f9d1cbf8025d49991b14acd935236234d6c156", size = 5261298, upload-time = "2026-09-02T14:50:47.301Z" }, + { url = "https://files.pythonhosted.org/packages/c9/0c/aba78bd3401cd99b73a0aed8e2b9b43e14be94fab3603d4bbc8a62365f2a/lxml-6.1.3-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:2f5b2a2b9811b853b39bfa41367c6d78747b8e3e80e07fc5a24aae295c1a4d7d", size = 5090453, upload-time = "2026-09-02T14:50:49.952Z" }, + { url = "https://files.pythonhosted.org/packages/8d/dc/fa4426c3355aa0216cbeb3911495b5f65a26e0df85859a89928fe28f0396/lxml-6.1.3-cp315-cp315-musllinux_1_2_armv7l.whl", hash = "sha256:6a406d0b3cb207b0fa460ed4dc93e866f44f105da0169361cb18ff998a44c7f0", size = 4744709, upload-time = "2026-09-02T14:50:52.394Z" }, + { url = "https://files.pythonhosted.org/packages/be/2b/224fe7918658ab7c532ac2412f3c1eb28f71e6364fb07566262d0cc6a7b6/lxml-6.1.3-cp315-cp315-musllinux_1_2_ppc64le.whl", hash = "sha256:53258656846f5c48996b882fb4b135885e088a3ad3d96b4bc0530f95124d1f69", size = 5685802, upload-time = "2026-09-02T14:50:55.043Z" }, + { url = "https://files.pythonhosted.org/packages/21/44/7d480819b9adcae5f84dd8ac529132c6b7a578544398225cd20321adcd91/lxml-6.1.3-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:aa633613ff907ea91b9b0489a1f0da1b8725d8c6ccec6b77e8a1c9c235044bb0", size = 5249019, upload-time = "2026-09-02T14:50:57.985Z" }, + { url = "https://files.pythonhosted.org/packages/72/83/385a267ea1b6b283f2249dd827ef360a295e9db14e13ef4665a120c60d64/lxml-6.1.3-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:90f709b9accab6b2e4d14f5c8718203877a0486bcb3afd74d8b539ecd1e961d4", size = 5271886, upload-time = "2026-09-02T14:51:01.667Z" }, + { url = "https://files.pythonhosted.org/packages/d8/0d/f967b0eb172ae876855a402d6d9b11fa86e3e0c89ca9bbfeadf7ffbfa719/lxml-6.1.3-cp315-cp315-win32.whl", hash = "sha256:b4fc6b03b9d9d90557274f571ab30e7fbbfc527955536935d96f98b6817a86e4", size = 3662894, upload-time = "2026-09-02T14:51:45.173Z" }, + { url = "https://files.pythonhosted.org/packages/f4/48/d8a8c4160a29e663109ad520bac2deb37fcd014756d024561e8bc3e611ec/lxml-6.1.3-cp315-cp315-win_amd64.whl", hash = "sha256:33cadd956b667997e4de1635fce9541f2e8ede2038fcde8cf55aa14d571d1bad", size = 4074626, upload-time = "2026-09-02T14:51:47.77Z" }, + { url = "https://files.pythonhosted.org/packages/25/20/3e1395d34d19f9254625d0b567b81cf70d37d3417be074f4d63b94a2be3c/lxml-6.1.3-cp315-cp315-win_arm64.whl", hash = "sha256:8a330c0ee5fa318c7b5cbbaad882baeca3f570357e7eb25ab34bf31008150758", size = 3749495, upload-time = "2026-09-02T14:51:50.663Z" }, + { url = "https://files.pythonhosted.org/packages/8f/c6/7465ffd9c43883526a382df6fa4846c9d8d419214f7effbf65270e795471/lxml-6.1.3-cp315-cp315t-macosx_10_15_universal2.whl", hash = "sha256:0bf5a3e397df2ec4258eb5eea4c1ac6cf013ca1abd04a176903bff20a70021fe", size = 8857677, upload-time = "2026-09-02T14:51:05.109Z" }, + { url = "https://files.pythonhosted.org/packages/ed/eb/1f3a917e299df43c8162c3e6f64fc2cea3bcf277910f35bff5b8e5d39901/lxml-6.1.3-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:13d22c0d57355366b393936acf6b98a5e0edeadddd3fccbc6a846c50a76b8741", size = 4754522, upload-time = "2026-09-02T14:51:08.137Z" }, + { url = "https://files.pythonhosted.org/packages/d7/f9/f81b4bdb6efb7a596be29603d8758154d00a5f545db9f3cef9d9041c8f64/lxml-6.1.3-cp315-cp315t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cad7617727a96d189bd6f979d0fadf765198c7934e85f4edaba9bf3ad919a300", size = 5033744, upload-time = "2026-09-02T14:51:10.633Z" }, + { url = "https://files.pythonhosted.org/packages/c8/0f/26d9bfaacb319c86e0eca8a1a0bf1130d36a7afbd318883e23caea63763d/lxml-6.1.3-cp315-cp315t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cae82b5ca24b0c2beedb269f6e2a96f466acd926879ab00ae19f1a65cbf9ffb0", size = 5615269, upload-time = "2026-09-02T14:51:13.357Z" }, + { url = "https://files.pythonhosted.org/packages/5d/90/73675f3f4141350ed65d6fec533b107d4e802c5caa340cf111771edd86e0/lxml-6.1.3-cp315-cp315t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:69cafd61aea04ebb3502c93c2aaa568b12931ca0802231e0b5de76bf8b6e74bd", size = 5236280, upload-time = "2026-09-02T14:51:16.051Z" }, + { url = "https://files.pythonhosted.org/packages/fd/be/ed260767e7977de463a0f91f3f4fffcab85c0a2a024a21ffe1fa442c2c79/lxml-6.1.3-cp315-cp315t-manylinux_2_31_armv7l.whl", hash = "sha256:dc205732d593118cf701d986f40e9de7801bb2e371cb189ddbda9b7348f4d97e", size = 4650718, upload-time = "2026-09-02T14:51:19.102Z" }, + { url = "https://files.pythonhosted.org/packages/d0/fd/e9839d03b1e767f2725cf7d7d81b80d5f3f9fdc10ad8827e2479311b046e/lxml-6.1.3-cp315-cp315t-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:88e719b9437f148f7e1465df845c758dd1598618cbea3a2fd1e61a715542f2b2", size = 5243376, upload-time = "2026-09-02T14:51:21.606Z" }, + { url = "https://files.pythonhosted.org/packages/34/a5/4606e347e2788c301f677004aa83e28d24da9fe663a24380122af57be6fc/lxml-6.1.3-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:40983eabefd13da003e68170928c7acc011f0d095eefce5871a3c71c9385fb9a", size = 5092340, upload-time = "2026-09-02T14:51:24.21Z" }, + { url = "https://files.pythonhosted.org/packages/ea/99/3314a8661cdf30f493c55a87db283961dfaae08451976a2ca418958e1804/lxml-6.1.3-cp315-cp315t-musllinux_1_2_armv7l.whl", hash = "sha256:fad67b12ffe0f71e02b4932b04883cbc76a9072bbd30731409d3523cf058b011", size = 4758768, upload-time = "2026-09-02T14:51:26.813Z" }, + { url = "https://files.pythonhosted.org/packages/30/58/3bdc577f78ea8b7d72d39a84506f7001d5b28728f43e5b84891e3b7d9a4a/lxml-6.1.3-cp315-cp315t-musllinux_1_2_ppc64le.whl", hash = "sha256:6cd11e7550d89e551a87dcec30f04b1fca32e86b68708aa01a4daa455d8605e5", size = 5649546, upload-time = "2026-09-02T14:51:29.453Z" }, + { url = "https://files.pythonhosted.org/packages/6a/e4/652633de1a2395949ebb7a8fc7d089aba12a2b45f0fefbc9d29e3e3ab3cf/lxml-6.1.3-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:ca0ec532ad2f5ba1e5ec120ac157769c57f01855b3d8bf37213f5d88abd9ba0a", size = 5234874, upload-time = "2026-09-02T14:51:32.262Z" }, + { url = "https://files.pythonhosted.org/packages/65/a6/c4581d171de30449304b4859bbd3607e9b40da13c0f88b68e6097c8d785e/lxml-6.1.3-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:e99e09ab7741f1281e2677f4c0058c7f5267d182530b09c87e4f6aa26adf3887", size = 5260043, upload-time = "2026-09-02T14:51:34.841Z" }, + { url = "https://files.pythonhosted.org/packages/b8/d7/ed6ee6186a89e69ca4ea9658b2a278f46a5efe8b5d4db56c7197f18653fe/lxml-6.1.3-cp315-cp315t-win32.whl", hash = "sha256:ace1d2c83b2bd24db5940600541140e87a325e119cb32d5fa9ad720d7e76648e", size = 3901093, upload-time = "2026-09-02T14:51:37.234Z" }, + { url = "https://files.pythonhosted.org/packages/67/9d/11d10257a4a048d04195d638bb61f0246ce2448eb05f682bcbab25a257a8/lxml-6.1.3-cp315-cp315t-win_amd64.whl", hash = "sha256:b49638355ea3bebba70da783ccbc630fd72afa16bc46c54474bfa1f9a915bbc6", size = 4395446, upload-time = "2026-09-02T14:51:39.884Z" }, + { url = "https://files.pythonhosted.org/packages/f8/b7/44edd7de434181c582892e68d1ffe6775ca403ce14aea07cb5a218a936cf/lxml-6.1.3-cp315-cp315t-win_arm64.whl", hash = "sha256:5a721a98c649855963811b59b55755b30566e7f7fc40bdc9803d66dee9f811cf", size = 3822836, upload-time = "2026-09-02T14:51:42.471Z" }, + { url = "https://files.pythonhosted.org/packages/ad/23/dc1fdf3a53f84ca88b6e942277ddb47954844a0ececea8cc5fa3c1324831/lxml-6.1.3-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4b061064b4a2fe8598a466d723d43dbcd5a610a5d5cfe02fb6226f5c17349f75", size = 3947704, upload-time = "2026-09-02T14:46:22.27Z" }, + { url = "https://files.pythonhosted.org/packages/f0/ed/e36d547d6c958b5693b873504735cb4d0388d545945d66a7aed8983a720b/lxml-6.1.3-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8499d464de86fab0f102313cce32a9bed9ab1f06ec813cf025cb790964fbb765", size = 4220149, upload-time = "2026-09-02T14:46:24.907Z" }, + { url = "https://files.pythonhosted.org/packages/98/54/7f51e6b6cc0755f9b5fc6637748279e9f48289d917b3a47ac9fedf3318d3/lxml-6.1.3-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9e67324961ac9bbe616cce5100514d2e34d88665aeb07071e8b16eac55d06d94", size = 4329391, upload-time = "2026-09-02T14:46:27.111Z" }, + { url = "https://files.pythonhosted.org/packages/eb/9e/840b0d2e25c10c491b010d555b46e6e5264d3ad73a91557405fceb738c35/lxml-6.1.3-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d12669a2c419b0e8dc423d23dea24bb82f6f9cb829f32e04674b0ba40322a7c", size = 4262125, upload-time = "2026-09-02T14:46:29.199Z" }, + { url = "https://files.pythonhosted.org/packages/69/8f/42a41571dfc772c12628747f883d24c978053856825b99d7a187117b8079/lxml-6.1.3-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:97acecb11cbc411473f15b8d780df06d7a9f3a2aad9aca78364f56640c8fb70e", size = 4410104, upload-time = "2026-09-02T14:46:32.102Z" }, + { url = "https://files.pythonhosted.org/packages/f3/aa/27d93812be916f1f674b2035edd86d41c77745ff2ad84f58c25a7445a397/lxml-6.1.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f8b9c8ceebae6387d0dc77f7f4dbbfbfc962dba2efbfe6877486075a480726b4", size = 3510724, upload-time = "2026-09-02T14:46:34.122Z" }, + { url = "https://files.pythonhosted.org/packages/ec/c1/2433176de263cc3f51fd2c303f993d5bb7f1da3139a0f7d168116c0bfa7a/lxml-6.1.3-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:d2765c18ce303149ee804b1f3dad11232726dd0a702d73a15cf19179ac8cc962", size = 3942969, upload-time = "2026-09-02T14:46:36.55Z" }, + { url = "https://files.pythonhosted.org/packages/7c/71/de7759096f480180fd9e43ff7c017860e2d2a9a43741ab093cbdf1820f07/lxml-6.1.3-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d5a748d12dd9b535e0a130f60dae9ddf0adafbabe61e7864f55c7436c84547a", size = 4213008, upload-time = "2026-09-02T14:46:38.784Z" }, + { url = "https://files.pythonhosted.org/packages/b8/9b/c2d09af47a34fa6c0c27473083812b449a411680bd04bbe609cde291ddc8/lxml-6.1.3-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:41096ec0740a58dad03d3ae0c7486d306d20becefb13ceb1649835ab3eb64167", size = 4322012, upload-time = "2026-09-02T14:46:41.031Z" }, + { url = "https://files.pythonhosted.org/packages/68/f3/bf56fee0403ebd995be8e78ec9aca566016487d1b3cbf755ebea8ccffbdb/lxml-6.1.3-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:415e3a115c0d510e329020012834d1c0aa1c581ee53a218603e38abbc1dea70a", size = 4257402, upload-time = "2026-09-02T14:46:43.134Z" }, + { url = "https://files.pythonhosted.org/packages/1c/1d/6da9cc086a20d9dd6bcbf7c5d9575f0331cca9a05e67dab02d15e828170b/lxml-6.1.3-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20428910dae17a1a93152a3ff2c0441d2f4932992c0797d65651dd0561f1792f", size = 4410889, upload-time = "2026-09-02T14:46:46.975Z" }, + { url = "https://files.pythonhosted.org/packages/03/5c/91fe48856f9f8089be3096fa4dbe4b3fb5526f3bf3e852ea9497f399cb9f/lxml-6.1.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:bc8dd3d9c93e70c3df974a201ac2958b6d77b465d813c51d1f15fa8e645763ae", size = 3511258, upload-time = "2026-09-02T14:46:49.046Z" }, +] + +[[package]] +name = "lxml-stubs" +version = "0.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/99/da/1a3a3e5d159b249fc2970d73437496b908de8e4716a089c69591b4ffa6fd/lxml-stubs-0.5.1.tar.gz", hash = "sha256:e0ec2aa1ce92d91278b719091ce4515c12adc1d564359dfaf81efa7d4feab79d", size = 14778, upload-time = "2024-01-10T09:37:46.521Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/c9/e0f8e4e6e8a69e5959b06499582dca6349db6769cc7fdfb8a02a7c75a9ae/lxml_stubs-0.5.1-py3-none-any.whl", hash = "sha256:1f689e5dbc4b9247cb09ae820c7d34daeb1fdbd1db06123814b856dae7787272", size = 13584, upload-time = "2024-01-10T09:37:44.931Z" }, +] + +[[package]] +name = "narwhals" +version = "2.28.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/67/43/e11d75a7fb635c6f63dd6e176cb3e050ec2fee35f2f2267b332a6ad351ec/narwhals-2.28.0.tar.gz", hash = "sha256:2d9860c80d6610820826e94c6e42ce4b1d92d89cdd479586e652a8d211dab345", size = 754977, upload-time = "2026-10-27T12:19:33.777Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cf/82/8ef9c7e0f50493307a49c09cfa7f00c5a778b6d1921f7b2dabe1d3a5809e/narwhals-2.28.0-py3-none-any.whl", hash = "sha256:1f69d6385ec30e2fa6e1fdeb37c562ecabd0f713f6f3e3b58a668c5c9df9567f", size = 490591, upload-time = "2026-10-27T12:19:31.649Z" }, +] + +[[package]] +name = "numpy" +version = "2.2.6" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11'", +] +sdist = { url = "https://files.pythonhosted.org/packages/76/21/7d2a95e4bba9dc13d043ee156a356c0a8f0c6309dff6b21b4d71a073b8a8/numpy-2.2.6.tar.gz", hash = "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd", size = 20276440, upload-time = "2025-05-17T22:38:04.611Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9a/3e/ed6db5be21ce87955c0cbd3009f2803f59fa08df21b5df06862e2d8e2bdd/numpy-2.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb", size = 21165245, upload-time = "2025-05-17T21:27:58.555Z" }, + { url = "https://files.pythonhosted.org/packages/22/c2/4b9221495b2a132cc9d2eb862e21d42a009f5a60e45fc44b00118c174bff/numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90", size = 14360048, upload-time = "2025-05-17T21:28:21.406Z" }, + { url = "https://files.pythonhosted.org/packages/fd/77/dc2fcfc66943c6410e2bf598062f5959372735ffda175b39906d54f02349/numpy-2.2.6-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:37e990a01ae6ec7fe7fa1c26c55ecb672dd98b19c3d0e1d1f326fa13cb38d163", size = 5340542, upload-time = "2025-05-17T21:28:30.931Z" }, + { url = "https://files.pythonhosted.org/packages/7a/4f/1cb5fdc353a5f5cc7feb692db9b8ec2c3d6405453f982435efc52561df58/numpy-2.2.6-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:5a6429d4be8ca66d889b7cf70f536a397dc45ba6faeb5f8c5427935d9592e9cf", size = 6878301, upload-time = "2025-05-17T21:28:41.613Z" }, + { url = "https://files.pythonhosted.org/packages/eb/17/96a3acd228cec142fcb8723bd3cc39c2a474f7dcf0a5d16731980bcafa95/numpy-2.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efd28d4e9cd7d7a8d39074a4d44c63eda73401580c5c76acda2ce969e0a38e83", size = 14297320, upload-time = "2025-05-17T21:29:02.78Z" }, + { url = "https://files.pythonhosted.org/packages/b4/63/3de6a34ad7ad6646ac7d2f55ebc6ad439dbbf9c4370017c50cf403fb19b5/numpy-2.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc7b73d02efb0e18c000e9ad8b83480dfcd5dfd11065997ed4c6747470ae8915", size = 16801050, upload-time = "2025-05-17T21:29:27.675Z" }, + { url = "https://files.pythonhosted.org/packages/07/b6/89d837eddef52b3d0cec5c6ba0456c1bf1b9ef6a6672fc2b7873c3ec4e2e/numpy-2.2.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74d4531beb257d2c3f4b261bfb0fc09e0f9ebb8842d82a7b4209415896adc680", size = 15807034, upload-time = "2025-05-17T21:29:51.102Z" }, + { url = "https://files.pythonhosted.org/packages/01/c8/dc6ae86e3c61cfec1f178e5c9f7858584049b6093f843bca541f94120920/numpy-2.2.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8fc377d995680230e83241d8a96def29f204b5782f371c532579b4f20607a289", size = 18614185, upload-time = "2025-05-17T21:30:18.703Z" }, + { url = "https://files.pythonhosted.org/packages/5b/c5/0064b1b7e7c89137b471ccec1fd2282fceaae0ab3a9550f2568782d80357/numpy-2.2.6-cp310-cp310-win32.whl", hash = "sha256:b093dd74e50a8cba3e873868d9e93a85b78e0daf2e98c6797566ad8044e8363d", size = 6527149, upload-time = "2025-05-17T21:30:29.788Z" }, + { url = "https://files.pythonhosted.org/packages/a3/dd/4b822569d6b96c39d1215dbae0582fd99954dcbcf0c1a13c61783feaca3f/numpy-2.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:f0fd6321b839904e15c46e0d257fdd101dd7f530fe03fd6359c1ea63738703f3", size = 12904620, upload-time = "2025-05-17T21:30:48.994Z" }, + { url = "https://files.pythonhosted.org/packages/da/a8/4f83e2aa666a9fbf56d6118faaaf5f1974d456b1823fda0a176eff722839/numpy-2.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f9f1adb22318e121c5c69a09142811a201ef17ab257a1e66ca3025065b7f53ae", size = 21176963, upload-time = "2025-05-17T21:31:19.36Z" }, + { url = "https://files.pythonhosted.org/packages/b3/2b/64e1affc7972decb74c9e29e5649fac940514910960ba25cd9af4488b66c/numpy-2.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c820a93b0255bc360f53eca31a0e676fd1101f673dda8da93454a12e23fc5f7a", size = 14406743, upload-time = "2025-05-17T21:31:41.087Z" }, + { url = "https://files.pythonhosted.org/packages/4a/9f/0121e375000b5e50ffdd8b25bf78d8e1a5aa4cca3f185d41265198c7b834/numpy-2.2.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3d70692235e759f260c3d837193090014aebdf026dfd167834bcba43e30c2a42", size = 5352616, upload-time = "2025-05-17T21:31:50.072Z" }, + { url = "https://files.pythonhosted.org/packages/31/0d/b48c405c91693635fbe2dcd7bc84a33a602add5f63286e024d3b6741411c/numpy-2.2.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:481b49095335f8eed42e39e8041327c05b0f6f4780488f61286ed3c01368d491", size = 6889579, upload-time = "2025-05-17T21:32:01.712Z" }, + { url = "https://files.pythonhosted.org/packages/52/b8/7f0554d49b565d0171eab6e99001846882000883998e7b7d9f0d98b1f934/numpy-2.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b64d8d4d17135e00c8e346e0a738deb17e754230d7e0810ac5012750bbd85a5a", size = 14312005, upload-time = "2025-05-17T21:32:23.332Z" }, + { url = "https://files.pythonhosted.org/packages/b3/dd/2238b898e51bd6d389b7389ffb20d7f4c10066d80351187ec8e303a5a475/numpy-2.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba10f8411898fc418a521833e014a77d3ca01c15b0c6cdcce6a0d2897e6dbbdf", size = 16821570, upload-time = "2025-05-17T21:32:47.991Z" }, + { url = "https://files.pythonhosted.org/packages/83/6c/44d0325722cf644f191042bf47eedad61c1e6df2432ed65cbe28509d404e/numpy-2.2.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd48227a919f1bafbdda0583705e547892342c26fb127219d60a5c36882609d1", size = 15818548, upload-time = "2025-05-17T21:33:11.728Z" }, + { url = "https://files.pythonhosted.org/packages/ae/9d/81e8216030ce66be25279098789b665d49ff19eef08bfa8cb96d4957f422/numpy-2.2.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9551a499bf125c1d4f9e250377c1ee2eddd02e01eac6644c080162c0c51778ab", size = 18620521, upload-time = "2025-05-17T21:33:39.139Z" }, + { url = "https://files.pythonhosted.org/packages/6a/fd/e19617b9530b031db51b0926eed5345ce8ddc669bb3bc0044b23e275ebe8/numpy-2.2.6-cp311-cp311-win32.whl", hash = "sha256:0678000bb9ac1475cd454c6b8c799206af8107e310843532b04d49649c717a47", size = 6525866, upload-time = "2025-05-17T21:33:50.273Z" }, + { url = "https://files.pythonhosted.org/packages/31/0a/f354fb7176b81747d870f7991dc763e157a934c717b67b58456bc63da3df/numpy-2.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:e8213002e427c69c45a52bbd94163084025f533a55a59d6f9c5b820774ef3303", size = 12907455, upload-time = "2025-05-17T21:34:09.135Z" }, + { url = "https://files.pythonhosted.org/packages/82/5d/c00588b6cf18e1da539b45d3598d3557084990dcc4331960c15ee776ee41/numpy-2.2.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff", size = 20875348, upload-time = "2025-05-17T21:34:39.648Z" }, + { url = "https://files.pythonhosted.org/packages/66/ee/560deadcdde6c2f90200450d5938f63a34b37e27ebff162810f716f6a230/numpy-2.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c", size = 14119362, upload-time = "2025-05-17T21:35:01.241Z" }, + { url = "https://files.pythonhosted.org/packages/3c/65/4baa99f1c53b30adf0acd9a5519078871ddde8d2339dc5a7fde80d9d87da/numpy-2.2.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3", size = 5084103, upload-time = "2025-05-17T21:35:10.622Z" }, + { url = "https://files.pythonhosted.org/packages/cc/89/e5a34c071a0570cc40c9a54eb472d113eea6d002e9ae12bb3a8407fb912e/numpy-2.2.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282", size = 6625382, upload-time = "2025-05-17T21:35:21.414Z" }, + { url = "https://files.pythonhosted.org/packages/f8/35/8c80729f1ff76b3921d5c9487c7ac3de9b2a103b1cd05e905b3090513510/numpy-2.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87", size = 14018462, upload-time = "2025-05-17T21:35:42.174Z" }, + { url = "https://files.pythonhosted.org/packages/8c/3d/1e1db36cfd41f895d266b103df00ca5b3cbe965184df824dec5c08c6b803/numpy-2.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249", size = 16527618, upload-time = "2025-05-17T21:36:06.711Z" }, + { url = "https://files.pythonhosted.org/packages/61/c6/03ed30992602c85aa3cd95b9070a514f8b3c33e31124694438d88809ae36/numpy-2.2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49", size = 15505511, upload-time = "2025-05-17T21:36:29.965Z" }, + { url = "https://files.pythonhosted.org/packages/b7/25/5761d832a81df431e260719ec45de696414266613c9ee268394dd5ad8236/numpy-2.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de", size = 18313783, upload-time = "2025-05-17T21:36:56.883Z" }, + { url = "https://files.pythonhosted.org/packages/57/0a/72d5a3527c5ebffcd47bde9162c39fae1f90138c961e5296491ce778e682/numpy-2.2.6-cp312-cp312-win32.whl", hash = "sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4", size = 6246506, upload-time = "2025-05-17T21:37:07.368Z" }, + { url = "https://files.pythonhosted.org/packages/36/fa/8c9210162ca1b88529ab76b41ba02d433fd54fecaf6feb70ef9f124683f1/numpy-2.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2", size = 12614190, upload-time = "2025-05-17T21:37:26.213Z" }, + { url = "https://files.pythonhosted.org/packages/f9/5c/6657823f4f594f72b5471f1db1ab12e26e890bb2e41897522d134d2a3e81/numpy-2.2.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0811bb762109d9708cca4d0b13c4f67146e3c3b7cf8d34018c722adb2d957c84", size = 20867828, upload-time = "2025-05-17T21:37:56.699Z" }, + { url = "https://files.pythonhosted.org/packages/dc/9e/14520dc3dadf3c803473bd07e9b2bd1b69bc583cb2497b47000fed2fa92f/numpy-2.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:287cc3162b6f01463ccd86be154f284d0893d2b3ed7292439ea97eafa8170e0b", size = 14143006, upload-time = "2025-05-17T21:38:18.291Z" }, + { url = "https://files.pythonhosted.org/packages/4f/06/7e96c57d90bebdce9918412087fc22ca9851cceaf5567a45c1f404480e9e/numpy-2.2.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:f1372f041402e37e5e633e586f62aa53de2eac8d98cbfb822806ce4bbefcb74d", size = 5076765, upload-time = "2025-05-17T21:38:27.319Z" }, + { url = "https://files.pythonhosted.org/packages/73/ed/63d920c23b4289fdac96ddbdd6132e9427790977d5457cd132f18e76eae0/numpy-2.2.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:55a4d33fa519660d69614a9fad433be87e5252f4b03850642f88993f7b2ca566", size = 6617736, upload-time = "2025-05-17T21:38:38.141Z" }, + { url = "https://files.pythonhosted.org/packages/85/c5/e19c8f99d83fd377ec8c7e0cf627a8049746da54afc24ef0a0cb73d5dfb5/numpy-2.2.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f92729c95468a2f4f15e9bb94c432a9229d0d50de67304399627a943201baa2f", size = 14010719, upload-time = "2025-05-17T21:38:58.433Z" }, + { url = "https://files.pythonhosted.org/packages/19/49/4df9123aafa7b539317bf6d342cb6d227e49f7a35b99c287a6109b13dd93/numpy-2.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bc23a79bfabc5d056d106f9befb8d50c31ced2fbc70eedb8155aec74a45798f", size = 16526072, upload-time = "2025-05-17T21:39:22.638Z" }, + { url = "https://files.pythonhosted.org/packages/b2/6c/04b5f47f4f32f7c2b0e7260442a8cbcf8168b0e1a41ff1495da42f42a14f/numpy-2.2.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3143e4451880bed956e706a3220b4e5cf6172ef05fcc397f6f36a550b1dd868", size = 15503213, upload-time = "2025-05-17T21:39:45.865Z" }, + { url = "https://files.pythonhosted.org/packages/17/0a/5cd92e352c1307640d5b6fec1b2ffb06cd0dabe7d7b8227f97933d378422/numpy-2.2.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4f13750ce79751586ae2eb824ba7e1e8dba64784086c98cdbbcc6a42112ce0d", size = 18316632, upload-time = "2025-05-17T21:40:13.331Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3b/5cba2b1d88760ef86596ad0f3d484b1cbff7c115ae2429678465057c5155/numpy-2.2.6-cp313-cp313-win32.whl", hash = "sha256:5beb72339d9d4fa36522fc63802f469b13cdbe4fdab4a288f0c441b74272ebfd", size = 6244532, upload-time = "2025-05-17T21:43:46.099Z" }, + { url = "https://files.pythonhosted.org/packages/cb/3b/d58c12eafcb298d4e6d0d40216866ab15f59e55d148a5658bb3132311fcf/numpy-2.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c", size = 12610885, upload-time = "2025-05-17T21:44:05.145Z" }, + { url = "https://files.pythonhosted.org/packages/6b/9e/4bf918b818e516322db999ac25d00c75788ddfd2d2ade4fa66f1f38097e1/numpy-2.2.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0bca768cd85ae743b2affdc762d617eddf3bcf8724435498a1e80132d04879e6", size = 20963467, upload-time = "2025-05-17T21:40:44Z" }, + { url = "https://files.pythonhosted.org/packages/61/66/d2de6b291507517ff2e438e13ff7b1e2cdbdb7cb40b3ed475377aece69f9/numpy-2.2.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fc0c5673685c508a142ca65209b4e79ed6740a4ed6b2267dbba90f34b0b3cfda", size = 14225144, upload-time = "2025-05-17T21:41:05.695Z" }, + { url = "https://files.pythonhosted.org/packages/e4/25/480387655407ead912e28ba3a820bc69af9adf13bcbe40b299d454ec011f/numpy-2.2.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5bd4fc3ac8926b3819797a7c0e2631eb889b4118a9898c84f585a54d475b7e40", size = 5200217, upload-time = "2025-05-17T21:41:15.903Z" }, + { url = "https://files.pythonhosted.org/packages/aa/4a/6e313b5108f53dcbf3aca0c0f3e9c92f4c10ce57a0a721851f9785872895/numpy-2.2.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:fee4236c876c4e8369388054d02d0e9bb84821feb1a64dd59e137e6511a551f8", size = 6712014, upload-time = "2025-05-17T21:41:27.321Z" }, + { url = "https://files.pythonhosted.org/packages/b7/30/172c2d5c4be71fdf476e9de553443cf8e25feddbe185e0bd88b096915bcc/numpy-2.2.6-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1dda9c7e08dc141e0247a5b8f49cf05984955246a327d4c48bda16821947b2f", size = 14077935, upload-time = "2025-05-17T21:41:49.738Z" }, + { url = "https://files.pythonhosted.org/packages/12/fb/9e743f8d4e4d3c710902cf87af3512082ae3d43b945d5d16563f26ec251d/numpy-2.2.6-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f447e6acb680fd307f40d3da4852208af94afdfab89cf850986c3ca00562f4fa", size = 16600122, upload-time = "2025-05-17T21:42:14.046Z" }, + { url = "https://files.pythonhosted.org/packages/12/75/ee20da0e58d3a66f204f38916757e01e33a9737d0b22373b3eb5a27358f9/numpy-2.2.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:389d771b1623ec92636b0786bc4ae56abafad4a4c513d36a55dce14bd9ce8571", size = 15586143, upload-time = "2025-05-17T21:42:37.464Z" }, + { url = "https://files.pythonhosted.org/packages/76/95/bef5b37f29fc5e739947e9ce5179ad402875633308504a52d188302319c8/numpy-2.2.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8e9ace4a37db23421249ed236fdcdd457d671e25146786dfc96835cd951aa7c1", size = 18385260, upload-time = "2025-05-17T21:43:05.189Z" }, + { url = "https://files.pythonhosted.org/packages/09/04/f2f83279d287407cf36a7a8053a5abe7be3622a4363337338f2585e4afda/numpy-2.2.6-cp313-cp313t-win32.whl", hash = "sha256:038613e9fb8c72b0a41f025a7e4c3f0b7a1b5d768ece4796b674c8f3fe13efff", size = 6377225, upload-time = "2025-05-17T21:43:16.254Z" }, + { url = "https://files.pythonhosted.org/packages/67/0e/35082d13c09c02c011cf21570543d202ad929d961c02a147493cb0c2bdf5/numpy-2.2.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6031dd6dfecc0cf9f668681a37648373bddd6421fff6c66ec1624eed0180ee06", size = 12771374, upload-time = "2025-05-17T21:43:35.479Z" }, + { url = "https://files.pythonhosted.org/packages/9e/3b/d94a75f4dbf1ef5d321523ecac21ef23a3cd2ac8b78ae2aac40873590229/numpy-2.2.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0b605b275d7bd0c640cad4e5d30fa701a8d59302e127e5f79138ad62762c3e3d", size = 21040391, upload-time = "2025-05-17T21:44:35.948Z" }, + { url = "https://files.pythonhosted.org/packages/17/f4/09b2fa1b58f0fb4f7c7963a1649c64c4d315752240377ed74d9cd878f7b5/numpy-2.2.6-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:7befc596a7dc9da8a337f79802ee8adb30a552a94f792b9c9d18c840055907db", size = 6786754, upload-time = "2025-05-17T21:44:47.446Z" }, + { url = "https://files.pythonhosted.org/packages/af/30/feba75f143bdc868a1cc3f44ccfa6c4b9ec522b36458e738cd00f67b573f/numpy-2.2.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce47521a4754c8f4593837384bd3424880629f718d87c5d44f8ed763edd63543", size = 16643476, upload-time = "2025-05-17T21:45:11.871Z" }, + { url = "https://files.pythonhosted.org/packages/37/48/ac2a9584402fb6c0cd5b5d1a91dcf176b15760130dd386bbafdbfe3640bf/numpy-2.2.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d042d24c90c41b54fd506da306759e06e568864df8ec17ccc17e9e884634fd00", size = 12812666, upload-time = "2025-05-17T21:45:31.426Z" }, +] + +[[package]] +name = "numpy" +version = "2.4.6" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version == '3.11.*'", +] +sdist = { url = "https://files.pythonhosted.org/packages/d0/ad/fed0499ce6a338d2a03ebae59cd15093910c8875328855781952abf6c2fe/numpy-2.4.6.tar.gz", hash = "sha256:f3a3570c4a2a16746ac2c31a7c7c7b0c186b95ce902e33db6f28094ed7387dda", size = 20735807, upload-time = "2026-05-18T23:37:14.07Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/49/ec46835a70be8fa6446c495126ac84fdb28cb2558e1620ffb87a10c8b64c/numpy-2.4.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0280e0356c0829a18d9de1cb7eee50ec22ca639878d7240307ca0943d73cd2c4", size = 16969194, upload-time = "2026-05-18T23:33:13.503Z" }, + { url = "https://files.pythonhosted.org/packages/0e/0d/f5957185c0ee2f3e12f78715aa9e3b353fd83633316c8532b38faa37e3f6/numpy-2.4.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:110f8b71aacb688ec69062bb7f6938a0f8acb01b7c1c4beb453c65b6d234584d", size = 14964111, upload-time = "2026-05-18T23:33:17.795Z" }, + { url = "https://files.pythonhosted.org/packages/ad/40/40a40ee0ddf7ceb782c49af278894b686e586d65d8c1889c8b5da01a3d7d/numpy-2.4.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:4cfe66903cc32a9921a6733d96b19bb6abf310397581bbad89c228f5abaf0ee8", size = 5469159, upload-time = "2026-05-18T23:33:20.654Z" }, + { url = "https://files.pythonhosted.org/packages/63/13/f9a8046535cb21deae82f8d03de9617e08882d274fad2539630761888228/numpy-2.4.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8155154c7c691289fe18f510b5d4657c68c67989f293f0535a91360392ff6538", size = 6798936, upload-time = "2026-05-18T23:33:22.987Z" }, + { url = "https://files.pythonhosted.org/packages/33/a8/6fa8c1a345a8c85dbb21932c447bee07c30a2c2a3f31e369c0a84b300147/numpy-2.4.6-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ab0a9c4ffb1a6d95ef519fe4247dba8eb6b18ad93999f76b7f657039acabd47", size = 15966692, upload-time = "2026-05-18T23:33:26.62Z" }, + { url = "https://files.pythonhosted.org/packages/02/03/74fe2a4cb3817d94d86402f2506554130a2f01414e299b5a843e5a8a957f/numpy-2.4.6-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:89cd468399cfd2504718f0ba50e410dca55a170b61a02ad92bb18c8a65186e93", size = 16918164, upload-time = "2026-05-18T23:33:29.955Z" }, + { url = "https://files.pythonhosted.org/packages/c5/80/3615be3313f7e7696609bc194b9f0101da809df79e859bdb84e0cd043f46/numpy-2.4.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c2d37ab77531417474168eb79d6d80b14f821a966818505d03013d0833edb7a8", size = 17322877, upload-time = "2026-05-18T23:33:34.724Z" }, + { url = "https://files.pythonhosted.org/packages/ca/ac/a691e0fe2675e370d0e08ff905adc49a1c8830e8cae03efe4477e92cd55d/numpy-2.4.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f407cb6b8e9d6d8c626bc73c945db1706035af8fd632295547bf1c9e46d092d6", size = 18651487, upload-time = "2026-05-18T23:33:38.217Z" }, + { url = "https://files.pythonhosted.org/packages/15/a7/9bc1cd626d7bf6869bfedf27b91b6ab5dd607758bf8e959d6fa80c6a59cb/numpy-2.4.6-cp311-cp311-win32.whl", hash = "sha256:ddea102b48f9e339f3948bf22040944184627a30fdf7f858667673b9c5f033c8", size = 6233945, upload-time = "2026-05-18T23:33:41.331Z" }, + { url = "https://files.pythonhosted.org/packages/c5/31/7fc6239c12bce7e931463251cca4426c465e1876ba3cc785402ef4dd8f4e/numpy-2.4.6-cp311-cp311-win_amd64.whl", hash = "sha256:1e254a00cdf42b1e4d5b3d68d33af63268d41340d8885df2ab6470f2e1500147", size = 12608406, upload-time = "2026-05-18T23:33:44.131Z" }, + { url = "https://files.pythonhosted.org/packages/27/83/140f85a466595a16382996a1bf06b2b54bcd597488921b0c9daaeeda72af/numpy-2.4.6-cp311-cp311-win_arm64.whl", hash = "sha256:ed9749eef4cbd126da3dc1d6bcb3a57f5eb7ac6a6484146bdbf743f552dfc577", size = 10479528, upload-time = "2026-05-18T23:33:50.725Z" }, + { url = "https://files.pythonhosted.org/packages/95/2a/3d7b5ac8aac24feaf9ad7ed58f45b0bbc06d37e4338ae84c9f2298b570f9/numpy-2.4.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:001fbb8e08d942dd57599e781f2472269ee7f2755fae407b4f67b2f0b17da3f1", size = 16689119, upload-time = "2026-05-18T23:33:54.065Z" }, + { url = "https://files.pythonhosted.org/packages/ea/12/92c4c131527599e8288d6918e888d88726f84d805d784b771f32408aeaef/numpy-2.4.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ebfb099f8dcf083deef3ac1ca4c1503f387cf76296fcb3816b66f5ecb5f54fdb", size = 14699246, upload-time = "2026-05-18T23:33:57.621Z" }, + { url = "https://files.pythonhosted.org/packages/ad/fe/c0a6b7b2ca128a8fb228575147073b660656734b8ebe4d76c8fd748dcc79/numpy-2.4.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:3213d622a0283a39a93d188f3cf72b26862df52fbb4ca3697f51705016523d41", size = 5204410, upload-time = "2026-05-18T23:34:00.302Z" }, + { url = "https://files.pythonhosted.org/packages/f3/d4/9770d14ba719432bb90a421bfd443872ed0f70f7264b64bec12ea363d5fd/numpy-2.4.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:357cc07a6d7b0b182ff02249616a03742827ebb1277546b5c7cd7f7620a45698", size = 6551240, upload-time = "2026-05-18T23:34:02.852Z" }, + { url = "https://files.pythonhosted.org/packages/c9/c6/50a46a6205feba2343f1d6d17438107c5dc491ed1c736e6ea68689fd906b/numpy-2.4.6-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f9fb9157b4ce2971008323afe46053787b526ef624fea915b261468a8421a0f", size = 15671012, upload-time = "2026-05-18T23:34:05.485Z" }, + { url = "https://files.pythonhosted.org/packages/99/60/14115e6364fa676c5397c2ad3004e527e9aa487abf5d0706ec81bbd08529/numpy-2.4.6-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90f9849678c75fe7afa2d348ac842c168b0a4d3d61919687216dfc547976d853", size = 16645538, upload-time = "2026-05-18T23:34:09.265Z" }, + { url = "https://files.pythonhosted.org/packages/ae/c5/693cbe59e57db94d2231fa519ca3978dc9e19da5a8f088588f5c6e947ff2/numpy-2.4.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c1a2af6c6ef86344a6b0db6b97834208bf598db514f2b155042439b62605601a", size = 17020706, upload-time = "2026-05-18T23:34:13.053Z" }, + { url = "https://files.pythonhosted.org/packages/ef/fc/85b7c4eff9b4966ade25c2273cf7e7012e92366c032058653934b37de044/numpy-2.4.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e5805d5a22fd19c8ccff10a9561f9df94436b0545619ea579db2d3c35294bce2", size = 18368541, upload-time = "2026-05-18T23:34:17.024Z" }, + { url = "https://files.pythonhosted.org/packages/f6/81/e1b27545deedce7f4a0b348618c6b62d74e36a4dc9ccd42f3eb2f85eee32/numpy-2.4.6-cp312-cp312-win32.whl", hash = "sha256:e3eeb0aabd6bd5ce64faae67e9935203a6991b4bc2a485a767fbafb2c5125f45", size = 5962825, upload-time = "2026-05-18T23:34:20.3Z" }, + { url = "https://files.pythonhosted.org/packages/ab/ca/feab00bd44aa5fe1ad2c18f08b4d3bb92e26484b0b1d1443897809ed528c/numpy-2.4.6-cp312-cp312-win_amd64.whl", hash = "sha256:d8e8286dd7cea7895157318d1b91cdacac64c479f3cbc8dce548331728484751", size = 12321687, upload-time = "2026-05-18T23:34:23.095Z" }, + { url = "https://files.pythonhosted.org/packages/63/cf/5a6d34850a39d1093558564f77ee8e8e0bee5061151b8f05a55711001ec7/numpy-2.4.6-cp312-cp312-win_arm64.whl", hash = "sha256:4081eb135ac24158bd51cdfbef16f1c64df7063b1143f24731387137c092bec8", size = 10221482, upload-time = "2026-05-18T23:34:25.876Z" }, + { url = "https://files.pythonhosted.org/packages/fb/82/bdab26d7438c6791ca31b7c024ca37c1eab8b726ba236129005cd4a06e45/numpy-2.4.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:511dbaf848decaaaf4b4ca48032619fb3138710c4bf7da7617765edad1ef96b0", size = 16684648, upload-time = "2026-05-18T23:34:29.41Z" }, + { url = "https://files.pythonhosted.org/packages/1b/30/a80189bcc7f5e4258b3fbc3968d909d1756f54d023299ecc39ad6fdb9ef8/numpy-2.4.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bf162abab1c1a736333192707cef898e735a5ca00f38f27eeedf44b39d9e85eb", size = 14693902, upload-time = "2026-05-18T23:34:33.013Z" }, + { url = "https://files.pythonhosted.org/packages/97/12/70b5d0d7c15e1ebb8a6a84a8caa1d19e181d84fb58bb6d70aca29099dec1/numpy-2.4.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:043191bfa8eab18c776647b62723ac9dddece59743b13f49b2016094129c2b3f", size = 5198992, upload-time = "2026-05-18T23:34:36.132Z" }, + { url = "https://files.pythonhosted.org/packages/ba/8c/ebd2a8f8a83541f8d38cc5667e8c2b69cecfd30da6e45693e8158857d44b/numpy-2.4.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:6180d8b35af935aed8ece3a85e0a43f87393ae0ac87c8d2c8bd2c993f7270ef3", size = 6546944, upload-time = "2026-05-18T23:34:38.484Z" }, + { url = "https://files.pythonhosted.org/packages/bb/c5/7b863a97a91671a0338f4253bd3b5a3d3852f0692dae91711c9f4a10e787/numpy-2.4.6-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72fbe16c6fac95aedf5937fa873445cec2110be35d8a4e9433d7501fd98dae6b", size = 15669392, upload-time = "2026-05-18T23:34:41.257Z" }, + { url = "https://files.pythonhosted.org/packages/a5/9d/3584b9984ca4c047aea75214ce1a4c4c73d849bd71b604264b7f5653f8a8/numpy-2.4.6-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a7830bab239b79cda9c08c2da014761cafb48da6150e1da17ac06283f43b6089", size = 16633220, upload-time = "2026-05-18T23:34:45.075Z" }, + { url = "https://files.pythonhosted.org/packages/05/ae/7c67fba23bd98caec7c99261f3a16072ade14813486b0282cb29846de832/numpy-2.4.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ef4aea96ce4d3b074422cb4f2f64e216bf9e213004bb58ecfdf50ea02ea8eb9a", size = 17020800, upload-time = "2026-05-18T23:34:49.065Z" }, + { url = "https://files.pythonhosted.org/packages/d9/5d/3b6725cb31d983c5e66916f5d36f6d7e5521129e4c4404d64f918292a5b6/numpy-2.4.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dfa20cc6ca228e6b155b11da03825975ce66aea520985dbbddf0f2a5a495c605", size = 18357600, upload-time = "2026-05-18T23:34:52.709Z" }, + { url = "https://files.pythonhosted.org/packages/f7/da/2ccc6c2fe8898dee01d90c75c5f5f914a23daf99e3e0f59516a08760c8b5/numpy-2.4.6-cp313-cp313-win32.whl", hash = "sha256:56b39e5e0622a09a25bf5baf62f4bcf0cb8a41ae6e2819cf49bbc5a74c083f91", size = 5961134, upload-time = "2026-05-18T23:34:55.618Z" }, + { url = "https://files.pythonhosted.org/packages/b5/cd/9cc4dc876fb065d5c220aae4d5e14826b2715331bb7618ce1fb07a679d99/numpy-2.4.6-cp313-cp313-win_amd64.whl", hash = "sha256:c4fc99836233ea196540b17ab0983aff60ed07941751930f5f4d05bc3b3b7359", size = 12318598, upload-time = "2026-05-18T23:34:58.928Z" }, + { url = "https://files.pythonhosted.org/packages/39/1e/c0bcba1f8694116485fe28fd1be698c278fcda4141c5b0e53a2aed8b12a8/numpy-2.4.6-cp313-cp313-win_arm64.whl", hash = "sha256:a7c711e21628b52034bb5ab8d1bce291f752fcc5e92accc615778acee1ff4778", size = 10222272, upload-time = "2026-05-18T23:35:02.167Z" }, + { url = "https://files.pythonhosted.org/packages/63/6d/cc5619247c8f4204e507f5883528372e4ac4bb189e579fb859a12e480b1f/numpy-2.4.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:112b06a867b235ef466ed3508ddf0238050df9c727cafb5301ac385b899189a1", size = 14821197, upload-time = "2026-05-18T23:35:05.468Z" }, + { url = "https://files.pythonhosted.org/packages/00/58/f1c39161c87d9e9bed660f1ed4bafc0e403d5ec9650b6dd77aead07d489b/numpy-2.4.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:eaf7fa2de5c0be8ae6ff8e9bea2ccd725e980541244521d8d4b5f3354a27babe", size = 5326287, upload-time = "2026-05-18T23:35:08.693Z" }, + { url = "https://files.pythonhosted.org/packages/af/57/3917ab0fd97f271a8694513581b8a36c655f111c446852c302f04ccdb6fc/numpy-2.4.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:7265a2f3d436e54ef9f2b52b5c937e6be778781bd97a590319d7348f1c1ca997", size = 6646763, upload-time = "2026-05-18T23:35:11.459Z" }, + { url = "https://files.pythonhosted.org/packages/eb/0f/037e64c494b67581ae18193d770adef354c41f3f2c8ebf865602d949bf8f/numpy-2.4.6-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f74a575920ab21fe304421a3fc28793d82e299cae9eccb37084e9fc7f3617c20", size = 15728070, upload-time = "2026-05-18T23:35:14.79Z" }, + { url = "https://files.pythonhosted.org/packages/21/a6/5d2bae9c9542eb4df16dc9c46dc79c186e9bad53805dfa5399a6023c6db0/numpy-2.4.6-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ede83e07a75dd06bc501566c1eca2afc0d61677c1472ac9ad93fdee6e638a48d", size = 16681752, upload-time = "2026-05-18T23:35:18.836Z" }, + { url = "https://files.pythonhosted.org/packages/92/14/23d1dfb410ae362cd59ce53e936b1513d545eb40db3949ced632e19a459e/numpy-2.4.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:68bb27509ac1b9a3443094260f6326150663b06abe40b73a2f81160623da5b67", size = 17086024, upload-time = "2026-05-18T23:35:22.52Z" }, + { url = "https://files.pythonhosted.org/packages/4b/6e/23595a2c642cdf3bc567877064bdd7f91c8b0038a4453cf2daf7248eafe9/numpy-2.4.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a0df0043bdb289bde1f62da130d20df23d58b45429f752bc7a8fc5325a225ecd", size = 18403398, upload-time = "2026-05-18T23:35:26.398Z" }, + { url = "https://files.pythonhosted.org/packages/8a/90/0ac3bc947217e66dec77e7cbc6a1979d1af70b6461b82f620d3bccd5e4c8/numpy-2.4.6-cp313-cp313t-win32.whl", hash = "sha256:29a287e0cf63ff528da061de6b9f64a4618da591ca1046aafc54062e40ca7eab", size = 6084971, upload-time = "2026-05-18T23:35:29.387Z" }, + { url = "https://files.pythonhosted.org/packages/77/71/5673e351671a1d2bd6063b91b44f70c0affea7d1516fa7a6572941ba4aa1/numpy-2.4.6-cp313-cp313t-win_amd64.whl", hash = "sha256:25c692919ac5a01f170a3bfcd62d745b24fd095c353d50812637d6fcab442e75", size = 12458532, upload-time = "2026-05-18T23:35:32.175Z" }, + { url = "https://files.pythonhosted.org/packages/3f/88/19d3503c5046e688f049274b27a3ef3d771152fa80d3ba3d01a3dff61abe/numpy-2.4.6-cp313-cp313t-win_arm64.whl", hash = "sha256:1e978ec1e8bd0e0e4de6bb75de9d30cbb74db6b6a2bb727618613703ca0167dd", size = 10291881, upload-time = "2026-05-18T23:35:35.465Z" }, + { url = "https://files.pythonhosted.org/packages/f8/91/3ab2044d05fd16d343c5ac2e69b127f1b2854040dd20b193257c78028bd3/numpy-2.4.6-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:06ca2f61ec4385a07a6977c55ba998a4466c123642b4a32694d3128fce18c079", size = 16683458, upload-time = "2026-05-18T23:35:38.353Z" }, + { url = "https://files.pythonhosted.org/packages/8e/62/764ce66fa4147ae6d73071a3abf804ffe606f174618697c571acdf26a7c9/numpy-2.4.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:38efbc8de75c7a0fc1ac190162d892787f3f47b57cc291231aafee36b80982b7", size = 14704559, upload-time = "2026-05-18T23:35:42.14Z" }, + { url = "https://files.pythonhosted.org/packages/60/61/23f27c172f022e04025b7dc2367f4d63c1a398120607ec896228649a6f48/numpy-2.4.6-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:d581b735e177fdcdce6fed8e7e8880a3fb6ee4e3653a3ac6af01c6f4c03effc5", size = 5209716, upload-time = "2026-05-18T23:35:45.377Z" }, + { url = "https://files.pythonhosted.org/packages/03/71/21cf70dc6ea3e3acb95fc53a265b2fc248b981f0194ceb5b475271b8809d/numpy-2.4.6-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:0a041d3d761dc3c35cc56ce0351506a02bcbc25f7b169f652435141a17db9096", size = 6543947, upload-time = "2026-05-18T23:35:47.926Z" }, + { url = "https://files.pythonhosted.org/packages/d5/91/64288395ee1799bd2e0b04a305dce9666da90c961e1f3fe982a05ee1c036/numpy-2.4.6-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:40fdc1ae7125e518ea98e53e69a4ebc27e1fd50510c47b7ea130cf21e5e1d42b", size = 15685197, upload-time = "2026-05-18T23:35:50.863Z" }, + { url = "https://files.pythonhosted.org/packages/f3/eb/ebffaa97dc55502df69584a8f0dcf07f69a3e0b3e2323670a2722db9aa39/numpy-2.4.6-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a2c306dea656c12c68f51f4cea133cbe78ca7435eb28c735eac1d3ebe73be6e8", size = 16638245, upload-time = "2026-05-18T23:35:54.752Z" }, + { url = "https://files.pythonhosted.org/packages/b8/0b/54f9da33128d7e350fab89c7455902eeae70349ee52bddb448dc4a576f45/numpy-2.4.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:33111801a01c12a8a1e3721f0a9232f8cfc8ae2c6b7098167e6f623c6073f402", size = 17036587, upload-time = "2026-05-18T23:35:58.355Z" }, + { url = "https://files.pythonhosted.org/packages/b6/f0/fdebc1052db1cc37c64beb22072d67cd6d1c71adca1299f53dec2b5e20d3/numpy-2.4.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ae506e6902902557576a26ff33eda8695e7ecb3cb36c3b573a0765dee114ebdb", size = 18363226, upload-time = "2026-05-18T23:36:02.845Z" }, + { url = "https://files.pythonhosted.org/packages/aa/b4/298628d98c72b57e57f7165ae6a481a1deaf6f3c28262a6e4c739c275930/numpy-2.4.6-cp314-cp314-win32.whl", hash = "sha256:aaf159caa35993cb1f56fb9b8e4610d35758e7ca005412eb1daa856a78c9c4b1", size = 6010196, upload-time = "2026-05-18T23:36:05.92Z" }, + { url = "https://files.pythonhosted.org/packages/df/ac/46de6dda46478f7942f839e094970be2d4a861e005c4b3bf07c92e291a09/numpy-2.4.6-cp314-cp314-win_amd64.whl", hash = "sha256:b507f5c4c1d508876d1819b6bf9a49d365b96320b5d4993426b33a23ca4b8261", size = 12450334, upload-time = "2026-05-18T23:36:09.107Z" }, + { url = "https://files.pythonhosted.org/packages/78/92/b8b798ac784102c0da830d2257d59358e3d3d90d1e2b3f2575dad976c5cf/numpy-2.4.6-cp314-cp314-win_arm64.whl", hash = "sha256:6f41ae150c4e32db4f3310cdaf64b1593a03dbabe29eec77fc9b50fe64061df6", size = 10495678, upload-time = "2026-05-18T23:36:12.766Z" }, + { url = "https://files.pythonhosted.org/packages/30/34/ec28d1aa8115971537c01469ab2011ee96827930f0a124de1000cc2a7ed7/numpy-2.4.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ece3d2cfe132e7d51f44a832b303895e6f2d499c5e74dfbdb06ee246147a304a", size = 14823672, upload-time = "2026-05-18T23:36:16.473Z" }, + { url = "https://files.pythonhosted.org/packages/16/bd/f6d1fede4e54e8042a7ff97bb495510f3c220f94bcd9e8b228e87c92cc0d/numpy-2.4.6-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:e3e5193ef5a3dc73bceee50f7fdc2c90dbb76c42df8d8fae3d1067a583df579e", size = 5328731, upload-time = "2026-05-18T23:36:19.767Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f0/e105b9e2fd728a9910103884decd6951d9dd73896b914a98d9a231de02ee/numpy-2.4.6-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:17f9ade344e7d9b464a084d69bcf18fc691cb1db67c62ed80820bf4926d78f0e", size = 6649805, upload-time = "2026-05-18T23:36:22.266Z" }, + { url = "https://files.pythonhosted.org/packages/82/dd/1206a7ca6ab15e3f02069707ca96222e202af681bb73756da7527f3cb837/numpy-2.4.6-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9cd5ffd25db4e7ba6a375693b3fc0fc1791ec636c17db3720da19bde7180ec43", size = 15730496, upload-time = "2026-05-18T23:36:25.713Z" }, + { url = "https://files.pythonhosted.org/packages/51/e7/38d3ea825dcab85a591734decb2f6c67caa7c8367d374df1a1c3842f9b07/numpy-2.4.6-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d92c3819208a60205a12a245c91ad70cb0a85336659b19b834205573ac8456e", size = 16679616, upload-time = "2026-05-18T23:36:29.652Z" }, + { url = "https://files.pythonhosted.org/packages/93/b7/caabfdf53edf663e0b4eb74d7d405d83baef09eb5e83bcd32d601d72b93e/numpy-2.4.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e85b752a1e912b70eaad4fafbd4d1238007ab221de2009b9a2f5ae7461239895", size = 17085145, upload-time = "2026-05-18T23:36:33.449Z" }, + { url = "https://files.pythonhosted.org/packages/f9/45/68d7c33a6bcf3e5aa3bdbd57a367e6f615286dfd6482f97e8ffeb734306e/numpy-2.4.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:29cb7f67d10b479ff07c17d33e39f78c07f71c40ef30d63c153d340e96cd3fb4", size = 18403813, upload-time = "2026-05-18T23:36:37.369Z" }, + { url = "https://files.pythonhosted.org/packages/9c/50/0753655aa844c99cd9e018aacf76f130f1bd81d881bb74bc0aef5d73a8ba/numpy-2.4.6-cp314-cp314t-win32.whl", hash = "sha256:260a5d70215b61ab4fadf5c7baacd64821842975eea312125ed3c39a6391b063", size = 6156982, upload-time = "2026-05-18T23:36:40.817Z" }, + { url = "https://files.pythonhosted.org/packages/b2/d4/7c67becf668f973cb490cec3e98dfd799d866f9c989a54d355672cfa0db6/numpy-2.4.6-cp314-cp314t-win_amd64.whl", hash = "sha256:81a1cca95ed5bb92aa8b10dd2cdc9a0d3853a50fad926c28b5d7e8ea54389627", size = 12638908, upload-time = "2026-05-18T23:36:43.996Z" }, + { url = "https://files.pythonhosted.org/packages/43/bb/e1c71a4295b1b1d1393d50dbb4f2a36283c6859d9d3892e84f00ec5a91d5/numpy-2.4.6-cp314-cp314t-win_arm64.whl", hash = "sha256:0c9136e14ed34a9e343a31c533d78a9813a69a3148332bce5e9821cb2f996e66", size = 10565867, upload-time = "2026-05-18T23:36:47.114Z" }, + { url = "https://files.pythonhosted.org/packages/de/12/b422cc84439adc0d00de605bf4a308890ae5c26f2c71fbd73e5d08fbb0dd/numpy-2.4.6-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:55cced7c52e981362f708ad635198e97a752dfba412cc03c23bbf3bd8d5cd662", size = 16847511, upload-time = "2026-05-18T23:36:50.673Z" }, + { url = "https://files.pythonhosted.org/packages/44/53/f481bef68011740f8849418d82db07230e825013f31f4eef5ba5b805316a/numpy-2.4.6-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d6da64deb6b8ed903e7560180a92f2d804ee1ba5eeb849ac2748b8c1aba1f6d7", size = 14889064, upload-time = "2026-05-18T23:36:53.879Z" }, + { url = "https://files.pythonhosted.org/packages/7f/57/42ed575c10ced8af951d426bc4e1f8aff16fd851db33f067036215a7f860/numpy-2.4.6-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:68a5124b13fa6cc2086764a20005d30bc0548146f7f5322f02fce212ca14317f", size = 5394157, upload-time = "2026-05-18T23:36:57.194Z" }, + { url = "https://files.pythonhosted.org/packages/6a/ef/f66cc724fcc36c1e364c67f51ae9146090b8b584f27d58b97fdae3edd737/numpy-2.4.6-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:948424b06129ce883307e8cff868c31396d8dc7630a59c61d70d98dbe70f222c", size = 6708728, upload-time = "2026-05-18T23:36:59.575Z" }, + { url = "https://files.pythonhosted.org/packages/1a/9c/c531f2293b91265d8b48e9b329f54fdd7ffae73cb4134ea10cca4237e9cc/numpy-2.4.6-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5dbbdb29840ca3d91ee0fece42fc29278886d908280bfec0a5846c6f901a3eb0", size = 15798374, upload-time = "2026-05-18T23:37:02.674Z" }, + { url = "https://files.pythonhosted.org/packages/1a/b0/413077f6b1153ed3cba361401c6783bbad6114804a000cc22eb71c13e190/numpy-2.4.6-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8ad03c0965fb3c692200e74d458ca28c1dbb4ce96f9a479a8aa041ad5fabca02", size = 16747286, upload-time = "2026-05-18T23:37:06.327Z" }, + { url = "https://files.pythonhosted.org/packages/15/ce/e5ec180bc41812edcd8daeb8639d205622c0e8c02259d8ab25a0201b3c2a/numpy-2.4.6-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:2803abfebfc990042cd494d8ce2d5f82e9d847af6d35ec486923aa19dbad5e73", size = 12504263, upload-time = "2026-05-18T23:37:09.715Z" }, +] + +[[package]] +name = "numpy" +version = "2.5.4" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.12'", +] +sdist = { url = "https://files.pythonhosted.org/packages/95/b0/c7453d0b6e2073c3264468b106ee1563750cecc910965e67357e3698c83e/numpy-2.5.4.tar.gz", hash = "sha256:9a94cf751c9ad8ebaa835bcd3d40dacf8534ad086b88c38029b65123c7999d2a", size = 20866315, upload-time = "2026-10-10T20:05:31.422Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/97/ba2074e92b7befea137e77ea8471e768bbd87c339b7e8c9f5a931949f977/numpy-2.5.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c6342f54c67093cae5c0227eb0eb772fdb79f2a2c37a6eb278b9909ee06aa356", size = 17001609, upload-time = "2026-10-10T20:02:40.843Z" }, + { url = "https://files.pythonhosted.org/packages/ff/a9/bac826765e971d8e16e2064e9ac7525fd69b40ac17c905033a7f5442023f/numpy-2.5.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b11e8fda06a7d69f15ebf542660b74466c2e51094800c1fb794f47ad4faeef17", size = 12015718, upload-time = "2026-10-10T20:02:43.45Z" }, + { url = "https://files.pythonhosted.org/packages/31/2f/5ea3570fcb8ccd0882bea99436a513b2c85dad8f774a2057849130a8fb99/numpy-2.5.4-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9cb18a327b49c5c337f972b03682f6a49855525faaf3c0d3e9c96cd0fd8880a8", size = 5451717, upload-time = "2026-10-10T20:02:46.169Z" }, + { url = "https://files.pythonhosted.org/packages/34/f2/b4fc1bafca03868220b5eaf729d2f21ebd7d7b151c0f9e144fe212bbca35/numpy-2.5.4-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:aec3fc4b32ff82421274f5d205c559c51c840c8df66a78efd7f3612dd005a26a", size = 6789926, upload-time = "2026-10-10T20:02:48.139Z" }, + { url = "https://files.pythonhosted.org/packages/dc/96/8319e2457ae4333c62c815c7006b869a4f60985c1e01024c2f8c6c040fe5/numpy-2.5.4-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fe4d21ab149f15e4e6043dfb0de87e6e5f34ac176cde83060e9802981fca2ac2", size = 15695312, upload-time = "2026-10-10T20:02:50.115Z" }, + { url = "https://files.pythonhosted.org/packages/43/a3/c799c62e19c337e6d3770b08e475887fb30ce8477d3c09efca6b2f0228a6/numpy-2.5.4-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fbde6962867ee75b48b0ee29b2b9372ec5d617799dbaf38e82dc0596f2f7738a", size = 16727283, upload-time = "2026-10-10T20:02:53.186Z" }, + { url = "https://files.pythonhosted.org/packages/39/6b/3604e53fb00314d0dc1b94ec9125a1484f649c0a17480b1f0f0c7a9d6250/numpy-2.5.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:381a7a3d2e65e64c0ec302795ab9dc12bb1e73f150904699c153716177eebdaf", size = 17047890, upload-time = "2026-10-10T20:02:56.038Z" }, + { url = "https://files.pythonhosted.org/packages/4a/7a/e8b58a5289a0d464c52885de47c35a935cdd70c03a4c3ab94a5126416dd0/numpy-2.5.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b89d0aaae2fe498c648f4c4795c084db535af5bd98ef942b2a3681fb74ce8645", size = 18485839, upload-time = "2026-10-10T20:02:59.018Z" }, + { url = "https://files.pythonhosted.org/packages/6f/c9/47094f597015009f310b8c900def59065ef1ff5a6fe7b51fc65ec58ec2c6/numpy-2.5.4-cp312-cp312-win32.whl", hash = "sha256:9968ab7e49b93ac6e1c3b2239732183152c9150f16308d30b66a372cffe3483c", size = 6138936, upload-time = "2026-10-10T20:03:01.626Z" }, + { url = "https://files.pythonhosted.org/packages/12/33/fefe62073dc8acfd0f2b9ed7c003af2f50aa61555e113e6db02b8f79f145/numpy-2.5.4-cp312-cp312-win_amd64.whl", hash = "sha256:a7b1b6353e36a7e50de2973a38d705c88ee93adcf120673cee7f45a4a3fa223a", size = 12573091, upload-time = "2026-10-10T20:03:04.349Z" }, + { url = "https://files.pythonhosted.org/packages/1a/07/161270b0c2eec56e4c905f6d6d22e1b836887b2cb189d3f5820aa588e9dd/numpy-2.5.4-cp312-cp312-win_arm64.whl", hash = "sha256:aa1cce2ff3f8d953de38b76bf44602caeb69f101430208f64a10067f7cb4b1d3", size = 10521630, upload-time = "2026-10-10T20:03:06.767Z" }, + { url = "https://files.pythonhosted.org/packages/67/14/1c3ee0118a8fce08565a5d8482631608426a33af10a01077fada5dc7c119/numpy-2.5.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2377da2dd3ba2c1200956acbab2a358c83b8e1f8531191672d1cd6ad83250d53", size = 16997729, upload-time = "2026-10-10T20:03:09.291Z" }, + { url = "https://files.pythonhosted.org/packages/83/8c/b0ea9477fb1f0d4484bbc5cba21678cc9969704d8d7f3f158d1db35f8e14/numpy-2.5.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7415db95818b39ec475a5eea54d9e3b6bc83e3912158e46da3438cdce399804d", size = 12009826, upload-time = "2026-10-10T20:03:11.946Z" }, + { url = "https://files.pythonhosted.org/packages/e2/84/6a3d75b3ba3dfe84ac0053450753d1e6d250a8bf80f66474cc46d1fb643f/numpy-2.5.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:6d6a71b9d9a97c03633aa12565ef2825ffa036cc1d99cfd50dacf0f128af4fe2", size = 5445803, upload-time = "2026-10-10T20:03:14.329Z" }, + { url = "https://files.pythonhosted.org/packages/61/18/bb993f267ca20b376e07092a16793a5b31ed3138751e9ba480011a14d742/numpy-2.5.4-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:d8200f16437b289a5bb927c6e184eccc3e8389bc0070fea4cd5b9e13c1757959", size = 6786220, upload-time = "2026-10-10T20:03:16.602Z" }, + { url = "https://files.pythonhosted.org/packages/db/b6/135bb0953b61dc21c6cafa14b424ae666944e4899cf140e00c2b322a1a45/numpy-2.5.4-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c2e71b04c6cad90026e544501bbe0ab9290fa8a4d845e7e8c0d124fb429c988", size = 15689178, upload-time = "2026-10-10T20:03:18.721Z" }, + { url = "https://files.pythonhosted.org/packages/da/24/3bd070f3269dc609d8f26b2643f62ef91bb415841c0b294805aaf7fe06da/numpy-2.5.4-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6ffa07666f8da0eef81d149934a626d0d95fbd6838432a33e66245423a9062c0", size = 16718044, upload-time = "2026-10-10T20:03:21.386Z" }, + { url = "https://files.pythonhosted.org/packages/c7/8e/9d15bd356b0a019c965312b1a3c6a727cac4cae5bc40045fbc12ce4cff9c/numpy-2.5.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2fa3328f784fc8277fc48026f6cad516f5c561c5d8e2e39b3c9e0c8f23223b34", size = 17048364, upload-time = "2026-10-10T20:03:24.468Z" }, + { url = "https://files.pythonhosted.org/packages/dc/fe/9d5b560db964f15871885f2250795d15945f8699e17ef90c0c2ff4c875b2/numpy-2.5.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b86966fbe4ad7de710422175572bcdc75fdedadfb54bc6fab7deabccddd7780b", size = 18474904, upload-time = "2026-10-10T20:03:27.895Z" }, + { url = "https://files.pythonhosted.org/packages/e9/98/d27552990f1bd611ef3e7466adadc78312ea2df63b83aad47fdc3d3ca8df/numpy-2.5.4-cp313-cp313-win32.whl", hash = "sha256:5258bc06526964be5face2fc6f756857a3f24f21ec3e72ca131337a75b165d6c", size = 6134537, upload-time = "2026-10-10T20:03:30.511Z" }, + { url = "https://files.pythonhosted.org/packages/90/8c/140a40398a66b4471211be1affdb6ed24c486d581bd28d07b7f2fcb69540/numpy-2.5.4-cp313-cp313-win_amd64.whl", hash = "sha256:8b4d2fd2d34e5f8c9235ee787de5631a37a28402b15cb80814df973d2be54129", size = 12566113, upload-time = "2026-10-10T20:03:32.612Z" }, + { url = "https://files.pythonhosted.org/packages/34/52/01d205e5e8ccb27b2b0b141e801f22b830198c979111b0fa44771438d9a9/numpy-2.5.4-cp313-cp313-win_arm64.whl", hash = "sha256:bc39ac66a7a9a3fbd6134fda43136b60ffde99c8f4501e64e0d2b24da137babf", size = 10519523, upload-time = "2026-10-10T20:03:35.163Z" }, + { url = "https://files.pythonhosted.org/packages/99/ba/005cb5edd580d2f84d7ca3206b92dc17d4388e56e6f87ffe8f2762f83139/numpy-2.5.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:c668b2f0d651605b58892644b0e302c7157f7159544227758c896982ef384b18", size = 17005499, upload-time = "2026-10-10T20:03:37.961Z" }, + { url = "https://files.pythonhosted.org/packages/f3/49/fee7587c33ee35f7977f9051d7f2023d4e7246d62710c80f20c2361ea232/numpy-2.5.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ffa6ce09a1c6a08e9667dd9c97aa0b14184e8d18f2a14b78b2a2328c9147f076", size = 12019666, upload-time = "2026-10-10T20:03:40.606Z" }, + { url = "https://files.pythonhosted.org/packages/d5/b2/c6ce165acffceb15a82c07b9cc77d391f86b3f379ba62911908ae5d34b91/numpy-2.5.4-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:956555e0603a4d38019ae6925711cb9dc43195c076a928accf7ea5d50bddfe53", size = 5455617, upload-time = "2026-10-10T20:03:43.138Z" }, + { url = "https://files.pythonhosted.org/packages/77/7f/dd85ce260a669a89be06842cf355d7353a33e6cfbc590fb8ebb947d88dc9/numpy-2.5.4-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:2c2c4afffdeb7920e445028dd71eb932cac3e704792e964bc2a232426d4f1255", size = 6791932, upload-time = "2026-10-10T20:03:44.874Z" }, + { url = "https://files.pythonhosted.org/packages/63/d6/34b0a2b0741386a63025a65a2c09caaaaaad6d0ca95b66cd65c30dd7fcb5/numpy-2.5.4-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4054173604cd8658796053f1f3bc0befb68ec1c0762c57fdad61e199256a8617", size = 15710899, upload-time = "2026-10-10T20:03:46.839Z" }, + { url = "https://files.pythonhosted.org/packages/16/d5/928078d2b28f26829b138b4a6c3980045022fb409f570657a224ae60ef4e/numpy-2.5.4-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d549420b8858885cea8838a727842249218b9c1da24dd517e25c9c7a948310a3", size = 16721710, upload-time = "2026-10-10T20:03:49.489Z" }, + { url = "https://files.pythonhosted.org/packages/f9/cf/673fd1b8f4cd78eb6320e87ec4c90ac19c095644259e3749853a405c70f4/numpy-2.5.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:823874a507a84af050493b622affde94b6f7c3a0dc22cb2801381bc03b871c00", size = 17066182, upload-time = "2026-10-10T20:03:52.25Z" }, + { url = "https://files.pythonhosted.org/packages/f3/92/a77b5061b1b3e2643928c37976d79ee173e1b171ed158b7a3c61056b41bc/numpy-2.5.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4e263278bfb5ee6409db8aedbc4cc32973b1b82bc1e8d3c668551d04d83a7e37", size = 18480315, upload-time = "2026-10-10T20:03:55.39Z" }, + { url = "https://files.pythonhosted.org/packages/bb/1d/1486ef3d3fb2279fd93c4c43c1bbbf1ca389a19816696684409f71babaab/numpy-2.5.4-cp314-cp314-win32.whl", hash = "sha256:cfd73180400042a7c532d30c5e287bdd03c59ff9ee1b4c0316af0539e29dfe23", size = 6185739, upload-time = "2026-10-10T20:03:58.186Z" }, + { url = "https://files.pythonhosted.org/packages/52/9a/e1e512ebc948d5b9dd33b08736760f0ebbed2848fd4eda1f553088a6dcee/numpy-2.5.4-cp314-cp314-win_amd64.whl", hash = "sha256:2ca144f15135b6212a5c47b1e2aeca6e412f102f95a2d5d88d8aec77eb255de3", size = 12703552, upload-time = "2026-10-10T20:04:00.28Z" }, + { url = "https://files.pythonhosted.org/packages/2c/05/de709a982d7bbcd688a3fad71f002e9ff80c2db39e03ee726609b610f1d1/numpy-2.5.4-cp314-cp314-win_arm64.whl", hash = "sha256:468397ba3c64427474706e5c9123fe266395496714dc684294eac75cd4930d1e", size = 10803901, upload-time = "2026-10-10T20:04:02.659Z" }, + { url = "https://files.pythonhosted.org/packages/13/34/083570ada3bb2a30fbe5d77c8c6fef9141144a15d33e6f793a67e9749ab8/numpy-2.5.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1ef3aa6d7e29bb13677323114280b05acc57607fa2300e66432d665d5418a162", size = 12138695, upload-time = "2026-10-10T20:04:05.012Z" }, + { url = "https://files.pythonhosted.org/packages/94/06/1f9c24db48eef0c2d1207e3b11fffb0478e39dfd8c1e1be7476936885eed/numpy-2.5.4-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:98b053943e5a0474ec0da309d2cb9d3f18ea57f8a2067c2ab7b5f763d1068380", size = 5574615, upload-time = "2026-10-10T20:04:07.316Z" }, + { url = "https://files.pythonhosted.org/packages/da/0f/593fba2e1560e949123bc7d2fc48b5893d56e58cd4bd5a273d2fbf60b220/numpy-2.5.4-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:b64a85f40e154983960a4167d4c1d57a50c7f109b3d3264a3a984154e90a8454", size = 6889383, upload-time = "2026-10-10T20:04:09.918Z" }, + { url = "https://files.pythonhosted.org/packages/eb/9f/b799dfdce4e05e80ed4bc815c71ff343a11533b2c0ffc221cae8538cda63/numpy-2.5.4-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a813ed7719bf45463c51779e6a98d0385fe905e48447526938a4b8337333d551", size = 15753763, upload-time = "2026-10-10T20:04:12.278Z" }, + { url = "https://files.pythonhosted.org/packages/34/88/16c5f12f86f5ad2817c4d103205131fc6c8acb3d1878af05a1a4f23ec859/numpy-2.5.4-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9b80cdf5cedba0e90d93fa5f9a333c4d65bd545cd669b71bb97ce2b703c9d73", size = 16757212, upload-time = "2026-10-10T20:04:14.799Z" }, + { url = "https://files.pythonhosted.org/packages/ff/4f/a1fe40e18a898e6a5089f4f0d891f0a493eb0574d5b34458f0fbe5aa3e5c/numpy-2.5.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2199ed071f460487c8db2c0e5c0b564494190edb4772fe80f9aad88b2604def5", size = 17116471, upload-time = "2026-10-10T20:04:17.58Z" }, + { url = "https://files.pythonhosted.org/packages/aa/46/e923a11c78e65c1722e7aaad817c06bd591324174b9d28ce5d31eee4d432/numpy-2.5.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:64f9c9878c1938476365e11ccfb6b770f3b9e5f045ccddc514235041e6959365", size = 18524063, upload-time = "2026-10-10T20:04:20.365Z" }, + { url = "https://files.pythonhosted.org/packages/5a/fa/84ab064514440c1f64a1b21088f2c82756defdd05e07c75ab233899565b2/numpy-2.5.4-cp314-cp314t-win32.whl", hash = "sha256:64d1c8ac28a4077cf987e0a71a7a0ef7e2df70722f07f0baa42dbb7eb6938647", size = 6340926, upload-time = "2026-10-10T20:04:22.865Z" }, + { url = "https://files.pythonhosted.org/packages/7e/7e/6cd886876f435b10685db9b9f7eeb70356f99e052116f4e5f11c5792c714/numpy-2.5.4-cp314-cp314t-win_amd64.whl", hash = "sha256:067374eb538c34c745436365cf7b0112595c1d326f21ce4ff340f61230239fbb", size = 12901584, upload-time = "2026-10-10T20:04:24.99Z" }, + { url = "https://files.pythonhosted.org/packages/38/1b/3c1684f6a06f7307f2335fca6e486cb162847fb97e91d65f8eb5cabad213/numpy-2.5.4-cp314-cp314t-win_arm64.whl", hash = "sha256:e94aef2c639da4a960ad0db8e06471208d8589974953d78b61d345b4eb99e394", size = 10891152, upload-time = "2026-10-10T20:04:27.52Z" }, + { url = "https://files.pythonhosted.org/packages/08/f4/3224deff3af2bef6bc0b175369698d8cb348f3d91d9bb0286cd5c9eae9e0/numpy-2.5.4-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:8dddfbee2e68d26d0d7d7d9cb247b1fd4409241cce32d815a11d97ec2cfde179", size = 17003231, upload-time = "2026-10-10T20:04:30.021Z" }, + { url = "https://files.pythonhosted.org/packages/be/75/fee0b8c6d94b44b2fdfae74f6a4ad5a138739589a8aebaec28ce4e713ed5/numpy-2.5.4-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:81e3420b27048b65eb14c3acf0c174a8cb0e023277716110347d2dcb26026dad", size = 12018300, upload-time = "2026-10-10T20:04:32.519Z" }, + { url = "https://files.pythonhosted.org/packages/47/c0/d0b335a499a04b65f532c3f034346ef390f81299060f928492dabc1e0272/numpy-2.5.4-cp315-cp315-macosx_14_0_arm64.whl", hash = "sha256:0b4724a19de67bea8cfc4970798efa78bcbbe2ac2613cfac16721a42d44de2a5", size = 5454250, upload-time = "2026-10-10T20:04:34.943Z" }, + { url = "https://files.pythonhosted.org/packages/5a/0e/461b3783c03d668052e6a21b01b673db6ffcb7831fd32d9aa5368c1cd426/numpy-2.5.4-cp315-cp315-macosx_14_0_x86_64.whl", hash = "sha256:2132418bf8dd124a427ca9e6a1daf9ee1a87185344c95119ceae868b99466da1", size = 6789644, upload-time = "2026-10-10T20:04:37.258Z" }, + { url = "https://files.pythonhosted.org/packages/b3/02/5dad269b02166965a7b4ca14adaddd75dbee0de42435bfecf561b84ba5a6/numpy-2.5.4-cp315-cp315-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:325518d4245b9e331387702aa58c2ce1dc4cdcbb41dfb4ccd5dcbc7e08db1266", size = 15704353, upload-time = "2026-10-10T20:04:39.616Z" }, + { url = "https://files.pythonhosted.org/packages/93/3a/01360c8036822ed9f7aa32189a77d1476567ec1e8e1383522389e4faac45/numpy-2.5.4-cp315-cp315-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:56733449d2544178beaa4545cee357370440cf056c197f9c7bfb19dbfdd0e86d", size = 16718648, upload-time = "2026-10-10T20:04:42.383Z" }, + { url = "https://files.pythonhosted.org/packages/7d/5c/b863a2c093c4d6f21a597fcaf24ead0835c09ab16a8312d5a5a8868af683/numpy-2.5.4-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:5ec3753760c1a6d8bb91200666e545c3a9728e6269dfb5d6ce02340996698aa3", size = 17059053, upload-time = "2026-10-10T20:04:44.976Z" }, + { url = "https://files.pythonhosted.org/packages/0a/60/ced4f57f9a1258a0af74f17cb0b0c2700b5c67cd6678823c803b263e4df3/numpy-2.5.4-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:b1185012870173de7ae33d370bd45b1cf5baee747ea4b97036b65f4e93016877", size = 18477406, upload-time = "2026-10-10T20:04:47.863Z" }, + { url = "https://files.pythonhosted.org/packages/f9/bd/0ef22dafaafcc7d4bb3ca26b8d2afbd55dedad8eaba99a8c864e1997456f/numpy-2.5.4-cp315-cp315-win32.whl", hash = "sha256:298eca75243f2cbbfdb460560b9fb2a1792a33cf2ab4286efd43d92e8d3df508", size = 6185133, upload-time = "2026-10-10T20:04:50.467Z" }, + { url = "https://files.pythonhosted.org/packages/50/bc/d2651b155ecc608a77e6f4d15495c11f14f19bb98f8bf0c5b0d38f86dda1/numpy-2.5.4-cp315-cp315-win_amd64.whl", hash = "sha256:332f3378fe077dd850e677ec01bdcc4f22368fb5d50ef10b2c79230b1bf5a592", size = 12703085, upload-time = "2026-10-10T20:04:52.63Z" }, + { url = "https://files.pythonhosted.org/packages/dc/d2/45e404f8abb26fb9eda12b94012936873e827b1be76f2ee7890be128312e/numpy-2.5.4-cp315-cp315-win_arm64.whl", hash = "sha256:d4cccbbc78717966f764cd3af4fb70276fa01fc7a2688af11c78901fa5c04f05", size = 10801451, upload-time = "2026-10-10T20:04:55.677Z" }, + { url = "https://files.pythonhosted.org/packages/c6/c3/2ae14e09cfdb67dc187a342e15308a21c15bf4d2071f8079e6aee5fe56dc/numpy-2.5.4-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:950ea81d57ef070665581b6e1b5f6a029306423cd1739c5b95fe78aa30db6b9d", size = 17097121, upload-time = "2026-10-10T20:04:58.403Z" }, + { url = "https://files.pythonhosted.org/packages/f5/cf/305ae624ef8a039414317224abe9ec9c2fe7ea3c2e1cf204d43ff6b2ffb9/numpy-2.5.4-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:c05ede731b03fb1b7591faca9389ade3267d2bddf1ad8882bb3f2cc5e101694f", size = 12135439, upload-time = "2026-10-10T20:05:01.65Z" }, + { url = "https://files.pythonhosted.org/packages/a9/a8/f75c63813aef95827bb2c0d13b12803016853056e8792c280058cdbfe783/numpy-2.5.4-cp315-cp315t-macosx_14_0_arm64.whl", hash = "sha256:5fbf7141bbfd63aea22f435c9062a032b9ea0082fe9845dad7f021d3f1234e71", size = 5571451, upload-time = "2026-10-10T20:05:04.135Z" }, + { url = "https://files.pythonhosted.org/packages/6f/0f/f17763f983868b5c49b4101ebd7e00760bd1769478a6bb6a8de6e085bbac/numpy-2.5.4-cp315-cp315t-macosx_14_0_x86_64.whl", hash = "sha256:3573cd22564692a5b899ec344e5d5b9cc4576f2985b96f22af3564ed54f2710f", size = 6883356, upload-time = "2026-10-10T20:05:06.249Z" }, + { url = "https://files.pythonhosted.org/packages/67/a7/8af04c5a79e047996cfa38854dcfbececdd0343a7c933a46fdd03ef6f5da/numpy-2.5.4-cp315-cp315t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6c109eac9cd439193678f69d70733c1108487546ca8eafc107b510ae10c1aecd", size = 15750991, upload-time = "2026-10-10T20:05:08.376Z" }, + { url = "https://files.pythonhosted.org/packages/57/7a/648254290d0c504faa8f2d07aa206660c728802c781a6f3fc68ab7cb5d71/numpy-2.5.4-cp315-cp315t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:80d6ef6e8620eb2c2b4c4caad50b5935d6db3cde2d51581b55dcc79e14016d1d", size = 16757675, upload-time = "2026-10-10T20:05:11.393Z" }, + { url = "https://files.pythonhosted.org/packages/b8/fe/4a8c3cdb0c70400cfe4c5bec42d3099a5673802a95064614b33e07b82aa1/numpy-2.5.4-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:77045a4b175bbf5316ec08003880804336c78f92281a1b72222b274ea85ec5ac", size = 17113846, upload-time = "2026-10-10T20:05:14.49Z" }, + { url = "https://files.pythonhosted.org/packages/1b/7e/619692bb67778702c0e9eb2d468568a7573f4e269386ea61aed01ee4e557/numpy-2.5.4-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:0f02a46e49cfb6c73bdb7aea1c0d3461dbae9aba613542b65f657cd3d17b9fab", size = 18522915, upload-time = "2026-10-10T20:05:17.33Z" }, + { url = "https://files.pythonhosted.org/packages/b7/b5/4da41c328788f575838f97a098fe8ca691ebc6f6fd73ad4a262ee40b184d/numpy-2.5.4-cp315-cp315t-win32.whl", hash = "sha256:ad62a416ddcf863bf44bba76fbf6b53366ab0692e294f51cae4b5fbe0d246788", size = 6335804, upload-time = "2026-10-10T20:05:19.921Z" }, + { url = "https://files.pythonhosted.org/packages/98/94/6482ddfa3d312490cb9358f375bf2ad56427dbea8769187158e94d653753/numpy-2.5.4-cp315-cp315t-win_amd64.whl", hash = "sha256:38f47be9f74ab870d2633b5456ae519c43758a8d1fd05342f0ce4ecc034396ee", size = 12890095, upload-time = "2026-10-10T20:05:21.875Z" }, + { url = "https://files.pythonhosted.org/packages/48/7f/c2d1b436b6e7cfebac140c2579a298344b85f2991a2ce5c3615cefb29400/numpy-2.5.4-cp315-cp315t-win_arm64.whl", hash = "sha256:7a14a461d9340f1b46b8648578aed9cdb8b3b018a8fac6c1dde2c9192a01a87f", size = 10883718, upload-time = "2026-10-10T20:05:28.547Z" }, +] + +[[package]] +name = "packaging" +version = "26.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/fa/3944b40b07da9ce895c0e6303a5ab7d53da063554f534556b134a54d6093/packaging-26.3.tar.gz", hash = "sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79", size = 313412, upload-time = "2026-08-04T18:15:28.737Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl", hash = "sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c", size = 129956, upload-time = "2026-08-04T18:15:27.159Z" }, +] + +[[package]] +name = "pluggy" +version = "1.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bf/db/7fc19e6f2dc92a966727031389fc2e08b558f0f25eb7403c1119ad4713cd/pluggy-1.7.0.tar.gz", hash = "sha256:d1eaa46ebb595891b860ab086b4d09c8588af65ebd4361b8e8f4bb8920b90ba8", size = 123304, upload-time = "2026-10-15T09:50:58.343Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/9e/2b38731e0fc536806f16490e1a12d7f0dc2a1235aa8cc07bcc75416a7daa/pluggy-1.7.0-py3-none-any.whl", hash = "sha256:7dd7b0d8832ba3cb632c306926ded123429211b83641b35dc5c41ad2d34f9bec", size = 27082, upload-time = "2026-10-15T09:50:56.808Z" }, +] + +[[package]] +name = "pyaml" +version = "26.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/15/6a/acfdf17de0d6947b419da8696e02b781b18de2cf49e0472298b50e1f0711/pyaml-26.7.0.tar.gz", hash = "sha256:11cda3a796efc6dbce0d56836be56cfd26289dad07bcd78e9904086729929c93", size = 30669, upload-time = "2026-07-04T00:34:38.532Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a6/26/3f05f9e3692853dff663913d5d62fb8df3f5640c8d70b06588c0b51ed953/pyaml-26.7.0-py3-none-any.whl", hash = "sha256:cfa382780c43ae660669b87d394d550a41856ef175f5749f51f753e12d7077ac", size = 27226, upload-time = "2026-07-04T00:34:37.198Z" }, +] + +[[package]] +name = "pygments" +version = "2.21.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/49/2e/ced460408999b33da6b31b0021b0f37d329e202d4169aeb164493778f25b/pygments-2.21.0.tar.gz", hash = "sha256:610ca751c9bc2492b38eb9a38a7fbc93edbbb2d7182edaf34e66ae493dee5c8c", size = 5005329, upload-time = "2026-08-17T08:02:48.824Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl", hash = "sha256:2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9", size = 1250147, upload-time = "2026-08-17T08:02:44.912Z" }, +] + +[[package]] +name = "pytest" +version = "9.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/79/42/bb4641652e58dedeac2ec51abc1f8cae4fee4ec63899a0999016229a0f2a/pytest-9.2.0.tar.gz", hash = "sha256:97c4f3b1f3c7414aa36465e09b8220f1d03627993bd51b1282e193753c80557b", size = 1797555, upload-time = "2026-10-27T21:30:20.728Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/39/1f5d8c8877a0fa327db959c19341d4be61660de1ab6b7391f9eb805bcd67/pytest-9.2.0-py3-none-any.whl", hash = "sha256:07acdcf88ec174f907dc01af70bf52d49b014bbab03faeeade31c96b18c2e588", size = 411776, upload-time = "2026-10-27T21:30:19.131Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227, upload-time = "2025-09-25T21:31:46.04Z" }, + { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019, upload-time = "2025-09-25T21:31:47.706Z" }, + { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646, upload-time = "2025-09-25T21:31:49.21Z" }, + { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793, upload-time = "2025-09-25T21:31:50.735Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293, upload-time = "2025-09-25T21:31:51.828Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872, upload-time = "2025-09-25T21:31:53.282Z" }, + { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828, upload-time = "2025-09-25T21:31:54.807Z" }, + { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415, upload-time = "2025-09-25T21:31:55.885Z" }, + { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561, upload-time = "2025-09-25T21:31:57.406Z" }, + { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, + { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, + { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, + { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, + { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, + { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, + { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, + { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, +] + +[[package]] +name = "ruff" +version = "0.17.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/59/73/81f140c4edd9cc323de5478e6bbd3bbcfae9a82692df1a258de8cec6a6d2/ruff-0.17.3.tar.gz", hash = "sha256:a57049c8addb3662073859bb55a7ad35aa54f8a7c9ed268911d1333c5aadaaa9", size = 5339444, upload-time = "2026-10-27T00:34:05.914Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/8c/083365310c4e79c842f25bf5a842facbd9b0c0ec336f96dffa5074fe723d/ruff-0.17.3-py3-none-linux_armv6l.whl", hash = "sha256:ab86b84cd9d05e56d329742c0cabdcbe2d1d56c98f4a04aab9b5b66196febfb4", size = 10216522, upload-time = "2026-10-27T00:33:29.822Z" }, + { url = "https://files.pythonhosted.org/packages/72/26/4b2edf31cfebe9605d8f6ed8f1d6f376d3a53d4c9a123e62661c64c440f0/ruff-0.17.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e407b4a6852853a9a2cdce96963e94ad9775578bb44e7561a0f2829f3cc04b11", size = 10217786, upload-time = "2026-10-27T00:33:33.949Z" }, + { url = "https://files.pythonhosted.org/packages/a2/7e/537aba4b7f54397a374d2f6a6fc93e9c8015e18553f31a4a7b7dbced48b5/ruff-0.17.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b75cc113b3aca388933d8296b667b1ac401a80317ea3074c9b0a66541199da29", size = 9440362, upload-time = "2026-10-27T00:33:35.784Z" }, + { url = "https://files.pythonhosted.org/packages/3d/66/283e39734f66c8a5ebaa93c22eb7b7515779a0b1d5a5c0ad20e05c0edb41/ruff-0.17.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab5fa7ed5ce18554ea69d850ad162cbaa0c85fc47c08d83a569f806681c9a6ad", size = 10094281, upload-time = "2026-10-27T00:33:38.216Z" }, + { url = "https://files.pythonhosted.org/packages/21/4c/1ffc768497bd025a32c72152771e40c0b99bddc5cc6e4f50c7949a395346/ruff-0.17.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c673c170e27834d1262e3a9c1e97bdc9b9c3b180c63d89173ce69747232474c1", size = 10022543, upload-time = "2026-10-27T00:33:40.181Z" }, + { url = "https://files.pythonhosted.org/packages/73/c3/f90db547301080fcb82c92abf914c8bd57b89911d9b65a6c4cc6b52d0635/ruff-0.17.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a754c0341bc9ca151b7b335988b3263921c08859f84ca219b70cee825571b6f", size = 10683921, upload-time = "2026-10-27T00:33:42.182Z" }, + { url = "https://files.pythonhosted.org/packages/e5/98/92d4a8a26c6c96cf1a5b34dd59036d8a71e52d650aab065c58867e964e63/ruff-0.17.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4590b9d86c0b1543ebb09094254e191cd43fe8edaf330baa035aab03da251532", size = 11373408, upload-time = "2026-10-27T00:33:44.19Z" }, + { url = "https://files.pythonhosted.org/packages/43/02/1f24d2e3064c9753926deeb901afa57777b37ee46799b09ddd7aee6e5145/ruff-0.17.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bbde18beccd98c29a227c63c99022e3443b99258e08326df6425dfe0443705ef", size = 10977469, upload-time = "2026-10-27T00:33:46.179Z" }, + { url = "https://files.pythonhosted.org/packages/f0/20/fecedea2209f574ab92033b344e01a7f0c2dc76c6d6d19a14c9f8141173f/ruff-0.17.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fa4b0f931cdbcb8a52044f370a3eb429fb42eb88807b0e800fcaa98dd42b24e", size = 10577491, upload-time = "2026-10-27T00:33:48.233Z" }, + { url = "https://files.pythonhosted.org/packages/33/36/b93fdf0bc6f84f0cd487aadfb0354deb40013669ea35ac3d26855de1e959/ruff-0.17.3-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:39405f341deec934b4289634324ad695f72df2970f9121582872eaf5b722f0f5", size = 10608748, upload-time = "2026-10-27T00:33:50.284Z" }, + { url = "https://files.pythonhosted.org/packages/5d/b7/7d3f5f14145daead1efb0b9a8289ed1daa100f419d60774375951723ce00/ruff-0.17.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:68074094f55ca3d29ab19491f640282f7a84061c4c7977aa5094b968ca457e9a", size = 10075057, upload-time = "2026-10-27T00:33:52.074Z" }, + { url = "https://files.pythonhosted.org/packages/b0/ed/93ff7a5909ee56e2bd4b982deae9e0efb2724417874a90c9e41ad66c6dd7/ruff-0.17.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:27bb571ac78fef178fe5118d2827df95c2aae74a48fff2b15f6acd03af5ff5bb", size = 10022431, upload-time = "2026-10-27T00:33:54.061Z" }, + { url = "https://files.pythonhosted.org/packages/9b/07/a83b9eeec8c1c3c0e4eda15f06c3a91001bfd2687ea2f07b750719bf9712/ruff-0.17.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:029c37cbd3de48ca37aa12117bead2d065f15da17d66bf84e0d4274013705db2", size = 10394903, upload-time = "2026-10-27T00:33:56.158Z" }, + { url = "https://files.pythonhosted.org/packages/af/b2/05c39857c2526fcbebe46ad93a8dc97424656dfef14d3ef933abe1ffd331/ruff-0.17.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:692fdb46d0fd9c71e380947dc5fc72f2c3f881073bc1f739e4579376231affbe", size = 10799780, upload-time = "2026-10-27T00:33:58.204Z" }, + { url = "https://files.pythonhosted.org/packages/ec/d9/47171a16739eb7a353936b31c20cf54340531e68c9af7d72fd7a784e235d/ruff-0.17.3-py3-none-win32.whl", hash = "sha256:46539cb031b01fd29ae0a02142483c46640b233ee12bb1c1b690bffa1555d5ca", size = 9908481, upload-time = "2026-10-27T00:34:00.087Z" }, + { url = "https://files.pythonhosted.org/packages/d0/a0/f08c1631bfd81faa6a90eaf70c37c786c11bed2046302b56bb506c25e1a0/ruff-0.17.3-py3-none-win_amd64.whl", hash = "sha256:56b8ffb3f3b3cbccb8b76b71b38261b7ed982ef5d20f5b447b1b61a7f4949b24", size = 10341333, upload-time = "2026-10-27T00:34:02.099Z" }, + { url = "https://files.pythonhosted.org/packages/99/d5/4ad4ed31413c301430918e70d3d38ae6f097af0766cb9ab8c9d502b2a4d6/ruff-0.17.3-py3-none-win_arm64.whl", hash = "sha256:81fce74bcd6be0e9da7c67c7553fd0f1f12964a2052cd728ef917b937a5ca1d9", size = 9854332, upload-time = "2026-10-27T00:34:03.847Z" }, +] + +[[package]] +name = "scikit-learn" +version = "1.7.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11'", +] +dependencies = [ + { name = "joblib" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" } }, + { name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" } }, + { name = "threadpoolctl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/c2/a7855e41c9d285dfe86dc50b250978105dce513d6e459ea66a6aeb0e1e0c/scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda", size = 7193136, upload-time = "2025-09-09T08:21:29.075Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/3e/daed796fd69cce768b8788401cc464ea90b306fb196ae1ffed0b98182859/scikit_learn-1.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b33579c10a3081d076ab403df4a4190da4f4432d443521674637677dc91e61f", size = 9336221, upload-time = "2025-09-09T08:20:19.328Z" }, + { url = "https://files.pythonhosted.org/packages/1c/ce/af9d99533b24c55ff4e18d9b7b4d9919bbc6cd8f22fe7a7be01519a347d5/scikit_learn-1.7.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:36749fb62b3d961b1ce4fedf08fa57a1986cd409eff2d783bca5d4b9b5fce51c", size = 8653834, upload-time = "2025-09-09T08:20:22.073Z" }, + { url = "https://files.pythonhosted.org/packages/58/0e/8c2a03d518fb6bd0b6b0d4b114c63d5f1db01ff0f9925d8eb10960d01c01/scikit_learn-1.7.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7a58814265dfc52b3295b1900cfb5701589d30a8bb026c7540f1e9d3499d5ec8", size = 9660938, upload-time = "2025-09-09T08:20:24.327Z" }, + { url = "https://files.pythonhosted.org/packages/2b/75/4311605069b5d220e7cf5adabb38535bd96f0079313cdbb04b291479b22a/scikit_learn-1.7.2-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a847fea807e278f821a0406ca01e387f97653e284ecbd9750e3ee7c90347f18", size = 9477818, upload-time = "2025-09-09T08:20:26.845Z" }, + { url = "https://files.pythonhosted.org/packages/7f/9b/87961813c34adbca21a6b3f6b2bea344c43b30217a6d24cc437c6147f3e8/scikit_learn-1.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:ca250e6836d10e6f402436d6463d6c0e4d8e0234cfb6a9a47835bd392b852ce5", size = 8886969, upload-time = "2025-09-09T08:20:29.329Z" }, + { url = "https://files.pythonhosted.org/packages/43/83/564e141eef908a5863a54da8ca342a137f45a0bfb71d1d79704c9894c9d1/scikit_learn-1.7.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7509693451651cd7361d30ce4e86a1347493554f172b1c72a39300fa2aea79e", size = 9331967, upload-time = "2025-09-09T08:20:32.421Z" }, + { url = "https://files.pythonhosted.org/packages/18/d6/ba863a4171ac9d7314c4d3fc251f015704a2caeee41ced89f321c049ed83/scikit_learn-1.7.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:0486c8f827c2e7b64837c731c8feff72c0bd2b998067a8a9cbc10643c31f0fe1", size = 8648645, upload-time = "2025-09-09T08:20:34.436Z" }, + { url = "https://files.pythonhosted.org/packages/ef/0e/97dbca66347b8cf0ea8b529e6bb9367e337ba2e8be0ef5c1a545232abfde/scikit_learn-1.7.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:89877e19a80c7b11a2891a27c21c4894fb18e2c2e077815bcade10d34287b20d", size = 9715424, upload-time = "2025-09-09T08:20:36.776Z" }, + { url = "https://files.pythonhosted.org/packages/f7/32/1f3b22e3207e1d2c883a7e09abb956362e7d1bd2f14458c7de258a26ac15/scikit_learn-1.7.2-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8da8bf89d4d79aaec192d2bda62f9b56ae4e5b4ef93b6a56b5de4977e375c1f1", size = 9509234, upload-time = "2025-09-09T08:20:38.957Z" }, + { url = "https://files.pythonhosted.org/packages/9f/71/34ddbd21f1da67c7a768146968b4d0220ee6831e4bcbad3e03dd3eae88b6/scikit_learn-1.7.2-cp311-cp311-win_amd64.whl", hash = "sha256:9b7ed8d58725030568523e937c43e56bc01cadb478fc43c042a9aca1dacb3ba1", size = 8894244, upload-time = "2025-09-09T08:20:41.166Z" }, + { url = "https://files.pythonhosted.org/packages/a7/aa/3996e2196075689afb9fce0410ebdb4a09099d7964d061d7213700204409/scikit_learn-1.7.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8d91a97fa2b706943822398ab943cde71858a50245e31bc71dba62aab1d60a96", size = 9259818, upload-time = "2025-09-09T08:20:43.19Z" }, + { url = "https://files.pythonhosted.org/packages/43/5d/779320063e88af9c4a7c2cf463ff11c21ac9c8bd730c4a294b0000b666c9/scikit_learn-1.7.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:acbc0f5fd2edd3432a22c69bed78e837c70cf896cd7993d71d51ba6708507476", size = 8636997, upload-time = "2025-09-09T08:20:45.468Z" }, + { url = "https://files.pythonhosted.org/packages/5c/d0/0c577d9325b05594fdd33aa970bf53fb673f051a45496842caee13cfd7fe/scikit_learn-1.7.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e5bf3d930aee75a65478df91ac1225ff89cd28e9ac7bd1196853a9229b6adb0b", size = 9478381, upload-time = "2025-09-09T08:20:47.982Z" }, + { url = "https://files.pythonhosted.org/packages/82/70/8bf44b933837ba8494ca0fc9a9ab60f1c13b062ad0197f60a56e2fc4c43e/scikit_learn-1.7.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4d6e9deed1a47aca9fe2f267ab8e8fe82ee20b4526b2c0cd9e135cea10feb44", size = 9300296, upload-time = "2025-09-09T08:20:50.366Z" }, + { url = "https://files.pythonhosted.org/packages/c6/99/ed35197a158f1fdc2fe7c3680e9c70d0128f662e1fee4ed495f4b5e13db0/scikit_learn-1.7.2-cp312-cp312-win_amd64.whl", hash = "sha256:6088aa475f0785e01bcf8529f55280a3d7d298679f50c0bb70a2364a82d0b290", size = 8731256, upload-time = "2025-09-09T08:20:52.627Z" }, + { url = "https://files.pythonhosted.org/packages/ae/93/a3038cb0293037fd335f77f31fe053b89c72f17b1c8908c576c29d953e84/scikit_learn-1.7.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0b7dacaa05e5d76759fb071558a8b5130f4845166d88654a0f9bdf3eb57851b7", size = 9212382, upload-time = "2025-09-09T08:20:54.731Z" }, + { url = "https://files.pythonhosted.org/packages/40/dd/9a88879b0c1104259136146e4742026b52df8540c39fec21a6383f8292c7/scikit_learn-1.7.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:abebbd61ad9e1deed54cca45caea8ad5f79e1b93173dece40bb8e0c658dbe6fe", size = 8592042, upload-time = "2025-09-09T08:20:57.313Z" }, + { url = "https://files.pythonhosted.org/packages/46/af/c5e286471b7d10871b811b72ae794ac5fe2989c0a2df07f0ec723030f5f5/scikit_learn-1.7.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:502c18e39849c0ea1a5d681af1dbcf15f6cce601aebb657aabbfe84133c1907f", size = 9434180, upload-time = "2025-09-09T08:20:59.671Z" }, + { url = "https://files.pythonhosted.org/packages/f1/fd/df59faa53312d585023b2da27e866524ffb8faf87a68516c23896c718320/scikit_learn-1.7.2-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a4c328a71785382fe3fe676a9ecf2c86189249beff90bf85e22bdb7efaf9ae0", size = 9283660, upload-time = "2025-09-09T08:21:01.71Z" }, + { url = "https://files.pythonhosted.org/packages/a7/c7/03000262759d7b6f38c836ff9d512f438a70d8a8ddae68ee80de72dcfb63/scikit_learn-1.7.2-cp313-cp313-win_amd64.whl", hash = "sha256:63a9afd6f7b229aad94618c01c252ce9e6fa97918c5ca19c9a17a087d819440c", size = 8702057, upload-time = "2025-09-09T08:21:04.234Z" }, + { url = "https://files.pythonhosted.org/packages/55/87/ef5eb1f267084532c8e4aef98a28b6ffe7425acbfd64b5e2f2e066bc29b3/scikit_learn-1.7.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:9acb6c5e867447b4e1390930e3944a005e2cb115922e693c08a323421a6966e8", size = 9558731, upload-time = "2025-09-09T08:21:06.381Z" }, + { url = "https://files.pythonhosted.org/packages/93/f8/6c1e3fc14b10118068d7938878a9f3f4e6d7b74a8ddb1e5bed65159ccda8/scikit_learn-1.7.2-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:2a41e2a0ef45063e654152ec9d8bcfc39f7afce35b08902bfe290c2498a67a6a", size = 9038852, upload-time = "2025-09-09T08:21:08.628Z" }, + { url = "https://files.pythonhosted.org/packages/83/87/066cafc896ee540c34becf95d30375fe5cbe93c3b75a0ee9aa852cd60021/scikit_learn-1.7.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:98335fb98509b73385b3ab2bd0639b1f610541d3988ee675c670371d6a87aa7c", size = 9527094, upload-time = "2025-09-09T08:21:11.486Z" }, + { url = "https://files.pythonhosted.org/packages/9c/2b/4903e1ccafa1f6453b1ab78413938c8800633988c838aa0be386cbb33072/scikit_learn-1.7.2-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:191e5550980d45449126e23ed1d5e9e24b2c68329ee1f691a3987476e115e09c", size = 9367436, upload-time = "2025-09-09T08:21:13.602Z" }, + { url = "https://files.pythonhosted.org/packages/b5/aa/8444be3cfb10451617ff9d177b3c190288f4563e6c50ff02728be67ad094/scikit_learn-1.7.2-cp313-cp313t-win_amd64.whl", hash = "sha256:57dc4deb1d3762c75d685507fbd0bc17160144b2f2ba4ccea5dc285ab0d0e973", size = 9275749, upload-time = "2025-09-09T08:21:15.96Z" }, + { url = "https://files.pythonhosted.org/packages/d9/82/dee5acf66837852e8e68df6d8d3a6cb22d3df997b733b032f513d95205b7/scikit_learn-1.7.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fa8f63940e29c82d1e67a45d5297bdebbcb585f5a5a50c4914cc2e852ab77f33", size = 9208906, upload-time = "2025-09-09T08:21:18.557Z" }, + { url = "https://files.pythonhosted.org/packages/3c/30/9029e54e17b87cb7d50d51a5926429c683d5b4c1732f0507a6c3bed9bf65/scikit_learn-1.7.2-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:f95dc55b7902b91331fa4e5845dd5bde0580c9cd9612b1b2791b7e80c3d32615", size = 8627836, upload-time = "2025-09-09T08:21:20.695Z" }, + { url = "https://files.pythonhosted.org/packages/60/18/4a52c635c71b536879f4b971c2cedf32c35ee78f48367885ed8025d1f7ee/scikit_learn-1.7.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9656e4a53e54578ad10a434dc1f993330568cfee176dff07112b8785fb413106", size = 9426236, upload-time = "2025-09-09T08:21:22.645Z" }, + { url = "https://files.pythonhosted.org/packages/99/7e/290362f6ab582128c53445458a5befd471ed1ea37953d5bcf80604619250/scikit_learn-1.7.2-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96dc05a854add0e50d3f47a1ef21a10a595016da5b007c7d9cd9d0bffd1fcc61", size = 9312593, upload-time = "2025-09-09T08:21:24.65Z" }, + { url = "https://files.pythonhosted.org/packages/8e/87/24f541b6d62b1794939ae6422f8023703bbf6900378b2b34e0b4384dfefd/scikit_learn-1.7.2-cp314-cp314-win_amd64.whl", hash = "sha256:bb24510ed3f9f61476181e4db51ce801e2ba37541def12dc9333b946fc7a9cf8", size = 8820007, upload-time = "2025-09-09T08:21:26.713Z" }, +] + +[[package]] +name = "scikit-learn" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.12'", + "python_full_version == '3.11.*'", +] +dependencies = [ + { name = "joblib" }, + { name = "narwhals" }, + { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, + { name = "numpy", version = "2.5.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, + { name = "scipy", version = "1.18.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "threadpoolctl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fa/6f/37092bdb25f712817231799fc5674d8e704066a8a70c1d2d40517e18b4ab/scikit_learn-1.9.0.tar.gz", hash = "sha256:8833266989d3a5110178a9fae30783675460724d0e1efb13b14901d2c660c557", size = 7750767, upload-time = "2026-06-02T11:54:32.706Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f5/be/e844fd9586e66540a15b71924d17a6cbc1bb749e81ddd0a796bcdba4c055/scikit_learn-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9db6f4d34e68c8899e4cab27fdf8eafe6ed21f2ba52ceb25ea250cd237f8e47b", size = 8789686, upload-time = "2026-06-02T11:53:05.439Z" }, + { url = "https://files.pythonhosted.org/packages/42/e2/ff880f62677a17d035817d543cb0fc8727d01eccbee81c5f7fc733a9d856/scikit_learn-1.9.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:f401448645a3e7bc115aa3c094097865155b34bff1cba8101857d9104e99074c", size = 8256782, upload-time = "2026-06-02T11:53:08.904Z" }, + { url = "https://files.pythonhosted.org/packages/25/64/eb40435e1a508ab1b4e284ce43ae80f6a162e5be5e38ed5a6fab467a9ea4/scikit_learn-1.9.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fd3a8ef0c758555a3b23c03adaa858af32f7736785ded50ad5991f59c4ed03fa", size = 8992419, upload-time = "2026-06-02T11:53:11.551Z" }, + { url = "https://files.pythonhosted.org/packages/8d/da/4810a28e473185429e45a57eebcc91fc991b33d889cc0676063e671db03d/scikit_learn-1.9.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7e254636164090da847715a27f8e5478feb98c40a9e0ee90cbd277de9e5ceb8", size = 9281411, upload-time = "2026-06-02T11:53:15.063Z" }, + { url = "https://files.pythonhosted.org/packages/3b/67/be3d369f40d8178ba3bd86635d132e08cb5329b023e4669d9426d84bc007/scikit_learn-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:5dc1818c77575d149e25fce9ef82dd7b7263ae372f03494158668ad632a69759", size = 8272736, upload-time = "2026-06-02T11:53:18.108Z" }, + { url = "https://files.pythonhosted.org/packages/37/79/a733f02dc2118da7e77a134b34f39f40201a353311b011d20859d2db3556/scikit_learn-1.9.0-cp311-cp311-win_arm64.whl", hash = "sha256:366652351f092b219c248f1e72821e841960a63d8f358f1dcfd54dc1cbdbbc28", size = 7919564, upload-time = "2026-06-02T11:53:21.2Z" }, + { url = "https://files.pythonhosted.org/packages/ac/20/75f915ff375d6249e6550ac740fdbbd66159a068fd3af1400ff62036b07a/scikit_learn-1.9.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2bd41b0d201bc81575531b96b713d3eb5e5f50fb0b82101ff0f92294fdc236ac", size = 8741122, upload-time = "2026-06-02T11:53:24.08Z" }, + { url = "https://files.pythonhosted.org/packages/cc/d5/2b5148f2279196775e1db2aeb85d14b70ac80e7e32b3b28e7ebeafb0901d/scikit_learn-1.9.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:5be45aa4a42a68a533913a6ed736cf309de2226411c79ef8d609a5456f1939b1", size = 8261512, upload-time = "2026-06-02T11:53:27.183Z" }, + { url = "https://files.pythonhosted.org/packages/a0/ee/5adbc77656b71f9456a2f5a7a9fdb4bcf9207a6b962889f1c2f9323afa4e/scikit_learn-1.9.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5e50ed4da51974e86e940690e9a3d82e729b62b5a49f7c9bac534d515d39d86f", size = 8837603, upload-time = "2026-06-02T11:53:30.328Z" }, + { url = "https://files.pythonhosted.org/packages/6c/c2/63fdda36c56437eeb44aaf9493c8bcd62ce230ab1598924fc626ffbfa943/scikit_learn-1.9.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:056c92bb67ad4c28463c2f2653d9701449201e7e7a9e94e321be0f71c4fef2b8", size = 9132097, upload-time = "2026-06-02T11:53:33.456Z" }, + { url = "https://files.pythonhosted.org/packages/83/a4/c8e67227c680e2259c8864ae72ff48b06e16a6f51253a22167aa02a8aa4e/scikit_learn-1.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:4306775fad04cc4b472a1b15af1ae9cede1540fbfcc17fbce3767cd8dc7ae283", size = 8211173, upload-time = "2026-06-02T11:53:36.602Z" }, + { url = "https://files.pythonhosted.org/packages/cf/fd/3c0863792e98e67e9184aa4029288a175935eb65443afcd30d4f143450cf/scikit_learn-1.9.0-cp312-cp312-win_arm64.whl", hash = "sha256:26e22435f63bcdcf396b574273f29f13dd531f5ea035801f5be10ba1540a4e60", size = 7867451, upload-time = "2026-06-02T11:53:39.075Z" }, + { url = "https://files.pythonhosted.org/packages/3c/01/cf3310626b6d48d3e9be69a1223f9180360b5e6edb045f50fade723ce494/scikit_learn-1.9.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:80746d63bd4b6eaca54d36fe5feaf4d28bb38dc6f9470f81c7cad7c40155f119", size = 8705188, upload-time = "2026-06-02T11:53:41.964Z" }, + { url = "https://files.pythonhosted.org/packages/3e/04/5acd7ae280c5f93b6ac5ef6cdec14eef4c8d1cd91d85b3292989c94d96b1/scikit_learn-1.9.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:5b934c45c252844a91d69fda3a34cff5e7307e1db10d77cb10a3980312c74713", size = 8228299, upload-time = "2026-06-02T11:53:44.817Z" }, + { url = "https://files.pythonhosted.org/packages/0c/39/ffe829a5b8ecb40a518724a997794657fdc354ada5e8fe8e64d998c0bac9/scikit_learn-1.9.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:38c3dcb9a1ffb85505ec53d54c7b4aea0cff70050425a7760c2af661ac85df05", size = 8789690, upload-time = "2026-06-02T11:53:47.461Z" }, + { url = "https://files.pythonhosted.org/packages/1f/88/8dab5de10c638c083772a6be83a3d8106ced492f74a928c8693638e5bb50/scikit_learn-1.9.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da76d09304a4706db7cc1e3ebaa3b6b98a67365cc11d2996c4f1e58ba47df714", size = 9087723, upload-time = "2026-06-02T11:53:50.702Z" }, + { url = "https://files.pythonhosted.org/packages/20/3f/7917ca72464038f6240ec70c29f94862d08a34a74291ae4d4ec5eb8186a0/scikit_learn-1.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:5808d98f15c6bf6d9d96d2348c1997392a5888ce7097e664105f930c4bca1277", size = 8184330, upload-time = "2026-06-02T11:53:53.396Z" }, + { url = "https://files.pythonhosted.org/packages/78/c7/15739eb2f61fda3c54639e9942414e5a19ad8a8d1f5a3266afad7cb7df80/scikit_learn-1.9.0-cp313-cp313-win_arm64.whl", hash = "sha256:d77f54c017633791bc0225a43e2f8d03745fdcfe4880268fcc4df15f505dec2e", size = 7840653, upload-time = "2026-06-02T11:53:56.035Z" }, + { url = "https://files.pythonhosted.org/packages/f4/7d/c9a35cf59b20a86fec24d306f1547b78dec194b08d367ce2a3e4854169d9/scikit_learn-1.9.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:9656acd4e93f74e0b66c8a36c88830a99252dfa900044d36bc2212ae89a47162", size = 8713289, upload-time = "2026-06-02T11:53:58.788Z" }, + { url = "https://files.pythonhosted.org/packages/3c/a7/552a7821597c632b907f7bfe8f36f9f572777af8ef8a48353041cf8e091a/scikit_learn-1.9.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:24360002ae845e7866522b0a5bbf690802e7bc388cac8663502e78aa98598aa2", size = 8245141, upload-time = "2026-06-02T11:54:01.694Z" }, + { url = "https://files.pythonhosted.org/packages/7d/79/f4a0c4fe9711154cddabf913471153af79056382ddc612cfe5ee0ff4b72e/scikit_learn-1.9.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5162ad10a418c8a282dde04c9aa06965de3e9a65f33c1440c0ae69bb1a09d913", size = 8847671, upload-time = "2026-06-02T11:54:04.448Z" }, + { url = "https://files.pythonhosted.org/packages/f0/af/4d72d9e475ac83719160c662619e4bf7b95c19507cd582e7d0167a3c3dae/scikit_learn-1.9.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fea2cc5677ab49d6f5bade978c866da44957b712d92e9635e8b4f723013c3cb", size = 9118104, upload-time = "2026-06-02T11:54:07.205Z" }, + { url = "https://files.pythonhosted.org/packages/a2/d5/6a58eea2cb9abbb9b3f2bb8b2cfb3243d1152d69f442d256c7af71304769/scikit_learn-1.9.0-cp314-cp314-win_amd64.whl", hash = "sha256:64fa347efc1c839c487433e40c5144d38c336e8a2b59c81aa8660373945c2673", size = 8290674, upload-time = "2026-06-02T11:54:10.087Z" }, + { url = "https://files.pythonhosted.org/packages/65/5b/d4c879cf358f1187141cf90ced473f087183489090244f50c124a2ee478b/scikit_learn-1.9.0-cp314-cp314-win_arm64.whl", hash = "sha256:1b944b6db288f6b926e3650026ddafb988929de95d11fc2cc5fa117773c9ba42", size = 7978807, upload-time = "2026-06-02T11:54:12.769Z" }, + { url = "https://files.pythonhosted.org/packages/8a/43/bfae3121ec67ae09150d453c442c7c1cc166e9aefe056e6ab3b7728a5cfc/scikit_learn-1.9.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:4ccacf04ca5f4b492158a5f28afe0ace43f81b2571e4b9a66d34848b46128949", size = 9031941, upload-time = "2026-06-02T11:54:15.436Z" }, + { url = "https://files.pythonhosted.org/packages/75/b0/20a4546eb17f3b25d3c66df15810411c14ed5065bcfab50b53c96fb627b2/scikit_learn-1.9.0-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:ee1a8db2c18c08e34c7412d4b10be1cac214cd4ea7dc9715a6a327eb49a37c96", size = 8613528, upload-time = "2026-06-02T11:54:18.842Z" }, + { url = "https://files.pythonhosted.org/packages/18/3c/e440e039bb82cd19004edaaad00acbde0fb9b461083c3ecf37941c557312/scikit_learn-1.9.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:147e9329ef0e39f75d4cffa02b2aa48d827832684926cd5210d9a2cb5c57246b", size = 8855050, upload-time = "2026-06-02T11:54:21.699Z" }, + { url = "https://files.pythonhosted.org/packages/43/26/b341b8dab5998da6270a3a42c2152c578501354d36f944b5856757035ef8/scikit_learn-1.9.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bad8f8b9950321b54c965fdcbac6c6c55e79e16646b49977bcf3668d3870a1a", size = 9097190, upload-time = "2026-06-02T11:54:24.454Z" }, + { url = "https://files.pythonhosted.org/packages/fb/de/b650b4d69b84468cfa2e28a3ff7b8103743029e6446ce1a97fe060ef688c/scikit_learn-1.9.0-cp314-cp314t-win_amd64.whl", hash = "sha256:78fc56eafd4edb9575d2d8950d1dd152061abb573341a1cb7e099fc40f6c6666", size = 8963204, upload-time = "2026-06-02T11:54:27.428Z" }, + { url = "https://files.pythonhosted.org/packages/ee/f3/ff83d76d7418112e5a61326443cdda87be3545dd8d6599c95b2481a4419e/scikit_learn-1.9.0-cp314-cp314t-win_arm64.whl", hash = "sha256:051075bda8b7aab87b1906ab3d4740a1e1224a19d7b3781a576736edc94e76aa", size = 8222661, upload-time = "2026-06-02T11:54:30.192Z" }, +] + +[[package]] +name = "scipy" +version = "1.15.3" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11'", +] +dependencies = [ + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" } }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0f/37/6964b830433e654ec7485e45a00fc9a27cf868d622838f6b6d9c5ec0d532/scipy-1.15.3.tar.gz", hash = "sha256:eae3cf522bc7df64b42cad3925c876e1b0b6c35c1337c93e12c0f366f55b0eaf", size = 59419214, upload-time = "2025-05-08T16:13:05.955Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/2f/4966032c5f8cc7e6a60f1b2e0ad686293b9474b65246b0c642e3ef3badd0/scipy-1.15.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:a345928c86d535060c9c2b25e71e87c39ab2f22fc96e9636bd74d1dbf9de448c", size = 38702770, upload-time = "2025-05-08T16:04:20.849Z" }, + { url = "https://files.pythonhosted.org/packages/a0/6e/0c3bf90fae0e910c274db43304ebe25a6b391327f3f10b5dcc638c090795/scipy-1.15.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:ad3432cb0f9ed87477a8d97f03b763fd1d57709f1bbde3c9369b1dff5503b253", size = 30094511, upload-time = "2025-05-08T16:04:27.103Z" }, + { url = "https://files.pythonhosted.org/packages/ea/b1/4deb37252311c1acff7f101f6453f0440794f51b6eacb1aad4459a134081/scipy-1.15.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:aef683a9ae6eb00728a542b796f52a5477b78252edede72b8327a886ab63293f", size = 22368151, upload-time = "2025-05-08T16:04:31.731Z" }, + { url = "https://files.pythonhosted.org/packages/38/7d/f457626e3cd3c29b3a49ca115a304cebb8cc6f31b04678f03b216899d3c6/scipy-1.15.3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:1c832e1bd78dea67d5c16f786681b28dd695a8cb1fb90af2e27580d3d0967e92", size = 25121732, upload-time = "2025-05-08T16:04:36.596Z" }, + { url = "https://files.pythonhosted.org/packages/db/0a/92b1de4a7adc7a15dcf5bddc6e191f6f29ee663b30511ce20467ef9b82e4/scipy-1.15.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:263961f658ce2165bbd7b99fa5135195c3a12d9bef045345016b8b50c315cb82", size = 35547617, upload-time = "2025-05-08T16:04:43.546Z" }, + { url = "https://files.pythonhosted.org/packages/8e/6d/41991e503e51fc1134502694c5fa7a1671501a17ffa12716a4a9151af3df/scipy-1.15.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2abc762b0811e09a0d3258abee2d98e0c703eee49464ce0069590846f31d40", size = 37662964, upload-time = "2025-05-08T16:04:49.431Z" }, + { url = "https://files.pythonhosted.org/packages/25/e1/3df8f83cb15f3500478c889be8fb18700813b95e9e087328230b98d547ff/scipy-1.15.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ed7284b21a7a0c8f1b6e5977ac05396c0d008b89e05498c8b7e8f4a1423bba0e", size = 37238749, upload-time = "2025-05-08T16:04:55.215Z" }, + { url = "https://files.pythonhosted.org/packages/93/3e/b3257cf446f2a3533ed7809757039016b74cd6f38271de91682aa844cfc5/scipy-1.15.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5380741e53df2c566f4d234b100a484b420af85deb39ea35a1cc1be84ff53a5c", size = 40022383, upload-time = "2025-05-08T16:05:01.914Z" }, + { url = "https://files.pythonhosted.org/packages/d1/84/55bc4881973d3f79b479a5a2e2df61c8c9a04fcb986a213ac9c02cfb659b/scipy-1.15.3-cp310-cp310-win_amd64.whl", hash = "sha256:9d61e97b186a57350f6d6fd72640f9e99d5a4a2b8fbf4b9ee9a841eab327dc13", size = 41259201, upload-time = "2025-05-08T16:05:08.166Z" }, + { url = "https://files.pythonhosted.org/packages/96/ab/5cc9f80f28f6a7dff646c5756e559823614a42b1939d86dd0ed550470210/scipy-1.15.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:993439ce220d25e3696d1b23b233dd010169b62f6456488567e830654ee37a6b", size = 38714255, upload-time = "2025-05-08T16:05:14.596Z" }, + { url = "https://files.pythonhosted.org/packages/4a/4a/66ba30abe5ad1a3ad15bfb0b59d22174012e8056ff448cb1644deccbfed2/scipy-1.15.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:34716e281f181a02341ddeaad584205bd2fd3c242063bd3423d61ac259ca7eba", size = 30111035, upload-time = "2025-05-08T16:05:20.152Z" }, + { url = "https://files.pythonhosted.org/packages/4b/fa/a7e5b95afd80d24313307f03624acc65801846fa75599034f8ceb9e2cbf6/scipy-1.15.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3b0334816afb8b91dab859281b1b9786934392aa3d527cd847e41bb6f45bee65", size = 22384499, upload-time = "2025-05-08T16:05:24.494Z" }, + { url = "https://files.pythonhosted.org/packages/17/99/f3aaddccf3588bb4aea70ba35328c204cadd89517a1612ecfda5b2dd9d7a/scipy-1.15.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:6db907c7368e3092e24919b5e31c76998b0ce1684d51a90943cb0ed1b4ffd6c1", size = 25152602, upload-time = "2025-05-08T16:05:29.313Z" }, + { url = "https://files.pythonhosted.org/packages/56/c5/1032cdb565f146109212153339f9cb8b993701e9fe56b1c97699eee12586/scipy-1.15.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:721d6b4ef5dc82ca8968c25b111e307083d7ca9091bc38163fb89243e85e3889", size = 35503415, upload-time = "2025-05-08T16:05:34.699Z" }, + { url = "https://files.pythonhosted.org/packages/bd/37/89f19c8c05505d0601ed5650156e50eb881ae3918786c8fd7262b4ee66d3/scipy-1.15.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39cb9c62e471b1bb3750066ecc3a3f3052b37751c7c3dfd0fd7e48900ed52982", size = 37652622, upload-time = "2025-05-08T16:05:40.762Z" }, + { url = "https://files.pythonhosted.org/packages/7e/31/be59513aa9695519b18e1851bb9e487de66f2d31f835201f1b42f5d4d475/scipy-1.15.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:795c46999bae845966368a3c013e0e00947932d68e235702b5c3f6ea799aa8c9", size = 37244796, upload-time = "2025-05-08T16:05:48.119Z" }, + { url = "https://files.pythonhosted.org/packages/10/c0/4f5f3eeccc235632aab79b27a74a9130c6c35df358129f7ac8b29f562ac7/scipy-1.15.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:18aaacb735ab38b38db42cb01f6b92a2d0d4b6aabefeb07f02849e47f8fb3594", size = 40047684, upload-time = "2025-05-08T16:05:54.22Z" }, + { url = "https://files.pythonhosted.org/packages/ab/a7/0ddaf514ce8a8714f6ed243a2b391b41dbb65251affe21ee3077ec45ea9a/scipy-1.15.3-cp311-cp311-win_amd64.whl", hash = "sha256:ae48a786a28412d744c62fd7816a4118ef97e5be0bee968ce8f0a2fba7acf3bb", size = 41246504, upload-time = "2025-05-08T16:06:00.437Z" }, + { url = "https://files.pythonhosted.org/packages/37/4b/683aa044c4162e10ed7a7ea30527f2cbd92e6999c10a8ed8edb253836e9c/scipy-1.15.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6ac6310fdbfb7aa6612408bd2f07295bcbd3fda00d2d702178434751fe48e019", size = 38766735, upload-time = "2025-05-08T16:06:06.471Z" }, + { url = "https://files.pythonhosted.org/packages/7b/7e/f30be3d03de07f25dc0ec926d1681fed5c732d759ac8f51079708c79e680/scipy-1.15.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:185cd3d6d05ca4b44a8f1595af87f9c372bb6acf9c808e99aa3e9aa03bd98cf6", size = 30173284, upload-time = "2025-05-08T16:06:11.686Z" }, + { url = "https://files.pythonhosted.org/packages/07/9c/0ddb0d0abdabe0d181c1793db51f02cd59e4901da6f9f7848e1f96759f0d/scipy-1.15.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:05dc6abcd105e1a29f95eada46d4a3f251743cfd7d3ae8ddb4088047f24ea477", size = 22446958, upload-time = "2025-05-08T16:06:15.97Z" }, + { url = "https://files.pythonhosted.org/packages/af/43/0bce905a965f36c58ff80d8bea33f1f9351b05fad4beaad4eae34699b7a1/scipy-1.15.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:06efcba926324df1696931a57a176c80848ccd67ce6ad020c810736bfd58eb1c", size = 25242454, upload-time = "2025-05-08T16:06:20.394Z" }, + { url = "https://files.pythonhosted.org/packages/56/30/a6f08f84ee5b7b28b4c597aca4cbe545535c39fe911845a96414700b64ba/scipy-1.15.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05045d8b9bfd807ee1b9f38761993297b10b245f012b11b13b91ba8945f7e45", size = 35210199, upload-time = "2025-05-08T16:06:26.159Z" }, + { url = "https://files.pythonhosted.org/packages/0b/1f/03f52c282437a168ee2c7c14a1a0d0781a9a4a8962d84ac05c06b4c5b555/scipy-1.15.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271e3713e645149ea5ea3e97b57fdab61ce61333f97cfae392c28ba786f9bb49", size = 37309455, upload-time = "2025-05-08T16:06:32.778Z" }, + { url = "https://files.pythonhosted.org/packages/89/b1/fbb53137f42c4bf630b1ffdfc2151a62d1d1b903b249f030d2b1c0280af8/scipy-1.15.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6cfd56fc1a8e53f6e89ba3a7a7251f7396412d655bca2aa5611c8ec9a6784a1e", size = 36885140, upload-time = "2025-05-08T16:06:39.249Z" }, + { url = "https://files.pythonhosted.org/packages/2e/2e/025e39e339f5090df1ff266d021892694dbb7e63568edcfe43f892fa381d/scipy-1.15.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ff17c0bb1cb32952c09217d8d1eed9b53d1463e5f1dd6052c7857f83127d539", size = 39710549, upload-time = "2025-05-08T16:06:45.729Z" }, + { url = "https://files.pythonhosted.org/packages/e6/eb/3bf6ea8ab7f1503dca3a10df2e4b9c3f6b3316df07f6c0ded94b281c7101/scipy-1.15.3-cp312-cp312-win_amd64.whl", hash = "sha256:52092bc0472cfd17df49ff17e70624345efece4e1a12b23783a1ac59a1b728ed", size = 40966184, upload-time = "2025-05-08T16:06:52.623Z" }, + { url = "https://files.pythonhosted.org/packages/73/18/ec27848c9baae6e0d6573eda6e01a602e5649ee72c27c3a8aad673ebecfd/scipy-1.15.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c620736bcc334782e24d173c0fdbb7590a0a436d2fdf39310a8902505008759", size = 38728256, upload-time = "2025-05-08T16:06:58.696Z" }, + { url = "https://files.pythonhosted.org/packages/74/cd/1aef2184948728b4b6e21267d53b3339762c285a46a274ebb7863c9e4742/scipy-1.15.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:7e11270a000969409d37ed399585ee530b9ef6aa99d50c019de4cb01e8e54e62", size = 30109540, upload-time = "2025-05-08T16:07:04.209Z" }, + { url = "https://files.pythonhosted.org/packages/5b/d8/59e452c0a255ec352bd0a833537a3bc1bfb679944c4938ab375b0a6b3a3e/scipy-1.15.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:8c9ed3ba2c8a2ce098163a9bdb26f891746d02136995df25227a20e71c396ebb", size = 22383115, upload-time = "2025-05-08T16:07:08.998Z" }, + { url = "https://files.pythonhosted.org/packages/08/f5/456f56bbbfccf696263b47095291040655e3cbaf05d063bdc7c7517f32ac/scipy-1.15.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:0bdd905264c0c9cfa74a4772cdb2070171790381a5c4d312c973382fc6eaf730", size = 25163884, upload-time = "2025-05-08T16:07:14.091Z" }, + { url = "https://files.pythonhosted.org/packages/a2/66/a9618b6a435a0f0c0b8a6d0a2efb32d4ec5a85f023c2b79d39512040355b/scipy-1.15.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79167bba085c31f38603e11a267d862957cbb3ce018d8b38f79ac043bc92d825", size = 35174018, upload-time = "2025-05-08T16:07:19.427Z" }, + { url = "https://files.pythonhosted.org/packages/b5/09/c5b6734a50ad4882432b6bb7c02baf757f5b2f256041da5df242e2d7e6b6/scipy-1.15.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9deabd6d547aee2c9a81dee6cc96c6d7e9a9b1953f74850c179f91fdc729cb7", size = 37269716, upload-time = "2025-05-08T16:07:25.712Z" }, + { url = "https://files.pythonhosted.org/packages/77/0a/eac00ff741f23bcabd352731ed9b8995a0a60ef57f5fd788d611d43d69a1/scipy-1.15.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dde4fc32993071ac0c7dd2d82569e544f0bdaff66269cb475e0f369adad13f11", size = 36872342, upload-time = "2025-05-08T16:07:31.468Z" }, + { url = "https://files.pythonhosted.org/packages/fe/54/4379be86dd74b6ad81551689107360d9a3e18f24d20767a2d5b9253a3f0a/scipy-1.15.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f77f853d584e72e874d87357ad70f44b437331507d1c311457bed8ed2b956126", size = 39670869, upload-time = "2025-05-08T16:07:38.002Z" }, + { url = "https://files.pythonhosted.org/packages/87/2e/892ad2862ba54f084ffe8cc4a22667eaf9c2bcec6d2bff1d15713c6c0703/scipy-1.15.3-cp313-cp313-win_amd64.whl", hash = "sha256:b90ab29d0c37ec9bf55424c064312930ca5f4bde15ee8619ee44e69319aab163", size = 40988851, upload-time = "2025-05-08T16:08:33.671Z" }, + { url = "https://files.pythonhosted.org/packages/1b/e9/7a879c137f7e55b30d75d90ce3eb468197646bc7b443ac036ae3fe109055/scipy-1.15.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3ac07623267feb3ae308487c260ac684b32ea35fd81e12845039952f558047b8", size = 38863011, upload-time = "2025-05-08T16:07:44.039Z" }, + { url = "https://files.pythonhosted.org/packages/51/d1/226a806bbd69f62ce5ef5f3ffadc35286e9fbc802f606a07eb83bf2359de/scipy-1.15.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:6487aa99c2a3d509a5227d9a5e889ff05830a06b2ce08ec30df6d79db5fcd5c5", size = 30266407, upload-time = "2025-05-08T16:07:49.891Z" }, + { url = "https://files.pythonhosted.org/packages/e5/9b/f32d1d6093ab9eeabbd839b0f7619c62e46cc4b7b6dbf05b6e615bbd4400/scipy-1.15.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:50f9e62461c95d933d5c5ef4a1f2ebf9a2b4e83b0db374cb3f1de104d935922e", size = 22540030, upload-time = "2025-05-08T16:07:54.121Z" }, + { url = "https://files.pythonhosted.org/packages/e7/29/c278f699b095c1a884f29fda126340fcc201461ee8bfea5c8bdb1c7c958b/scipy-1.15.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:14ed70039d182f411ffc74789a16df3835e05dc469b898233a245cdfd7f162cb", size = 25218709, upload-time = "2025-05-08T16:07:58.506Z" }, + { url = "https://files.pythonhosted.org/packages/24/18/9e5374b617aba742a990581373cd6b68a2945d65cc588482749ef2e64467/scipy-1.15.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a769105537aa07a69468a0eefcd121be52006db61cdd8cac8a0e68980bbb723", size = 34809045, upload-time = "2025-05-08T16:08:03.929Z" }, + { url = "https://files.pythonhosted.org/packages/e1/fe/9c4361e7ba2927074360856db6135ef4904d505e9b3afbbcb073c4008328/scipy-1.15.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db984639887e3dffb3928d118145ffe40eff2fa40cb241a306ec57c219ebbbb", size = 36703062, upload-time = "2025-05-08T16:08:09.558Z" }, + { url = "https://files.pythonhosted.org/packages/b7/8e/038ccfe29d272b30086b25a4960f757f97122cb2ec42e62b460d02fe98e9/scipy-1.15.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:40e54d5c7e7ebf1aa596c374c49fa3135f04648a0caabcb66c52884b943f02b4", size = 36393132, upload-time = "2025-05-08T16:08:15.34Z" }, + { url = "https://files.pythonhosted.org/packages/10/7e/5c12285452970be5bdbe8352c619250b97ebf7917d7a9a9e96b8a8140f17/scipy-1.15.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5e721fed53187e71d0ccf382b6bf977644c533e506c4d33c3fb24de89f5c3ed5", size = 38979503, upload-time = "2025-05-08T16:08:21.513Z" }, + { url = "https://files.pythonhosted.org/packages/81/06/0a5e5349474e1cbc5757975b21bd4fad0e72ebf138c5592f191646154e06/scipy-1.15.3-cp313-cp313t-win_amd64.whl", hash = "sha256:76ad1fb5f8752eabf0fa02e4cc0336b4e8f021e2d5f061ed37d6d264db35e3ca", size = 40308097, upload-time = "2025-05-08T16:08:27.627Z" }, +] + +[[package]] +name = "scipy" +version = "1.17.1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version == '3.11.*'", +] +dependencies = [ + { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" } }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7a/97/5a3609c4f8d58b039179648e62dd220f89864f56f7357f5d4f45c29eb2cc/scipy-1.17.1.tar.gz", hash = "sha256:95d8e012d8cb8816c226aef832200b1d45109ed4464303e997c5b13122b297c0", size = 30573822, upload-time = "2026-02-23T00:26:24.851Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/75/b4ce781849931fef6fd529afa6b63711d5a733065722d0c3e2724af9e40a/scipy-1.17.1-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:1f95b894f13729334fb990162e911c9e5dc1ab390c58aa6cbecb389c5b5e28ec", size = 31613675, upload-time = "2026-02-23T00:16:00.13Z" }, + { url = "https://files.pythonhosted.org/packages/f7/58/bccc2861b305abdd1b8663d6130c0b3d7cc22e8d86663edbc8401bfd40d4/scipy-1.17.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:e18f12c6b0bc5a592ed23d3f7b891f68fd7f8241d69b7883769eb5d5dfb52696", size = 28162057, upload-time = "2026-02-23T00:16:09.456Z" }, + { url = "https://files.pythonhosted.org/packages/6d/ee/18146b7757ed4976276b9c9819108adbc73c5aad636e5353e20746b73069/scipy-1.17.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:a3472cfbca0a54177d0faa68f697d8ba4c80bbdc19908c3465556d9f7efce9ee", size = 20334032, upload-time = "2026-02-23T00:16:17.358Z" }, + { url = "https://files.pythonhosted.org/packages/ec/e6/cef1cf3557f0c54954198554a10016b6a03b2ec9e22a4e1df734936bd99c/scipy-1.17.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:766e0dc5a616d026a3a1cffa379af959671729083882f50307e18175797b3dfd", size = 22709533, upload-time = "2026-02-23T00:16:25.791Z" }, + { url = "https://files.pythonhosted.org/packages/4d/60/8804678875fc59362b0fb759ab3ecce1f09c10a735680318ac30da8cd76b/scipy-1.17.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:744b2bf3640d907b79f3fd7874efe432d1cf171ee721243e350f55234b4cec4c", size = 33062057, upload-time = "2026-02-23T00:16:36.931Z" }, + { url = "https://files.pythonhosted.org/packages/09/7d/af933f0f6e0767995b4e2d705a0665e454d1c19402aa7e895de3951ebb04/scipy-1.17.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43af8d1f3bea642559019edfe64e9b11192a8978efbd1539d7bc2aaa23d92de4", size = 35349300, upload-time = "2026-02-23T00:16:49.108Z" }, + { url = "https://files.pythonhosted.org/packages/b4/3d/7ccbbdcbb54c8fdc20d3b6930137c782a163fa626f0aef920349873421ba/scipy-1.17.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd96a1898c0a47be4520327e01f874acfd61fb48a9420f8aa9f6483412ffa444", size = 35127333, upload-time = "2026-02-23T00:17:01.293Z" }, + { url = "https://files.pythonhosted.org/packages/e8/19/f926cb11c42b15ba08e3a71e376d816ac08614f769b4f47e06c3580c836a/scipy-1.17.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4eb6c25dd62ee8d5edf68a8e1c171dd71c292fdae95d8aeb3dd7d7de4c364082", size = 37741314, upload-time = "2026-02-23T00:17:12.576Z" }, + { url = "https://files.pythonhosted.org/packages/95/da/0d1df507cf574b3f224ccc3d45244c9a1d732c81dcb26b1e8a766ae271a8/scipy-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:d30e57c72013c2a4fe441c2fcb8e77b14e152ad48b5464858e07e2ad9fbfceff", size = 36607512, upload-time = "2026-02-23T00:17:23.424Z" }, + { url = "https://files.pythonhosted.org/packages/68/7f/bdd79ceaad24b671543ffe0ef61ed8e659440eb683b66f033454dcee90eb/scipy-1.17.1-cp311-cp311-win_arm64.whl", hash = "sha256:9ecb4efb1cd6e8c4afea0daa91a87fbddbce1b99d2895d151596716c0b2e859d", size = 24599248, upload-time = "2026-02-23T00:17:34.561Z" }, + { url = "https://files.pythonhosted.org/packages/35/48/b992b488d6f299dbe3f11a20b24d3dda3d46f1a635ede1c46b5b17a7b163/scipy-1.17.1-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:35c3a56d2ef83efc372eaec584314bd0ef2e2f0d2adb21c55e6ad5b344c0dcb8", size = 31610954, upload-time = "2026-02-23T00:17:49.855Z" }, + { url = "https://files.pythonhosted.org/packages/b2/02/cf107b01494c19dc100f1d0b7ac3cc08666e96ba2d64db7626066cee895e/scipy-1.17.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:fcb310ddb270a06114bb64bbe53c94926b943f5b7f0842194d585c65eb4edd76", size = 28172662, upload-time = "2026-02-23T00:18:01.64Z" }, + { url = "https://files.pythonhosted.org/packages/cf/a9/599c28631bad314d219cf9ffd40e985b24d603fc8a2f4ccc5ae8419a535b/scipy-1.17.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:cc90d2e9c7e5c7f1a482c9875007c095c3194b1cfedca3c2f3291cdc2bc7c086", size = 20344366, upload-time = "2026-02-23T00:18:12.015Z" }, + { url = "https://files.pythonhosted.org/packages/35/f5/906eda513271c8deb5af284e5ef0206d17a96239af79f9fa0aebfe0e36b4/scipy-1.17.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:c80be5ede8f3f8eded4eff73cc99a25c388ce98e555b17d31da05287015ffa5b", size = 22704017, upload-time = "2026-02-23T00:18:21.502Z" }, + { url = "https://files.pythonhosted.org/packages/da/34/16f10e3042d2f1d6b66e0428308ab52224b6a23049cb2f5c1756f713815f/scipy-1.17.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e19ebea31758fac5893a2ac360fedd00116cbb7628e650842a6691ba7ca28a21", size = 32927842, upload-time = "2026-02-23T00:18:35.367Z" }, + { url = "https://files.pythonhosted.org/packages/01/8e/1e35281b8ab6d5d72ebe9911edcdffa3f36b04ed9d51dec6dd140396e220/scipy-1.17.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:02ae3b274fde71c5e92ac4d54bc06c42d80e399fec704383dcd99b301df37458", size = 35235890, upload-time = "2026-02-23T00:18:49.188Z" }, + { url = "https://files.pythonhosted.org/packages/c5/5c/9d7f4c88bea6e0d5a4f1bc0506a53a00e9fcb198de372bfe4d3652cef482/scipy-1.17.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8a604bae87c6195d8b1045eddece0514d041604b14f2727bbc2b3020172045eb", size = 35003557, upload-time = "2026-02-23T00:18:54.74Z" }, + { url = "https://files.pythonhosted.org/packages/65/94/7698add8f276dbab7a9de9fb6b0e02fc13ee61d51c7c3f85ac28b65e1239/scipy-1.17.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f590cd684941912d10becc07325a3eeb77886fe981415660d9265c4c418d0bea", size = 37625856, upload-time = "2026-02-23T00:19:00.307Z" }, + { url = "https://files.pythonhosted.org/packages/a2/84/dc08d77fbf3d87d3ee27f6a0c6dcce1de5829a64f2eae85a0ecc1f0daa73/scipy-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:41b71f4a3a4cab9d366cd9065b288efc4d4f3c0b37a91a8e0947fb5bd7f31d87", size = 36549682, upload-time = "2026-02-23T00:19:07.67Z" }, + { url = "https://files.pythonhosted.org/packages/bc/98/fe9ae9ffb3b54b62559f52dedaebe204b408db8109a8c66fdd04869e6424/scipy-1.17.1-cp312-cp312-win_arm64.whl", hash = "sha256:f4115102802df98b2b0db3cce5cb9b92572633a1197c77b7553e5203f284a5b3", size = 24547340, upload-time = "2026-02-23T00:19:12.024Z" }, + { url = "https://files.pythonhosted.org/packages/76/27/07ee1b57b65e92645f219b37148a7e7928b82e2b5dbeccecb4dff7c64f0b/scipy-1.17.1-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:5e3c5c011904115f88a39308379c17f91546f77c1667cea98739fe0fccea804c", size = 31590199, upload-time = "2026-02-23T00:19:17.192Z" }, + { url = "https://files.pythonhosted.org/packages/ec/ae/db19f8ab842e9b724bf5dbb7db29302a91f1e55bc4d04b1025d6d605a2c5/scipy-1.17.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:6fac755ca3d2c3edcb22f479fceaa241704111414831ddd3bc6056e18516892f", size = 28154001, upload-time = "2026-02-23T00:19:22.241Z" }, + { url = "https://files.pythonhosted.org/packages/5b/58/3ce96251560107b381cbd6e8413c483bbb1228a6b919fa8652b0d4090e7f/scipy-1.17.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:7ff200bf9d24f2e4d5dc6ee8c3ac64d739d3a89e2326ba68aaf6c4a2b838fd7d", size = 20325719, upload-time = "2026-02-23T00:19:26.329Z" }, + { url = "https://files.pythonhosted.org/packages/b2/83/15087d945e0e4d48ce2377498abf5ad171ae013232ae31d06f336e64c999/scipy-1.17.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:4b400bdc6f79fa02a4d86640310dde87a21fba0c979efff5248908c6f15fad1b", size = 22683595, upload-time = "2026-02-23T00:19:30.304Z" }, + { url = "https://files.pythonhosted.org/packages/b4/e0/e58fbde4a1a594c8be8114eb4aac1a55bcd6587047efc18a61eb1f5c0d30/scipy-1.17.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2b64ca7d4aee0102a97f3ba22124052b4bd2152522355073580bf4845e2550b6", size = 32896429, upload-time = "2026-02-23T00:19:35.536Z" }, + { url = "https://files.pythonhosted.org/packages/f5/5f/f17563f28ff03c7b6799c50d01d5d856a1d55f2676f537ca8d28c7f627cd/scipy-1.17.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:581b2264fc0aa555f3f435a5944da7504ea3a065d7029ad60e7c3d1ae09c5464", size = 35203952, upload-time = "2026-02-23T00:19:42.259Z" }, + { url = "https://files.pythonhosted.org/packages/8d/a5/9afd17de24f657fdfe4df9a3f1ea049b39aef7c06000c13db1530d81ccca/scipy-1.17.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:beeda3d4ae615106d7094f7e7cef6218392e4465cc95d25f900bebabfded0950", size = 34979063, upload-time = "2026-02-23T00:19:47.547Z" }, + { url = "https://files.pythonhosted.org/packages/8b/13/88b1d2384b424bf7c924f2038c1c409f8d88bb2a8d49d097861dd64a57b2/scipy-1.17.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6609bc224e9568f65064cfa72edc0f24ee6655b47575954ec6339534b2798369", size = 37598449, upload-time = "2026-02-23T00:19:53.238Z" }, + { url = "https://files.pythonhosted.org/packages/35/e5/d6d0e51fc888f692a35134336866341c08655d92614f492c6860dc45bb2c/scipy-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:37425bc9175607b0268f493d79a292c39f9d001a357bebb6b88fdfaff13f6448", size = 36510943, upload-time = "2026-02-23T00:20:50.89Z" }, + { url = "https://files.pythonhosted.org/packages/2a/fd/3be73c564e2a01e690e19cc618811540ba5354c67c8680dce3281123fb79/scipy-1.17.1-cp313-cp313-win_arm64.whl", hash = "sha256:5cf36e801231b6a2059bf354720274b7558746f3b1a4efb43fcf557ccd484a87", size = 24545621, upload-time = "2026-02-23T00:20:55.871Z" }, + { url = "https://files.pythonhosted.org/packages/6f/6b/17787db8b8114933a66f9dcc479a8272e4b4da75fe03b0c282f7b0ade8cd/scipy-1.17.1-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:d59c30000a16d8edc7e64152e30220bfbd724c9bbb08368c054e24c651314f0a", size = 31936708, upload-time = "2026-02-23T00:19:58.694Z" }, + { url = "https://files.pythonhosted.org/packages/38/2e/524405c2b6392765ab1e2b722a41d5da33dc5c7b7278184a8ad29b6cb206/scipy-1.17.1-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:010f4333c96c9bb1a4516269e33cb5917b08ef2166d5556ca2fd9f082a9e6ea0", size = 28570135, upload-time = "2026-02-23T00:20:03.934Z" }, + { url = "https://files.pythonhosted.org/packages/fd/c3/5bd7199f4ea8556c0c8e39f04ccb014ac37d1468e6cfa6a95c6b3562b76e/scipy-1.17.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:2ceb2d3e01c5f1d83c4189737a42d9cb2fc38a6eeed225e7515eef71ad301dce", size = 20741977, upload-time = "2026-02-23T00:20:07.935Z" }, + { url = "https://files.pythonhosted.org/packages/d9/b8/8ccd9b766ad14c78386599708eb745f6b44f08400a5fd0ade7cf89b6fc93/scipy-1.17.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:844e165636711ef41f80b4103ed234181646b98a53c8f05da12ca5ca289134f6", size = 23029601, upload-time = "2026-02-23T00:20:12.161Z" }, + { url = "https://files.pythonhosted.org/packages/6d/a0/3cb6f4d2fb3e17428ad2880333cac878909ad1a89f678527b5328b93c1d4/scipy-1.17.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:158dd96d2207e21c966063e1635b1063cd7787b627b6f07305315dd73d9c679e", size = 33019667, upload-time = "2026-02-23T00:20:17.208Z" }, + { url = "https://files.pythonhosted.org/packages/f3/c3/2d834a5ac7bf3a0c806ad1508efc02dda3c8c61472a56132d7894c312dea/scipy-1.17.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:74cbb80d93260fe2ffa334efa24cb8f2f0f622a9b9febf8b483c0b865bfb3475", size = 35264159, upload-time = "2026-02-23T00:20:23.087Z" }, + { url = "https://files.pythonhosted.org/packages/4d/77/d3ed4becfdbd217c52062fafe35a72388d1bd82c2d0ba5ca19d6fcc93e11/scipy-1.17.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:dbc12c9f3d185f5c737d801da555fb74b3dcfa1a50b66a1a93e09190f41fab50", size = 35102771, upload-time = "2026-02-23T00:20:28.636Z" }, + { url = "https://files.pythonhosted.org/packages/bd/12/d19da97efde68ca1ee5538bb261d5d2c062f0c055575128f11a2730e3ac1/scipy-1.17.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:94055a11dfebe37c656e70317e1996dc197e1a15bbcc351bcdd4610e128fe1ca", size = 37665910, upload-time = "2026-02-23T00:20:34.743Z" }, + { url = "https://files.pythonhosted.org/packages/06/1c/1172a88d507a4baaf72c5a09bb6c018fe2ae0ab622e5830b703a46cc9e44/scipy-1.17.1-cp313-cp313t-win_amd64.whl", hash = "sha256:e30bdeaa5deed6bc27b4cc490823cd0347d7dae09119b8803ae576ea0ce52e4c", size = 36562980, upload-time = "2026-02-23T00:20:40.575Z" }, + { url = "https://files.pythonhosted.org/packages/70/b0/eb757336e5a76dfa7911f63252e3b7d1de00935d7705cf772db5b45ec238/scipy-1.17.1-cp313-cp313t-win_arm64.whl", hash = "sha256:a720477885a9d2411f94a93d16f9d89bad0f28ca23c3f8daa521e2dcc3f44d49", size = 24856543, upload-time = "2026-02-23T00:20:45.313Z" }, + { url = "https://files.pythonhosted.org/packages/cf/83/333afb452af6f0fd70414dc04f898647ee1423979ce02efa75c3b0f2c28e/scipy-1.17.1-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:a48a72c77a310327f6a3a920092fa2b8fd03d7deaa60f093038f22d98e096717", size = 31584510, upload-time = "2026-02-23T00:21:01.015Z" }, + { url = "https://files.pythonhosted.org/packages/ed/a6/d05a85fd51daeb2e4ea71d102f15b34fedca8e931af02594193ae4fd25f7/scipy-1.17.1-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:45abad819184f07240d8a696117a7aacd39787af9e0b719d00285549ed19a1e9", size = 28170131, upload-time = "2026-02-23T00:21:05.888Z" }, + { url = "https://files.pythonhosted.org/packages/db/7b/8624a203326675d7746a254083a187398090a179335b2e4a20e2ddc46e83/scipy-1.17.1-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:3fd1fcdab3ea951b610dc4cef356d416d5802991e7e32b5254828d342f7b7e0b", size = 20342032, upload-time = "2026-02-23T00:21:09.904Z" }, + { url = "https://files.pythonhosted.org/packages/c9/35/2c342897c00775d688d8ff3987aced3426858fd89d5a0e26e020b660b301/scipy-1.17.1-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:7bdf2da170b67fdf10bca777614b1c7d96ae3ca5794fd9587dce41eb2966e866", size = 22678766, upload-time = "2026-02-23T00:21:14.313Z" }, + { url = "https://files.pythonhosted.org/packages/ef/f2/7cdb8eb308a1a6ae1e19f945913c82c23c0c442a462a46480ce487fdc0ac/scipy-1.17.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:adb2642e060a6549c343603a3851ba76ef0b74cc8c079a9a58121c7ec9fe2350", size = 32957007, upload-time = "2026-02-23T00:21:19.663Z" }, + { url = "https://files.pythonhosted.org/packages/0b/2e/7eea398450457ecb54e18e9d10110993fa65561c4f3add5e8eccd2b9cd41/scipy-1.17.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eee2cfda04c00a857206a4330f0c5e3e56535494e30ca445eb19ec624ae75118", size = 35221333, upload-time = "2026-02-23T00:21:25.278Z" }, + { url = "https://files.pythonhosted.org/packages/d9/77/5b8509d03b77f093a0d52e606d3c4f79e8b06d1d38c441dacb1e26cacf46/scipy-1.17.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d2650c1fb97e184d12d8ba010493ee7b322864f7d3d00d3f9bb97d9c21de4068", size = 35042066, upload-time = "2026-02-23T00:21:31.358Z" }, + { url = "https://files.pythonhosted.org/packages/f9/df/18f80fb99df40b4070328d5ae5c596f2f00fffb50167e31439e932f29e7d/scipy-1.17.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:08b900519463543aa604a06bec02461558a6e1cef8fdbb8098f77a48a83c8118", size = 37612763, upload-time = "2026-02-23T00:21:37.247Z" }, + { url = "https://files.pythonhosted.org/packages/4b/39/f0e8ea762a764a9dc52aa7dabcfad51a354819de1f0d4652b6a1122424d6/scipy-1.17.1-cp314-cp314-win_amd64.whl", hash = "sha256:3877ac408e14da24a6196de0ddcace62092bfc12a83823e92e49e40747e52c19", size = 37290984, upload-time = "2026-02-23T00:22:35.023Z" }, + { url = "https://files.pythonhosted.org/packages/7c/56/fe201e3b0f93d1a8bcf75d3379affd228a63d7e2d80ab45467a74b494947/scipy-1.17.1-cp314-cp314-win_arm64.whl", hash = "sha256:f8885db0bc2bffa59d5c1b72fad7a6a92d3e80e7257f967dd81abb553a90d293", size = 25192877, upload-time = "2026-02-23T00:22:39.798Z" }, + { url = "https://files.pythonhosted.org/packages/96/ad/f8c414e121f82e02d76f310f16db9899c4fcde36710329502a6b2a3c0392/scipy-1.17.1-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:1cc682cea2ae55524432f3cdff9e9a3be743d52a7443d0cba9017c23c87ae2f6", size = 31949750, upload-time = "2026-02-23T00:21:42.289Z" }, + { url = "https://files.pythonhosted.org/packages/7c/b0/c741e8865d61b67c81e255f4f0a832846c064e426636cd7de84e74d209be/scipy-1.17.1-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:2040ad4d1795a0ae89bfc7e8429677f365d45aa9fd5e4587cf1ea737f927b4a1", size = 28585858, upload-time = "2026-02-23T00:21:47.706Z" }, + { url = "https://files.pythonhosted.org/packages/ed/1b/3985219c6177866628fa7c2595bfd23f193ceebbe472c98a08824b9466ff/scipy-1.17.1-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:131f5aaea57602008f9822e2115029b55d4b5f7c070287699fe45c661d051e39", size = 20757723, upload-time = "2026-02-23T00:21:52.039Z" }, + { url = "https://files.pythonhosted.org/packages/c0/19/2a04aa25050d656d6f7b9e7b685cc83d6957fb101665bfd9369ca6534563/scipy-1.17.1-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:9cdc1a2fcfd5c52cfb3045feb399f7b3ce822abdde3a193a6b9a60b3cb5854ca", size = 23043098, upload-time = "2026-02-23T00:21:56.185Z" }, + { url = "https://files.pythonhosted.org/packages/86/f1/3383beb9b5d0dbddd030335bf8a8b32d4317185efe495374f134d8be6cce/scipy-1.17.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e3dcd57ab780c741fde8dc68619de988b966db759a3c3152e8e9142c26295ad", size = 33030397, upload-time = "2026-02-23T00:22:01.404Z" }, + { url = "https://files.pythonhosted.org/packages/41/68/8f21e8a65a5a03f25a79165ec9d2b28c00e66dc80546cf5eb803aeeff35b/scipy-1.17.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a9956e4d4f4a301ebf6cde39850333a6b6110799d470dbbb1e25326ac447f52a", size = 35281163, upload-time = "2026-02-23T00:22:07.024Z" }, + { url = "https://files.pythonhosted.org/packages/84/8d/c8a5e19479554007a5632ed7529e665c315ae7492b4f946b0deb39870e39/scipy-1.17.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a4328d245944d09fd639771de275701ccadf5f781ba0ff092ad141e017eccda4", size = 35116291, upload-time = "2026-02-23T00:22:12.585Z" }, + { url = "https://files.pythonhosted.org/packages/52/52/e57eceff0e342a1f50e274264ed47497b59e6a4e3118808ee58ddda7b74a/scipy-1.17.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a77cbd07b940d326d39a1d1b37817e2ee4d79cb30e7338f3d0cddffae70fcaa2", size = 37682317, upload-time = "2026-02-23T00:22:18.513Z" }, + { url = "https://files.pythonhosted.org/packages/11/2f/b29eafe4a3fbc3d6de9662b36e028d5f039e72d345e05c250e121a230dd4/scipy-1.17.1-cp314-cp314t-win_amd64.whl", hash = "sha256:eb092099205ef62cd1782b006658db09e2fed75bffcae7cc0d44052d8aa0f484", size = 37345327, upload-time = "2026-02-23T00:22:24.442Z" }, + { url = "https://files.pythonhosted.org/packages/07/39/338d9219c4e87f3e708f18857ecd24d22a0c3094752393319553096b98af/scipy-1.17.1-cp314-cp314t-win_arm64.whl", hash = "sha256:200e1050faffacc162be6a486a984a0497866ec54149a01270adc8a59b7c7d21", size = 25489165, upload-time = "2026-02-23T00:22:29.563Z" }, +] + +[[package]] +name = "scipy" +version = "1.18.1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.12'", +] +dependencies = [ + { name = "numpy", version = "2.5.4", source = { registry = "https://pypi.org/simple" } }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7e/74/66de6258867beb2ef08f35f9f2ac017a52cacd5081714d239ff1a442d458/scipy-1.18.1.tar.gz", hash = "sha256:52c4b7422442aba924d03ad4019852b08a92e64ea187b933135687bfe2747307", size = 30781235, upload-time = "2026-08-21T23:28:50.599Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/f7/240c110c08693826b4513a52f5717d62ec7c7af72f2920821247c03b17b3/scipy-1.18.1-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:457fd7a2a8edeb044ab6ffbc0aa03ff6cd18491356e5e0c834d76ce621b916d1", size = 31111061, upload-time = "2026-08-21T23:23:44.522Z" }, + { url = "https://files.pythonhosted.org/packages/05/4a/78c6285577c375e7cf27277ea8ee6961224327f1e1a0c44af5f17f23635c/scipy-1.18.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:e708533e8b2ae2497d65346538a7dcc92814410b25b81432eac66de0f2af8265", size = 28733332, upload-time = "2026-08-21T23:23:50.015Z" }, + { url = "https://files.pythonhosted.org/packages/a5/f6/a5b82f8abbe14d134691b8b903696f701d25a081353a29dc655c364d9e62/scipy-1.18.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:7bbf207c4453ce1ad2e00b17313852b33310b83090c2311bdaf97f93c0380d12", size = 20475078, upload-time = "2026-08-21T23:23:54.138Z" }, + { url = "https://files.pythonhosted.org/packages/23/22/0858a0bbd6b3e825ceb8cd9baf9eaf3b2f2b1d77727eb6be40500bcdc92f/scipy-1.18.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:78c0665edead396b1abb4897c41a5c1d9bf090c8a637a4c20a61678e0a264e66", size = 23108904, upload-time = "2026-08-21T23:23:57.824Z" }, + { url = "https://files.pythonhosted.org/packages/75/9a/2e71719f31eaefe0e3a1706c4a1ded94e664bfd95ffca2b219a671faee01/scipy-1.18.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c085faa2cfa879c5141df483f836f4d691045a078224a670fa570fa01612d89", size = 34025113, upload-time = "2026-08-21T23:24:02.209Z" }, + { url = "https://files.pythonhosted.org/packages/df/64/ff35eb9e54894cf471ff4716abd3c81eb0a0626869217ce3e6ba4ccf17d7/scipy-1.18.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f55fa87b6c612ecd6b058f167c53231b1d14e412efe361d3d6e38b3631c73218", size = 35344199, upload-time = "2026-08-21T23:24:07.844Z" }, + { url = "https://files.pythonhosted.org/packages/d3/af/c5538be1792f7034c12c7db6ee67cace58253c7b87b122d68253eaf5de89/scipy-1.18.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c35d74ce0e193ff740c2f2be2ac913ddc232fe6c1ff40b26cfecb9c670c63314", size = 35639587, upload-time = "2026-08-21T23:24:13.05Z" }, + { url = "https://files.pythonhosted.org/packages/91/4c/075e4f66471bac101141ac739e9e135549be1bae584571bd03a530c056e1/scipy-1.18.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d2924a03db38dc2e848bca2fe9f077dafb891480b91a00a0963a8cf86dfc31c1", size = 37480330, upload-time = "2026-08-21T23:24:19.608Z" }, + { url = "https://files.pythonhosted.org/packages/39/e7/979fd14e75008623df31ba70d6bb144700f68feadcea042021c06a05bf82/scipy-1.18.1-cp312-cp312-win_amd64.whl", hash = "sha256:5e4d44984abc0020154ea81b247adeddcc3ac5527b975ff798bd1ba0adc513c2", size = 36658278, upload-time = "2026-08-21T23:24:25.463Z" }, + { url = "https://files.pythonhosted.org/packages/c7/0b/e1525354ff9d7d5feb6d1b31af6d14072e5c91e9607b421fa1ec889660b3/scipy-1.18.1-cp312-cp312-win_arm64.whl", hash = "sha256:d65d448389b8436493abcf629cc94ad0cf32aecaf06e1acca1de53cc795f2f12", size = 24400588, upload-time = "2026-08-21T23:24:30.579Z" }, + { url = "https://files.pythonhosted.org/packages/b6/55/4540ee0f9c42a9ad7109d0d1a8cc70de54c3572b01c6693a2b1c70e90ceb/scipy-1.18.1-cp313-cp313-macosx_10_15_x86_64.whl", hash = "sha256:3ab3523da44749156e1f68b464dc56af11ae4cbc5c739a49d05f32b982eca9f3", size = 31089958, upload-time = "2026-08-21T23:24:35.8Z" }, + { url = "https://files.pythonhosted.org/packages/2a/f5/769f36d14922b8071a43e95d24d18b6bdafad10d7f5cf647867e1ac052bc/scipy-1.18.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:e6fb6a55cc0ba97b59a1f288fb86dc6fce8bdfc0fffcbfd015e3a954bf2a2d93", size = 28715106, upload-time = "2026-08-21T23:24:40.775Z" }, + { url = "https://files.pythonhosted.org/packages/9a/d7/21d890274f75ea37a8209d5519e72da3da90302e3b9fb8397a0918386a62/scipy-1.18.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:ea324d9dd34c38bfb9bec8ca4d1b407db97dbb74029f566b8e322b1b6fe56fe6", size = 20456846, upload-time = "2026-08-21T23:24:45.066Z" }, + { url = "https://files.pythonhosted.org/packages/ec/01/798430ecea2e78ec7c02663d5f71c007bb6abeca931080debd40d7fa55ea/scipy-1.18.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:75b00eb8fb802090aa903f4ea1c7f5a584779f967361e68b7e98e531cc2d7174", size = 23087986, upload-time = "2026-08-21T23:24:49.539Z" }, + { url = "https://files.pythonhosted.org/packages/e6/5f/4634e9d35c68496e4e34cb6946eafab044458e6cedab42b40b6588e475b6/scipy-1.18.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d416b16cccfd70fbf62400e84d0bb2f4e6af519a45557f1692c749b37f14b315", size = 33998146, upload-time = "2026-08-21T23:24:54.714Z" }, + { url = "https://files.pythonhosted.org/packages/41/48/6450ed9243315322bbc19ac57b9b70d66a20bf1d38d124c96bc4bf6af9ea/scipy-1.18.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fdaf5ea890a6183d0565f51a61799d67081bd5b1cf03c5f4b3fd3732108625c9", size = 35312578, upload-time = "2026-08-21T23:25:00.44Z" }, + { url = "https://files.pythonhosted.org/packages/00/bd/bf5a4be6a3525676499f6dff307991739ff6fdcad1481b1aeb6745339f58/scipy-1.18.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c825cef2f49e46753726a7181a8e199804a912b29519ada542c6ebc654951899", size = 35612621, upload-time = "2026-08-21T23:25:06.144Z" }, + { url = "https://files.pythonhosted.org/packages/bd/4e/3c45c33e00a77996c4b1cb707929f833ba7b1d522ee29f882512c330676d/scipy-1.18.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e3b417bf8c2c7c16e8f58ad91db17783ec911ac16e7b50eb6eab6e809b4f5b07", size = 37457323, upload-time = "2026-08-21T23:25:12.483Z" }, + { url = "https://files.pythonhosted.org/packages/93/0e/e0348fbc0dbab65c114cf78957e7dfeb49f8e8b556b4d930cc12ff195e18/scipy-1.18.1-cp313-cp313-win_amd64.whl", hash = "sha256:559ed65f60c1af5a03f3912605a1b5114f522c7c32fb23c3376ae8f03219fe28", size = 36622841, upload-time = "2026-08-21T23:25:18.722Z" }, + { url = "https://files.pythonhosted.org/packages/50/a8/6a77f5f267c555108f0a864b6db714363dab567a8266422a79a385f9232b/scipy-1.18.1-cp313-cp313-win_arm64.whl", hash = "sha256:cd479fc04dd9401e3b4f49e76518768ef99c4f517a98c284eb091fd725719adf", size = 24399315, upload-time = "2026-08-21T23:25:23.458Z" }, + { url = "https://files.pythonhosted.org/packages/06/d5/d8eb4e280ddb56a4ab2c6f02ee49b56b23f6e977cf0802fd6d68dbef14f5/scipy-1.18.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:83de5453a7799afc9048b4616bd085cef126e36412f0ea2f6370c36a2a3a51e7", size = 31090936, upload-time = "2026-08-21T23:25:28.686Z" }, + { url = "https://files.pythonhosted.org/packages/2a/49/59ea385dc3a62ff498ddf3cfff7c2b41b0f9f9d3c4122b3f1dcb6d6327fe/scipy-1.18.1-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:9554bcc6d715ee87a633a3cc8e7703c6628b100dd29cb8a2efc4c0533c7ff729", size = 28725221, upload-time = "2026-08-21T23:25:33.244Z" }, + { url = "https://files.pythonhosted.org/packages/70/e8/6b0c288c50942d78193696c9f15f9a0874f5178aa0ddf40f83d9924b3e8d/scipy-1.18.1-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:011413b7426b75012840e35649e00fe0a2c3bae89fed433876e3a99251572efc", size = 20466839, upload-time = "2026-08-21T23:25:37.516Z" }, + { url = "https://files.pythonhosted.org/packages/4b/e0/54fd3793c729e3b936782f181b59cbb1205bf250ab605a16cb1ba61cdd5e/scipy-1.18.1-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:88f0e784020649f88ea48c9f5ddfa403bf9205820667c0914740b392035afb82", size = 23089121, upload-time = "2026-08-21T23:25:42.019Z" }, + { url = "https://files.pythonhosted.org/packages/0b/56/030af62bea3cf878e0028515dff78c123b01633606a879b63f42d2db99cc/scipy-1.18.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2d3ab0e8c69a17dd3559eab8cbb88f258e285c94d572c2719033f90f83290c89", size = 34053851, upload-time = "2026-08-21T23:25:47.998Z" }, + { url = "https://files.pythonhosted.org/packages/6b/89/2a844506d49651e9aa1af6ef95b6bd8031cb1d5a4375edec6155037e04cf/scipy-1.18.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ac0333bdf38309aa3dcbe7e3fa7ea29e7a2c37c6ea306a757b700ded8e4596ad", size = 35329183, upload-time = "2026-08-21T23:25:53.522Z" }, + { url = "https://files.pythonhosted.org/packages/eb/56/c7370c3640e92ac9613cbf26cb3f729f9b12ddf1727b55b94b53b24d6f48/scipy-1.18.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:911de823097db8b63f034299d12662db93344e6ffa0b881cbb57748974b70168", size = 35672551, upload-time = "2026-08-21T23:25:59.387Z" }, + { url = "https://files.pythonhosted.org/packages/24/16/ec8536f351421f8bf60a1120930638f83790f4710b8230446aca3d6159d4/scipy-1.18.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:95298364e251be3e60249facbeeca03631d3bb7584f85879516ec55ac717b81f", size = 37469416, upload-time = "2026-08-21T23:26:05.432Z" }, + { url = "https://files.pythonhosted.org/packages/52/94/d73da0d28f16c45bb9b0a5691b91610b0275c5ef0eb5e43c87cf2dc1bf31/scipy-1.18.1-cp314-cp314-win_amd64.whl", hash = "sha256:78a0d7c918e74a232394117160e7e3db503377572a45bcef8826e4ab8a35feba", size = 37362755, upload-time = "2026-08-21T23:26:11.366Z" }, + { url = "https://files.pythonhosted.org/packages/89/25/e996e4dc74e10e227b1e14db5eaf6608bb6dd33884a64851c38f18dd4249/scipy-1.18.1-cp314-cp314-win_arm64.whl", hash = "sha256:cbf38d043c1aa4ab306e1ada6ab6eddacc3322a20b7af1b30bc93254b366fe09", size = 25036090, upload-time = "2026-08-21T23:26:15.887Z" }, + { url = "https://files.pythonhosted.org/packages/fa/c9/c00213f92309d753b48903e6a451b87eb52ff5b7a16e789d1568bbf221c4/scipy-1.18.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:0fcb3c93519f27bb4f0c4b0f7802cdcaca7fcf93267b75edda2e9f4e8a55cbd7", size = 31485550, upload-time = "2026-08-21T23:26:20.776Z" }, + { url = "https://files.pythonhosted.org/packages/74/b2/e3067c487982d4eeab2938928529410370c06fea84a4d3f4925e7d96647d/scipy-1.18.1-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:ddef79fb382df40104a19bb7151b3b23e57c1778fcf857c71ceecd9bd264513f", size = 29174642, upload-time = "2026-08-21T23:26:25.395Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ab/374c9fe2d1ec014e576c781a4b5d8e1ba340e8f6b4638c16f711d2b194f0/scipy-1.18.1-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:0e82073ecc7acc6436fac4b31674109c7e1d3e596789767eda01258a8c9e8123", size = 20916357, upload-time = "2026-08-21T23:26:30.112Z" }, + { url = "https://files.pythonhosted.org/packages/90/38/223915c88a17317cafbf8ca2a42b11c265a9fb1e804aa665544132b5fe8a/scipy-1.18.1-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:8bcf3c1ba5d6456e2effd30fcbd3459b044d683fcdac79a2e6830f0bdf7de487", size = 23482611, upload-time = "2026-08-21T23:26:34.846Z" }, + { url = "https://files.pythonhosted.org/packages/c4/d1/db0948da8ca57a80b36520ef0a768b967d99f3af65f4b6f1bf6362ad4dd4/scipy-1.18.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cfbf154f2ba187f2ed6cce2639efff7d105f1140573642c0161615b6d91d6a87", size = 34143202, upload-time = "2026-08-21T23:26:40.4Z" }, + { url = "https://files.pythonhosted.org/packages/87/53/39d046cc7574ed6acacb6bd5723e220107ece80bff12faaf3efc4ddeede4/scipy-1.18.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a1d33a7836f7ddc1993427966a0823468ec41bcbdb1a9f9942d1d7e57f803ba3", size = 35380876, upload-time = "2026-08-21T23:26:46.1Z" }, + { url = "https://files.pythonhosted.org/packages/f9/da/32e0e799d875a85ca57d9bde6c78148afcc0e38276df683d95854eadc8c3/scipy-1.18.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7f4b8bc363b6d65ee2152bec57568e3c52639bb34c46057b09857a307ed5e21d", size = 35770885, upload-time = "2026-08-21T23:26:51.533Z" }, + { url = "https://files.pythonhosted.org/packages/88/2e/f97a666d362fee68b18f41c9c30ed502ca5c98b549749bfcb52a8b74d1eb/scipy-1.18.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:11c423f1049c5755ad4409af52a9ada1cff96fe9b50795d4af3619f292901239", size = 37525424, upload-time = "2026-08-21T23:26:56.751Z" }, + { url = "https://files.pythonhosted.org/packages/ca/d5/a9e765a84654ebba8479a1fd1b059ced1af72b168a3b2a3a46540ea38d20/scipy-1.18.1-cp314-cp314t-win_amd64.whl", hash = "sha256:c24acac1e18912761c4700239bbc1fd32f615af690f1584d49b35859be51324d", size = 37416961, upload-time = "2026-08-21T23:27:01.546Z" }, + { url = "https://files.pythonhosted.org/packages/ee/16/e79e0d1c63ef698879d85439d37e9fb434e3b804e506a6991038d086ebd9/scipy-1.18.1-cp314-cp314t-win_arm64.whl", hash = "sha256:9f2897bf7737392ad0d5213ea7b6add72a4edf5679b3153106aeb88b6507b3b9", size = 25331848, upload-time = "2026-08-21T23:27:05.884Z" }, + { url = "https://files.pythonhosted.org/packages/be/4f/1bd37c883b67163e2ca1f60977a399500e6879c15defecac62831c8d078d/scipy-1.18.1-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:eb0dfcf4e28a99c12c999744a2ff67c9b06200e20401c7c88186e33552a46331", size = 31091484, upload-time = "2026-08-21T23:27:11.051Z" }, + { url = "https://files.pythonhosted.org/packages/8c/c5/ba929d7feb9b2332f96827c12e0e924b61973b59b4dea383b603372c65ce/scipy-1.18.1-cp315-cp315-macosx_12_0_arm64.whl", hash = "sha256:30f464bee641fa8e282577c7dce027308403213c6ca8270bba73285c91024bc5", size = 28725057, upload-time = "2026-08-21T23:27:15.9Z" }, + { url = "https://files.pythonhosted.org/packages/a4/19/68f1c50f609d955d230e66d25d02bd3e1e167ec540232135354fb9a4b9e3/scipy-1.18.1-cp315-cp315-macosx_14_0_arm64.whl", hash = "sha256:1bca3b943fc2567ea49cd02c99abde49da4d5178ec46f624bd8255cda8755beb", size = 20466734, upload-time = "2026-08-21T23:27:20.044Z" }, + { url = "https://files.pythonhosted.org/packages/ef/6d/319fa29b73d1802fa80b32a6eaf3f5be456ef81526da2716a9493bcb5501/scipy-1.18.1-cp315-cp315-macosx_14_0_x86_64.whl", hash = "sha256:c9d18a33309122074ea483dd92dd444189166b8b2ec429fe9ed5ac73c7a0aa23", size = 23089664, upload-time = "2026-08-21T23:27:24.345Z" }, + { url = "https://files.pythonhosted.org/packages/b7/db/30992f9b51a63de671daf3888ffd18378b6cb9ec9f2c972264238ffa7fd6/scipy-1.18.1-cp315-cp315-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:82f201b4c878551d48558337aab270d3c6cca5507b8737c8d8a608d234cccde0", size = 34054035, upload-time = "2026-08-21T23:27:29.409Z" }, + { url = "https://files.pythonhosted.org/packages/91/d4/bf3e735dc0b9d5a8ff45079d2540e17d3aff7a2f0048dd8f552ffd031d2b/scipy-1.18.1-cp315-cp315-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0ac49ea97594532dd44b7136094d35f5440fa06e6d9c6384a74c01764df388c5", size = 35333883, upload-time = "2026-08-21T23:27:34.293Z" }, + { url = "https://files.pythonhosted.org/packages/19/93/12d78ce9f871fe945fca588d32644e6e63f553c2a35c564d73f3b22a3313/scipy-1.18.1-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:ceb30a00ce7c92d459819443d29ca486d882b83fb6738bdcbb2a1cce94ac5daa", size = 35673124, upload-time = "2026-08-21T23:27:39.059Z" }, + { url = "https://files.pythonhosted.org/packages/70/cd/886219313a1012a48e6ae0ec4f302c837151beb92e1ff0d709ef8fdfc488/scipy-1.18.1-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:f29633129f9fa7e88a3f0fca835de2d030bfc9643f7799e1a0c46cee24d38fc7", size = 37470753, upload-time = "2026-08-21T23:27:44.435Z" }, + { url = "https://files.pythonhosted.org/packages/17/6c/a776888ce618bee54fbde26172f0f46ac1da70d27b63861797fe78e1904b/scipy-1.18.1-cp315-cp315-win_amd64.whl", hash = "sha256:92c14f5bdbfb6216315ce33e78080474082de8b3830122ba97809bfbe65f75c0", size = 37361483, upload-time = "2026-08-21T23:27:49.334Z" }, + { url = "https://files.pythonhosted.org/packages/ab/09/97b651691322ebee97999b017ffc18a15a0b815103844c97e8da9d469731/scipy-1.18.1-cp315-cp315-win_arm64.whl", hash = "sha256:e402cf31eb68f453dbb2d36fc6d722b33f24a55d68b2ae1d92fa6305ca71c298", size = 25035883, upload-time = "2026-08-21T23:27:53.596Z" }, + { url = "https://files.pythonhosted.org/packages/ed/0f/9ec20467bbabd0d44e2a77d0fd3d124f884b4d67df92af82c91d2d6a486f/scipy-1.18.1-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:2a0b02f9fc46f8520330c23d45e6560db7e3a0d927232139427637f98943e11d", size = 31474926, upload-time = "2026-08-21T23:27:57.993Z" }, + { url = "https://files.pythonhosted.org/packages/8a/58/dcb79161e56efbedc50079fcd2f5fe427a0ebb53022eb476aa73c015ad8f/scipy-1.18.1-cp315-cp315t-macosx_12_0_arm64.whl", hash = "sha256:1d73131e358976663dd969e1fb4ed1404b815cd977eaaedc3b3a133ba2d81c35", size = 29164940, upload-time = "2026-08-21T23:28:03.062Z" }, + { url = "https://files.pythonhosted.org/packages/71/d3/1eeea80c817fcb8ef7bd4a05a58824977a0e57a375cfc3d7ea7c911c01ad/scipy-1.18.1-cp315-cp315t-macosx_14_0_arm64.whl", hash = "sha256:bff0b729edd992766136b34e39cc76bc2fad905aa58897ee72a9cd000a6d8443", size = 20906742, upload-time = "2026-08-21T23:28:07.642Z" }, + { url = "https://files.pythonhosted.org/packages/54/46/e59350428b6099301a20128108c995e2eb175a43f383af9a346e38824f9b/scipy-1.18.1-cp315-cp315t-macosx_14_0_x86_64.whl", hash = "sha256:10ac20c69d880f77f375db44c22e3e6a644f9fefa291d4cd2fb9790a89fc99fd", size = 23472183, upload-time = "2026-08-21T23:28:12.109Z" }, + { url = "https://files.pythonhosted.org/packages/89/31/cc91623fa98f0621766a0f0aaaadb2c66de74a7ea7e3837164f6e4354260/scipy-1.18.1-cp315-cp315t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:33a834464fdabc0f26a45508df31b3cc5d028e04dbf6c5ed398541418e0a12fe", size = 34130796, upload-time = "2026-08-21T23:28:17.906Z" }, + { url = "https://files.pythonhosted.org/packages/fc/3e/8572ef536957ddb8aa81bb4090d9e25f257e3b4e05d97deb54319deb8a3a/scipy-1.18.1-cp315-cp315t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:49023963c193dacee096301452f223ee24d86ec5807f8df93c0f7221d119e305", size = 35374253, upload-time = "2026-08-21T23:28:23.732Z" }, + { url = "https://files.pythonhosted.org/packages/b5/c6/59fdeffb4f1435299f93d9dc8140b43ad2916e6cfc944be6c3041fcec86d/scipy-1.18.1-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:d84a09d0dad90ba6525d8ac1c2334b33e64bf3ccfe9e841f02feb867a22681e4", size = 35758543, upload-time = "2026-08-21T23:28:29.431Z" }, + { url = "https://files.pythonhosted.org/packages/cf/d9/135be205d9de8783193aff9cc3bf483a03a38e4b29432c954e8cb66ac14e/scipy-1.18.1-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:179ce34a8d0fe273d8883ba59e17e052247d08973dfcb743ca52bb1cce2d60b0", size = 37521946, upload-time = "2026-08-21T23:28:35.245Z" }, + { url = "https://files.pythonhosted.org/packages/5c/a2/5b7d5270621ab7cfa3f7766067bf95dc360b5efb6394694e8143b4156e2b/scipy-1.18.1-cp315-cp315t-win_amd64.whl", hash = "sha256:5632e3ae3d09197c446310cd5187de63e28448ce22f0f67b2b93d97503c0c230", size = 37408295, upload-time = "2026-08-21T23:28:40.724Z" }, + { url = "https://files.pythonhosted.org/packages/63/ad/741c19fcb66755ff953daf9243af8480e4bf3d7fbe57583c178c7d2b6b51/scipy-1.18.1-cp315-cp315t-win_arm64.whl", hash = "sha256:eda632a7981f69730d6281f451db9c1c370993a2c0d7ddb43e2a809a2862b83a", size = 25319710, upload-time = "2026-08-21T23:28:45.713Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "threadpoolctl" +version = "3.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/56/97/b4748951a683e369513691c8eea33d100298d556308dcb0ab66b132a67f0/threadpoolctl-3.8.0.tar.gz", hash = "sha256:01080674ad7ac6182429c918a79de92da789bb448acc02fc0b620b1abd6b6137", size = 39424, upload-time = "2026-11-05T11:08:51.112Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/1b/831f2de4840a25db1dd7b1afea433ccafe6bb10aca07e13264f2079462d0/threadpoolctl-3.8.0-py3-none-any.whl", hash = "sha256:f1b49c82704d50f13ffae019c727b0fa4f6791a58f48f06a09c45face1be66da", size = 32091, upload-time = "2026-11-05T11:08:49.773Z" }, +] + +[[package]] +name = "tomli" +version = "2.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/78/9ad63712633ed3ab5cc1a648d863d7e7da371e9425e209555a0fe711b695/tomli-2.5.0.tar.gz", hash = "sha256:264507556cd8b8c8e7c6ee037cdf443a463f03f4c958e57195e3d369711b8ff6", size = 17662, upload-time = "2026-10-07T12:23:37.892Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/a6/ab99b60ee52acd949684febabc3005d0045d0f66bebd9cdebd67372d26dd/tomli-2.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c4dc1c1781f2f716de763d1e9a7b34c6a894e167e291c7c5d16c72f7a9538545", size = 163901, upload-time = "2026-10-07T12:22:15.601Z" }, + { url = "https://files.pythonhosted.org/packages/bc/00/ee01b7ed4579180fff07142d290257f25ba786f23f3ec6005f620933c2f5/tomli-2.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:eff8babca5a7999bc137acbc7482a8b7e17ffca5075ab41f5d770ab408c7bfef", size = 163756, upload-time = "2026-10-07T12:22:16.957Z" }, + { url = "https://files.pythonhosted.org/packages/72/c2/4efebf65372f6583185f79799312109dddb61102d47e5c33dcfd1a297aca/tomli-2.5.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:86665cee9c4835b7a7f1e8ec2c719b5258d4dc782887aded5a8ae7352a96843b", size = 268038, upload-time = "2026-10-07T12:22:18.135Z" }, + { url = "https://files.pythonhosted.org/packages/53/07/5850468e925d898abb36038666f9c333a94d2a223e802a8ba5b6d319d23f/tomli-2.5.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d7e369fd63331746182360977b1892bfc215476a30d61612d732425311639f56", size = 276422, upload-time = "2026-10-07T12:22:19.567Z" }, + { url = "https://files.pythonhosted.org/packages/b4/87/f293984cdcf83c054196d4fd3dad44fc68ae55b4b8c44bc76cef360c3150/tomli-2.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7ad1ea345759240d6463efa0ed1c704402752e49aa21476620738d74d72d8aa1", size = 272616, upload-time = "2026-10-07T12:22:20.794Z" }, + { url = "https://files.pythonhosted.org/packages/ce/ce/db582886b3c1219d3fec93ebd669332482e5aee7a91e0f7838d84f2d1759/tomli-2.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:96243987194634bd411066ce40c952e108f86af04db533ecd8ac3ff2a85b1885", size = 276593, upload-time = "2026-10-07T12:22:22.12Z" }, + { url = "https://files.pythonhosted.org/packages/bf/72/7619b87dea4261fc27dd7b54c4461c129c1f7d9bb7ba3aec89c797a431b8/tomli-2.5.0-cp311-cp311-win32.whl", hash = "sha256:610b27d99f28ec5f191c7064a48f3ddb179a1fe6ca73d571483ae859f57b605e", size = 101830, upload-time = "2026-10-07T12:22:23.651Z" }, + { url = "https://files.pythonhosted.org/packages/1e/74/220106da34502304b6751a2a9b8a9fbca6c3fd47e737a2e2e3da7c61c9db/tomli-2.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:c804ae44fe7b4bab5da295e4f980a1ff04670bca9d23fe0a4e887e08ebd741a8", size = 112742, upload-time = "2026-10-07T12:22:24.972Z" }, + { url = "https://files.pythonhosted.org/packages/27/99/7d9c8b41837a7773613e169504147375c157a290167aa59ad74a085f521f/tomli-2.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:cfac177ebd6236003846ea339981f71457cb6eb748f23381eb257e45092e3980", size = 109332, upload-time = "2026-10-07T12:22:26.117Z" }, + { url = "https://files.pythonhosted.org/packages/52/ed/7baa86f87493646a594de388c7c1c40a39dd0461f7e9c0359cbeefc91fe8/tomli-2.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1f4a40d03fb9f63424f0979855bdeaf44dd7696b8d59501822c10ed30ba532df", size = 164854, upload-time = "2026-10-07T12:22:27.444Z" }, + { url = "https://files.pythonhosted.org/packages/a5/b1/44c0341f2224397855723c7a8a39f718ea6fcbcc3dacc66e5aeca0f334e3/tomli-2.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9ebf8d19b17bd0daeb7b7dec81a946a439b753942fd0210d6e96c532249eea6b", size = 164074, upload-time = "2026-10-07T12:22:28.679Z" }, + { url = "https://files.pythonhosted.org/packages/23/04/e2d5b7d3fba47adedb23de616c16d428ea076c79a3d8e1d95d649ffe197e/tomli-2.5.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf0b5e8e0f68ebb494356e577c06c139161efd8d3b9050f93b39b7c26cc54ff0", size = 274274, upload-time = "2026-10-07T12:22:29.804Z" }, + { url = "https://files.pythonhosted.org/packages/43/90/6090e706ff27a6f89f4a40578e3324b95c3cd8c4150868aabf33a8f414c3/tomli-2.5.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cf74416bdc94ae458b14e37286c1073081850ac8459a00d0c5efef5d44294c6", size = 286435, upload-time = "2026-10-07T12:22:31.297Z" }, + { url = "https://files.pythonhosted.org/packages/0a/9e/a2c40768df16c408f22430afb0a73e9d7e5f79c950884954649d1146b74d/tomli-2.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:61ea1ebe1e55a34ea8199cc8dbff398d35027b82271c8ac4802fd3a1fd5b1bcc", size = 278119, upload-time = "2026-10-07T12:22:32.601Z" }, + { url = "https://files.pythonhosted.org/packages/12/25/3c0cb485b98e9cfac495629b1c93c87ccf0b72fbe9d2689fd8fe62c6d5a3/tomli-2.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ed53f7e89bb04f6d9e8e7799112360b0c4d5cbff067de0814c98c37c39b920f7", size = 286177, upload-time = "2026-10-07T12:22:33.745Z" }, + { url = "https://files.pythonhosted.org/packages/77/8b/0144c65f0e37e51c18d04ae15c21b19431c165002d0131fe9aa8b0b8b1e8/tomli-2.5.0-cp312-cp312-win32.whl", hash = "sha256:e7ad033e27a516a233bea839cdb77b80146facb3b4f40bf02cd0cac165cdd5c2", size = 102760, upload-time = "2026-10-07T12:22:34.887Z" }, + { url = "https://files.pythonhosted.org/packages/de/32/5d6d8f42fc9a05fce69354e00ff256484192f5f2fc9a2165718fa0de61ec/tomli-2.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:bd05de8c1698f8413dd7d869492693a0bf2211543b787ac78cd5e7536af1a6d7", size = 112722, upload-time = "2026-10-07T12:22:36.162Z" }, + { url = "https://files.pythonhosted.org/packages/30/65/df18032218db0fb9b769fb23c8039a051f15c811993995ea04c350273a32/tomli-2.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:069435bd5480429b98c5e5afb02ab21c219b6f0064680671c6dc0d46817346ea", size = 109534, upload-time = "2026-10-07T12:22:37.296Z" }, + { url = "https://files.pythonhosted.org/packages/42/e5/51736d70da209350969e15aca5c5ab6e2ce1ea87a0a892a6c13aec172a86/tomli-2.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:943276cf269e0071948d9ff697159c1735e623c1151d88abb09b74659ef0cbea", size = 163328, upload-time = "2026-10-07T12:22:38.373Z" }, + { url = "https://files.pythonhosted.org/packages/ec/55/086f80dab4ab497602644274e6dea7ec5dd0b4e262e443a8ad3bb7edee2d/tomli-2.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:463b16086865b97facd8d0b3fb4cb7c544e3f58d2a69dc3113d6db9653fdb043", size = 162246, upload-time = "2026-10-07T12:22:39.673Z" }, + { url = "https://files.pythonhosted.org/packages/aa/eb/3ecc94459f3635c92321f4e7bde571323fdb2267c50e19e3188a281eae3b/tomli-2.5.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1245a6638fc4bb0a60af38a7d45413db34a13842027c77597c712c998c62fdf0", size = 272655, upload-time = "2026-10-07T12:22:41.08Z" }, + { url = "https://files.pythonhosted.org/packages/c0/d7/494fd1f0c37a621f1ad9975c2efadb523e8101f144ed6edb2e7fe64738f2/tomli-2.5.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5d8bac3d603c97e6854424e5b2b5b741bdbde387e09f162fb0446812b4a8362b", size = 283595, upload-time = "2026-10-07T12:22:42.222Z" }, + { url = "https://files.pythonhosted.org/packages/70/51/bb8d62b1317e6640866f6949b2d5855e5300f2c99d46de1cd245570bba65/tomli-2.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:21e4cae4114aba25aa0d4f85cdf486d290fb35c0954d7bba536248da64d43066", size = 276253, upload-time = "2026-10-07T12:22:43.625Z" }, + { url = "https://files.pythonhosted.org/packages/66/f4/f46bd7f0763cd47de2db697dca9257c6a4adfd1a93b018cc75c8190ed5a8/tomli-2.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bbaefc84548d754be821bba7c4141c4787dda182f9e77f2f87b71213529efa7b", size = 283582, upload-time = "2026-10-07T12:22:44.983Z" }, + { url = "https://files.pythonhosted.org/packages/ac/03/70f2bcb2923a6db37818d917e124270a7f4cfd38ea576f5aa753a91c0ef5/tomli-2.5.0-cp313-cp313-win32.whl", hash = "sha256:abdbf6313b8d9efe157edeb7ab6eae4de064b1300ad31abf73755154b30abe68", size = 102628, upload-time = "2026-10-07T12:22:46.508Z" }, + { url = "https://files.pythonhosted.org/packages/dc/98/d52024bb5b0ff68b4f0d276d867f634c84a67319a7e9f6b7708a37742333/tomli-2.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:fd4dc129784e0c5335bd4e61dfcc4487499a013419e655cf2da1d091b7e0efdc", size = 113301, upload-time = "2026-10-07T12:22:47.647Z" }, + { url = "https://files.pythonhosted.org/packages/6f/f2/540db3a70572a8c23a28aba3e9c358ce0ffffbafc990905c1343aa265b31/tomli-2.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:69491c143d2fe063046e0301e62a810bed338fa4d1ce0fd870c27dc1e09b0d84", size = 109744, upload-time = "2026-10-07T12:22:48.925Z" }, + { url = "https://files.pythonhosted.org/packages/e4/49/caf6b307766eb9567664a8707e9d6be5fcc0e8903f18781c6677a60d80c7/tomli-2.5.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d3182ee2d887e507bd67319a0a61105d1dd33facc111329559a233b772c1a105", size = 162899, upload-time = "2026-10-07T12:22:50.088Z" }, + { url = "https://files.pythonhosted.org/packages/d3/c8/68cfce773a2733a49c74f99d627fb461bd990756860099eac25617889585/tomli-2.5.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:521345fd1f19d45b8df87657aaa38b6f2ca3800059fadf428e7ebf479a383646", size = 162080, upload-time = "2026-10-07T12:22:51.558Z" }, + { url = "https://files.pythonhosted.org/packages/7e/b2/e5bb8651fdad593f670501a7d718b1a7f73f064d44dea15e04c04dfef45d/tomli-2.5.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e95c7614e705bfe2b04b27aa124adec59752d15813df37e2156747cab3a006b", size = 273380, upload-time = "2026-10-07T12:22:52.918Z" }, + { url = "https://files.pythonhosted.org/packages/8d/d2/9e2d7f8b1dfe0e2b34c245986ebd55c4c553ea4ce6c47c443b332673253f/tomli-2.5.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7ac2027d37c3afbdf4bdd377f2676f6f1d2122a5be1f1137b49dced590b37e75", size = 283228, upload-time = "2026-10-07T12:22:54.173Z" }, + { url = "https://files.pythonhosted.org/packages/ba/df/ec7b876b7b1a2718bd74a3743c076fff565b04029ba33e8f61fac262739f/tomli-2.5.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c414be4ed9d3cac80c42e348fa5a956117d1a48227f48026e31f59cb4a7671eb", size = 277189, upload-time = "2026-10-07T12:22:55.342Z" }, + { url = "https://files.pythonhosted.org/packages/7d/7b/e192d9eed0b9cb80da799f4d77052297fb9a2c3cc9b19f571f56ea88add6/tomli-2.5.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9b03d7dc168353b4132965bde20feceabaa470e570c6f59660dfae59b1f9eeb3", size = 283632, upload-time = "2026-10-07T12:22:56.735Z" }, + { url = "https://files.pythonhosted.org/packages/84/50/ff94454e75461d75623e47401ed323d65c10aab8fe9033242c20cd2fdf32/tomli-2.5.0-cp314-cp314-win32.whl", hash = "sha256:6f041843c4d3a37245c0c056fd955b186bf8b1fb85690cbe40b81230891dc34b", size = 103535, upload-time = "2026-10-07T12:22:58.084Z" }, + { url = "https://files.pythonhosted.org/packages/54/0b/bdacf05f963bd6026ebf6eeb0beda847d1d60e03e440725c64a4e08a0afd/tomli-2.5.0-cp314-cp314-win_amd64.whl", hash = "sha256:f4b653094e18f9031102d3a1da5c729c8f222d85225b18037dac621695e46e1a", size = 114621, upload-time = "2026-10-07T12:22:59.2Z" }, + { url = "https://files.pythonhosted.org/packages/61/99/53f438fa6ae4f9d4ed0ddde3e7242b3bdc34b48c8f9948b72b9e9b127676/tomli-2.5.0-cp314-cp314-win_arm64.whl", hash = "sha256:3f89d10c1ff6a38d992c27fc8a4816af71a909e08a40ec66934240b1e74347c3", size = 111572, upload-time = "2026-10-07T12:23:00.479Z" }, + { url = "https://files.pythonhosted.org/packages/b9/20/1f88f19427d380a40e90a770e087489eaafe4aeee070ae88ed2bbec00acd/tomli-2.5.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:e9e15b4a6c7dd6b85b5fbab29488a73f1f70de516942308daa266bf0e0aeb0d4", size = 171814, upload-time = "2026-10-07T12:23:01.914Z" }, + { url = "https://files.pythonhosted.org/packages/d0/56/cbe5079c9f9a54b9b3e27fc82f08f3cb36edee75561679f53d2380c801d6/tomli-2.5.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e12bbcd32897272fb05929110362ae9ff4c1b9bb26bd9e971e71dcd3275b4c3d", size = 171324, upload-time = "2026-10-07T12:23:03.18Z" }, + { url = "https://files.pythonhosted.org/packages/2b/30/1d53fd3b0f1cb3ba542e345ec32c26aefdddc4e829e4f3429af8a4f27782/tomli-2.5.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:20aa36de8f2cf87237143bc1fa1aae8d6612c09118f4da21c6a684db5dd1f6f9", size = 297441, upload-time = "2026-10-07T12:23:04.345Z" }, + { url = "https://files.pythonhosted.org/packages/66/d9/0800acb6a111686f764c1b91ef15cc42a20a66a46013bb42220f1d2c61c1/tomli-2.5.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22185fad8a1e622f064e78008018a0dd3323550dcb479cb7a1d296888d74024f", size = 307476, upload-time = "2026-10-07T12:23:05.671Z" }, + { url = "https://files.pythonhosted.org/packages/e8/63/30a8f3cd51b5bec37f04744bad0b0dc6160df84aad4f27b0e9283d66f221/tomli-2.5.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:984012f71908165449a951de2050d52f276bfe3aa5d5f570f63ddad814370374", size = 296113, upload-time = "2026-10-07T12:23:07.202Z" }, + { url = "https://files.pythonhosted.org/packages/ab/18/0b9ffc597e69c5a1e20a7823cb60d54b39a9f54e91edcb8574f022186758/tomli-2.5.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f79203b3965b4000e91808aaa7c040206093f2b8bf86f455982f2274c9ccf442", size = 307725, upload-time = "2026-10-07T12:23:08.508Z" }, + { url = "https://files.pythonhosted.org/packages/ab/c7/18f8baae0b5607a60e8e19b4a7fedee43a8ff6458e3896dcbbadeeac9c22/tomli-2.5.0-cp314-cp314t-win32.whl", hash = "sha256:91294a9fb94a75542f6e46e4a2ae709bd8d9b51134098cae5cf3bea5478b6d03", size = 108546, upload-time = "2026-10-07T12:23:09.956Z" }, + { url = "https://files.pythonhosted.org/packages/72/34/4cca9739254130627bde87500b3f2b512154fe2f278efa7e2a5e10ad4bcb/tomli-2.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f15e3e0b835a6d68b10c86bf80a3149780498d6911c93c3ffd1861d19f9200f1", size = 117814, upload-time = "2026-10-07T12:23:11.486Z" }, + { url = "https://files.pythonhosted.org/packages/7d/fb/afa530d47dd80a78fce43beac6bc6e00f84558eafcffbc6f37b21e80d056/tomli-2.5.0-cp314-cp314t-win_arm64.whl", hash = "sha256:6664b7ae7af7294256c53960a6103077f4914cec8ff98479c352f622c6f6b2f0", size = 115188, upload-time = "2026-10-07T12:23:12.728Z" }, + { url = "https://files.pythonhosted.org/packages/66/98/316fdc00f8c0939e6fe50461dd343c162d3ad51d1286eb25b7db54361d50/tomli-2.5.0-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:a525685c2f97da40762b8695eb7aa0af4c8344ca1905c73e4e29cb04d34607dc", size = 162775, upload-time = "2026-10-07T12:23:13.941Z" }, + { url = "https://files.pythonhosted.org/packages/c5/22/7b10fa5bb01c9539f53f69b619361b19350acc73657772ea7ac70ba309a8/tomli-2.5.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:9dbb18c1cfb2f6517942fc9314437f66aa06d94436ffb1f06102ef3572f35276", size = 161406, upload-time = "2026-10-07T12:23:15.215Z" }, + { url = "https://files.pythonhosted.org/packages/9c/e7/1a069d86dfd20f1f84f71c63faed9f83c1d890bc06c27d82dc7d888fb573/tomli-2.5.0-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:752e8b1aa6a4367ef8bf6a1a1e005540f7ed055ba36d7193796812ca5404eb52", size = 273855, upload-time = "2026-10-07T12:23:16.471Z" }, + { url = "https://files.pythonhosted.org/packages/ae/83/d1ef43d1687d092ab9c235455c76e6e709483b346b056f086095c7c263a5/tomli-2.5.0-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c47300f9bf791808f77d82747691c4bb09cb14bdf3060cca99b42cdc4361d5a7", size = 284910, upload-time = "2026-10-07T12:23:18.166Z" }, + { url = "https://files.pythonhosted.org/packages/cc/05/f4d9cf7de61822ece0c3873f30d291e324911c71a378b8bfe5ced13fd9f5/tomli-2.5.0-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:19b0dd8749f4ea2f112c5fcfb3c5248390c899d7e2e173f1d91abee1fa0ff391", size = 277723, upload-time = "2026-10-07T12:23:19.355Z" }, + { url = "https://files.pythonhosted.org/packages/42/28/78262493141fa543151cf005760c3cb01d09fc28a11f993c05109902cb8c/tomli-2.5.0-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:57b1c3b01fab802e2899bc3d168dca320e14165e2fd9fd584760fb4ca5826859", size = 285115, upload-time = "2026-10-07T12:23:20.698Z" }, + { url = "https://files.pythonhosted.org/packages/1a/b9/e1dab9a30bcb677b5cc5cee810609cfd64f24306a3055767dd3fda00b1e0/tomli-2.5.0-cp315-cp315-win32.whl", hash = "sha256:667e521b37a6c5ccaa044202c235b530f90177ffe2cd4a64ecc213c7dd535feb", size = 103475, upload-time = "2026-10-07T12:23:21.941Z" }, + { url = "https://files.pythonhosted.org/packages/4c/bd/31a3790c11d6ea95fcf5e6022ac0f8d0543c9b61120b730fc481bd43d3b4/tomli-2.5.0-cp315-cp315-win_amd64.whl", hash = "sha256:d747252933c8a65ef6bd8da0fbb7ce28a90eb6119d8cd00772cd528aa07b68d5", size = 114589, upload-time = "2026-10-07T12:23:23.098Z" }, + { url = "https://files.pythonhosted.org/packages/47/a2/4f6310fa699364f0e3af7ee3af88dddd9af066d33e716a0265bbe2b3ea84/tomli-2.5.0-cp315-cp315-win_arm64.whl", hash = "sha256:75dbcde8751b0a960aa3de173aa5e894d590755c6d7758b7e774c06f1dc3cbdd", size = 111493, upload-time = "2026-10-07T12:23:24.233Z" }, + { url = "https://files.pythonhosted.org/packages/68/14/00853f0b396d8971107ae1921bb5b322fdee1650d2f16bf06c20adb532e5/tomli-2.5.0-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:2419c2a189551987b59d80e63ec355671283336f41c6b9b89462df679c7d0c57", size = 171380, upload-time = "2026-10-07T12:23:25.512Z" }, + { url = "https://files.pythonhosted.org/packages/89/ad/fa6949321dadee46b27363974fb197b94c911c3b0f7a5fd26d7dc18fc2a0/tomli-2.5.0-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:0dc598040da8d42cf20f0be588ed7004f46db12a0ac6c32e03a59dccedaaadcd", size = 170553, upload-time = "2026-10-07T12:23:26.855Z" }, + { url = "https://files.pythonhosted.org/packages/53/aa/3056c919eb3e084df3752b2cf5f865dcc04af0b27dba2f66d7b28af4633a/tomli-2.5.0-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49096930c8d886c9bbdab62d2d0d17ce823ddeea522309a190b36245d5b49e01", size = 294428, upload-time = "2026-10-07T12:23:28.132Z" }, + { url = "https://files.pythonhosted.org/packages/96/b2/faeeb5d8769ea3832021d73e892c8391eae7b4b4f8b55a789127bd8b18a9/tomli-2.5.0-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8ade5023067f99fe72b88accd30d0ea05a158e9e32a11f124e731ea9695313f", size = 304909, upload-time = "2026-10-07T12:23:29.381Z" }, + { url = "https://files.pythonhosted.org/packages/f6/52/f094c09e73fb654b621716d019acb5d29bdfd1be01df80c281d552bda48d/tomli-2.5.0-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:b69564772b5c8f22ea5f498dff08cfa825045b4d4c4400529000bdf818aa3b2a", size = 293220, upload-time = "2026-10-07T12:23:30.608Z" }, + { url = "https://files.pythonhosted.org/packages/86/f5/0c30541078ca4b505ce3bd76ed931facbfec524dd018535d691d1af0a6d2/tomli-2.5.0-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:8ff3a2ca028c7eee0c777f9a092038d0a594a9fa04e215f929a22c329e2cb142", size = 305705, upload-time = "2026-10-07T12:23:32.181Z" }, + { url = "https://files.pythonhosted.org/packages/05/74/590e7d19d6a118fc5cc5704ff358e21d95b8573f6b9443b1519f29ca8825/tomli-2.5.0-cp315-cp315t-win32.whl", hash = "sha256:62fc1bc8eb03e3a9cadfca713d65614ed8e09d974a283295ffe3a831976b4dc5", size = 108432, upload-time = "2026-10-07T12:23:33.496Z" }, + { url = "https://files.pythonhosted.org/packages/1c/b8/63a75cfb27a17c38550e44025d3a6e7be64516fd8608a3b75703bf37d81b/tomli-2.5.0-cp315-cp315t-win_amd64.whl", hash = "sha256:f3fcbc57b1791fa6cbe5d8434179d51de12be1a4811469529f47f6e7487a2571", size = 117281, upload-time = "2026-10-07T12:23:34.648Z" }, + { url = "https://files.pythonhosted.org/packages/72/01/e8c1debb2173973372934c68fc8e46170ab60ef23ed4592dff4dec6e8993/tomli-2.5.0-cp315-cp315t-win_arm64.whl", hash = "sha256:d2ba24db8a9376921b5e87b4762b9adb0f3f1deaea68f2b8b0bb2c11efb9c3e7", size = 115069, upload-time = "2026-10-07T12:23:35.77Z" }, + { url = "https://files.pythonhosted.org/packages/60/3f/3e3f8fd0919249b0200c80fbc4f9a1e70be19f9883da71dfb7f8b9ab8aca/tomli-2.5.0-py3-none-any.whl", hash = "sha256:32a7b79ac57a2e83670ce329ccf675798bc5a2094783a63676866b70503f2e2b", size = 14765, upload-time = "2026-10-07T12:23:36.875Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" }, +] + +[[package]] +name = "verbecc" +version = "2.1.0" +source = { editable = "." } +dependencies = [ + { name = "backports-strenum", marker = "python_full_version < '3.11'" }, + { name = "cython" }, + { name = "dataclass-wizard", extra = ["yaml"] }, + { name = "importlib-resources", marker = "python_full_version < '3.13'" }, + { name = "jsbeautifier" }, + { name = "lxml" }, + { name = "lxml-stubs" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, + { name = "numpy", version = "2.5.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "pyaml" }, + { name = "scikit-learn", version = "1.7.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "scikit-learn", version = "1.9.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, + { name = "scipy", version = "1.18.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, +] + +[package.optional-dependencies] +dev = [ + { name = "pytest" }, + { name = "ruff" }, +] + +[package.metadata] +requires-dist = [ + { name = "backports-strenum", marker = "python_full_version < '3.11'", specifier = ">=1.3.1,<2.0" }, + { name = "cython", specifier = ">=3.0.11" }, + { name = "dataclass-wizard", extras = ["yaml"], specifier = ">=0.39.1" }, + { name = "importlib-resources", marker = "python_full_version < '3.13'", specifier = ">=6.4.5" }, + { name = "jsbeautifier", specifier = ">=1.15.4,<2.0" }, + { name = "lxml", specifier = ">=6.0.2" }, + { name = "lxml-stubs", specifier = ">=0.5.1" }, + { name = "numpy", marker = "python_full_version < '3.10'", specifier = ">=1.26.4" }, + { name = "numpy", marker = "python_full_version >= '3.10'", specifier = ">=2.0.2" }, + { name = "pyaml", specifier = ">=25.7.0" }, + { name = "pytest", marker = "extra == 'dev'", specifier = ">=9.1.1" }, + { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.1.0" }, + { name = "scikit-learn", marker = "python_full_version < '3.11'", specifier = ">=1.6.1" }, + { name = "scikit-learn", marker = "python_full_version >= '3.11'", specifier = ">=1.7.2" }, + { name = "scipy", marker = "python_full_version < '3.10'", specifier = ">=1.13.1" }, + { name = "scipy", marker = "python_full_version >= '3.10'", specifier = ">=1.15.3" }, +] +provides-extras = ["dev"] diff --git a/verbecc/__init__.py b/verbecc/__init__.py deleted file mode 100755 index e7ff8d4..0000000 --- a/verbecc/__init__.py +++ /dev/null @@ -1,88 +0,0 @@ -from verbecc.src.conjugator.complete_conjugator import CompleteConjugator -from verbecc.src.conjugator.mood_conjugator import MoodConjugator -from verbecc.src.conjugator.tense_conjugator import TenseConjugator -from verbecc.src.defs.constants import grammar_defines -from verbecc.src.defs.constants.grammar_defines import SUPPORTED_LANGUAGES -from verbecc.src.defs.constants import localization -from verbecc.src.defs.types.config.verbecc_config import VerbeccConfig -from verbecc.src.defs.types.config.jsbeautifier_opts import JSBeautifierOpts -from verbecc.src.utils.config.verbecc_config_util import VerbeccConfigUtil -from verbecc.src.utils.logging_utils import LoggingUtils -from verbecc.src.defs.types.conjugation import CompleteConjugation -from verbecc.src.defs.types.conjugation.complete_conjugation import ( - CompleteConjugationData, -) -from verbecc.src.defs.types.conjugation.conjugation import Conjugation -from verbecc.src.defs.types.conjugation.conjugation_data import ConjugationData -from verbecc.src.defs.types.exceptions.conjugations_parser_error import ( - ConjugationsParserError, -) -from verbecc.src.defs.types.data.conjugation_template import ConjugationTemplate -from verbecc.src.defs.types.exceptions.conjugation_template_error import ( - ConjugationTemplateError, -) -from verbecc.src.defs.types.exceptions.conjugator_error import ConjugatorError -from verbecc.src.defs.types.data.element import Element -from verbecc.src.defs.types.gender import Gender -from verbecc.src.defs.types.exceptions.invalid_lang_error import InvalidLangError -from verbecc.src.defs.types.exceptions.invalid_mood_error import InvalidMoodError -from verbecc.src.defs.types.exceptions.invalid_tense_error import InvalidTenseError -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 -from verbecc.src.defs.types.lang_specific_options import LangSpecificOptions -from verbecc.src.defs.types.lang_specific_options.lang.es.lang_specific_options_es import ( - LangSpecificOptionsEs, -) -from verbecc.src.defs.types.mood.mood import Mood -from verbecc.src.defs.types.mood.lang.mood_ca import MoodCa -from verbecc.src.defs.types.conjugation.mood_conjugation import MoodConjugation -from verbecc.src.defs.types.conjugation.mood_conjugation_data import MoodConjugationData -from verbecc.src.defs.types.mood.lang.mood_es import MoodEs -from verbecc.src.defs.types.mood.lang.mood_fr import MoodFr -from verbecc.src.defs.types.mood.lang.mood_it import MoodIt -from verbecc.src.defs.types.mood.lang.mood_pt import MoodPt -from verbecc.src.defs.types.mood.lang.mood_ro import MoodRo -from verbecc.src.defs.types.mood.moods import Moods -from verbecc.src.defs.types.mood.mood_factory import MoodFactory -from verbecc.src.defs.types.conjugation.moods_conjugation import MoodsConjugation -from verbecc.src.defs.types.conjugation.moods_conjugation_data import ( - MoodsConjugationData, -) -from verbecc.src.defs.types.data.mood_template import MoodTemplate -from verbecc.src.defs.types.number import Number -from verbecc.src.defs.types.person import Person -from verbecc.src.defs.types.data.person_ending import PersonEnding -from verbecc.src.defs.types.exceptions.template_not_found_error import ( - TemplateNotFoundError, -) -from verbecc.src.defs.types.tense.tense import Tense -from verbecc.src.defs.types.tense.lang.tense_ca import TenseCa -from verbecc.src.defs.types.conjugation.tense_conjugation import TenseConjugation -from verbecc.src.defs.types.conjugation.tense_conjugation_data import ( - TenseConjugationData, -) -from verbecc.src.defs.types.tense.lang.tense_es import TenseEs -from verbecc.src.defs.types.tense.lang.tense_fr import TenseFr -from verbecc.src.defs.types.tense.lang.tense_it import TenseIt -from verbecc.src.defs.types.tense.lang.tense_pt import TensePt -from verbecc.src.defs.types.tense.lang.tense_ro import TenseRo -from verbecc.src.defs.types.tense.tenses import Tenses -from verbecc.src.defs.types.tense.tense_factory import TenseFactory -from verbecc.src.defs.types.data.tense_template import TenseTemplate -from verbecc.src.defs.types.data.verb import Verb -from verbecc.src.defs.types.conjugation.verb_info import VerbInfo -from verbecc.src.defs.types.conjugation.verb_info_data import VerbInfoData -from verbecc.src.defs.types.exceptions.verb_not_found_error import VerbNotFoundError -from verbecc.src.defs.types.data.verbs import Verbs -from verbecc.src.defs.types.lang_specific_options.lang.es.voseo_options import ( - VoseoOptions, -) -from verbecc.src.defs.types.pronoun.pronoun import Pronoun -from verbecc.src.defs.types.pronoun.pronouns import Pronouns -from verbecc.src.defs.types.pronoun.pronoun_factory import PronounFactory -from verbecc.src.defs.types.pronoun.lang.pronoun_ca import PronounCa -from verbecc.src.defs.types.pronoun.lang.pronoun_en import PronounEn -from verbecc.src.defs.types.pronoun.lang.pronoun_es import PronounEs -from verbecc.src.defs.types.pronoun.lang.pronoun_fr import PronounFr -from verbecc.src.defs.types.pronoun.lang.pronoun_it import PronounIt -from verbecc.src.defs.types.pronoun.lang.pronoun_pt import PronounPt -from verbecc.src.defs.types.pronoun.lang.pronoun_ro import PronounRo diff --git a/verbecc/src/defs/types/config/logging/__init__.py b/verbecc/src/defs/types/config/logging/__init__.py deleted file mode 100644 index e27ca25..0000000 --- a/verbecc/src/defs/types/config/logging/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -from verbecc.src.defs.types.config.logging.logging_config import LoggingConfig -from verbecc.src.defs.types.config.logging.formatter_config import FormatterConfig -from verbecc.src.defs.types.config.logging.stream_handler_config import ( - StreamHandlerConfig, -) -from verbecc.src.defs.types.config.logging.file_handler_config import FileHandlerConfig -from verbecc.src.defs.types.config.logging.handler_config import HandlerConfig -from verbecc.src.defs.types.config.logging.logger_config import LoggerConfig diff --git a/verbecc/src/defs/types/config/logging/logging_config.py b/verbecc/src/defs/types/config/logging/logging_config.py deleted file mode 100644 index 1c878c1..0000000 --- a/verbecc/src/defs/types/config/logging/logging_config.py +++ /dev/null @@ -1,25 +0,0 @@ -from dataclasses import dataclass, field -from typing import Dict, Optional - -from verbecc.src.defs.types.config.logging.formatter_config import FormatterConfig -from verbecc.src.defs.types.config.logging.stream_handler_config import ( - StreamHandlerConfig, -) -from verbecc.src.defs.types.config.logging.file_handler_config import FileHandlerConfig -from verbecc.src.defs.types.config.logging.handler_config import HandlerConfig -from verbecc.src.defs.types.config.logging.logger_config import LoggerConfig - - -@dataclass -class LoggingConfig: - version: int = field(default=1) - disable_existing_loggers: bool = field(default=False) - formatters: Dict[str, FormatterConfig] = field(default_factory=dict) - handlers: Dict[str, HandlerConfig] = field( - default_factory=lambda: { - "consoleHandler": StreamHandlerConfig(), - "fileHandler": FileHandlerConfig(), - } - ) - loggers: Dict[str, LoggerConfig] = field(default_factory=dict) - root: Optional[LoggerConfig] = field(default_factory=LoggerConfig) diff --git a/verbecc/src/defs/types/conjugation/__init__.py b/verbecc/src/defs/types/conjugation/__init__.py deleted file mode 100644 index 4bd63d1..0000000 --- a/verbecc/src/defs/types/conjugation/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -from verbecc.src.defs.types.conjugation.conjugation import Conjugation -from verbecc.src.defs.types.conjugation.conjugation_data import ConjugationData -from verbecc.src.defs.types.conjugation.abstract_conjugation import AbstractConjugation -from verbecc.src.defs.types.conjugation.verb_info import VerbInfo -from verbecc.src.defs.types.conjugation.verb_info_data import VerbInfoData -from verbecc.src.defs.types.conjugation.tense_conjugation import TenseConjugation -from verbecc.src.defs.types.conjugation.tense_conjugation_data import ( - TenseConjugationData, -) -from verbecc.src.defs.types.conjugation.mood_conjugation import MoodConjugation -from verbecc.src.defs.types.conjugation.mood_conjugation_data import MoodConjugationData -from verbecc.src.defs.types.conjugation.mood_conjugation_util import MoodConjugationUtil -from verbecc.src.defs.types.conjugation.moods_conjugation import MoodsConjugation -from verbecc.src.defs.types.conjugation.moods_conjugation_data import ( - MoodsConjugationData, -) -from verbecc.src.defs.types.conjugation.complete_conjugation import CompleteConjugation -from verbecc.src.defs.types.conjugation.complete_conjugation_data import ( - CompleteConjugationData, -) diff --git a/verbecc/src/defs/types/conjugation/complete_conjugation_data.py b/verbecc/src/defs/types/conjugation/complete_conjugation_data.py deleted file mode 100644 index 0fdc2c1..0000000 --- a/verbecc/src/defs/types/conjugation/complete_conjugation_data.py +++ /dev/null @@ -1,8 +0,0 @@ -from typing import Dict, Union - -from verbecc.src.defs.types.conjugation.verb_info_data import VerbInfoData -from verbecc.src.defs.types.conjugation.moods_conjugation_data import ( - MoodsConjugationData, -) - -CompleteConjugationData = Dict[str, Union[VerbInfoData, MoodsConjugationData]] diff --git a/verbecc/src/defs/types/conjugation/mood_conjugation_data.py b/verbecc/src/defs/types/conjugation/mood_conjugation_data.py deleted file mode 100644 index 538fe60..0000000 --- a/verbecc/src/defs/types/conjugation/mood_conjugation_data.py +++ /dev/null @@ -1,8 +0,0 @@ -from typing import Dict - -from verbecc.src.defs.types.tense import Tense -from verbecc.src.defs.types.conjugation.tense_conjugation_data import ( - TenseConjugationData, -) - -MoodConjugationData = Dict[Tense, TenseConjugationData] diff --git a/verbecc/src/defs/types/conjugation/moods_conjugation_data.py b/verbecc/src/defs/types/conjugation/moods_conjugation_data.py deleted file mode 100644 index 27b55de..0000000 --- a/verbecc/src/defs/types/conjugation/moods_conjugation_data.py +++ /dev/null @@ -1,6 +0,0 @@ -from typing import Dict - -from verbecc.src.defs.types.mood import Mood -from verbecc.src.defs.types.conjugation.mood_conjugation_data import MoodConjugationData - -MoodsConjugationData = Dict[Mood, MoodConjugationData] # the "moods" section diff --git a/verbecc/src/defs/types/conjugation/tense_conjugation_data.py b/verbecc/src/defs/types/conjugation/tense_conjugation_data.py deleted file mode 100644 index cbb6bd5..0000000 --- a/verbecc/src/defs/types/conjugation/tense_conjugation_data.py +++ /dev/null @@ -1,5 +0,0 @@ -from typing import List - -from verbecc.src.defs.types.conjugation.conjugation_data import ConjugationData - -TenseConjugationData = List[ConjugationData] diff --git a/verbecc/src/defs/types/conjugation/verb_info_data.py b/verbecc/src/defs/types/conjugation/verb_info_data.py deleted file mode 100644 index 0e70dbe..0000000 --- a/verbecc/src/defs/types/conjugation/verb_info_data.py +++ /dev/null @@ -1,3 +0,0 @@ -from typing import Dict, Union - -VerbInfoData = Dict[str, Union[str, bool, float]] # the "verb" section diff --git a/verbecc/src/defs/types/data/mood_template.py b/verbecc/src/defs/types/data/mood_template.py deleted file mode 100644 index 86c7e9b..0000000 --- a/verbecc/src/defs/types/data/mood_template.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Dict - -from verbecc.src.defs.types.data.element import Element -from verbecc.src.defs.types.data.tense_template import TenseTemplate -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 as Lang -from verbecc.src.defs.types.mood import Mood -from verbecc.src.defs.types.tense import Tense - - -class MoodTemplate(Element): - def __init__( - self, lang: Lang, mood: Mood, tense_templates: Dict[Tense, TenseTemplate] - ) -> None: - self.lang = lang - self.mood = mood - self.tense_templates = tense_templates - - def __repr__(self) -> str: - return ( - f"lang={self.lang} mood={self.mood} tense_templates={self.tense_templates}" - ) diff --git a/verbecc/src/defs/types/exceptions/__init__.py b/verbecc/src/defs/types/exceptions/__init__.py deleted file mode 100644 index 92865ca..0000000 --- a/verbecc/src/defs/types/exceptions/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -from verbecc.src.defs.types.exceptions.conjugator_error import ConjugatorError -from verbecc.src.defs.types.exceptions.conjugations_parser_error import ( - ConjugationsParserError, -) -from verbecc.src.defs.types.exceptions.conjugation_template_error import ( - ConjugationTemplateError, -) -from verbecc.src.defs.types.exceptions.invalid_lang_error import InvalidLangError -from verbecc.src.defs.types.exceptions.invalid_mood_error import InvalidMoodError -from verbecc.src.defs.types.exceptions.invalid_tense_error import InvalidTenseError -from verbecc.src.defs.types.exceptions.template_not_found_error import ( - TemplateNotFoundError, -) -from verbecc.src.defs.types.exceptions.verb_not_found_error import VerbNotFoundError -from verbecc.src.defs.types.exceptions.verbs_parser_error import VerbsParserError diff --git a/verbecc/src/defs/types/lang_specific_options/__init__.py b/verbecc/src/defs/types/lang_specific_options/__init__.py deleted file mode 100644 index a4513b0..0000000 --- a/verbecc/src/defs/types/lang_specific_options/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -from verbecc.src.defs.types.lang_specific_options.lang_specific_options import ( - LangSpecificOptions, -) -from verbecc.src.defs.types.lang_specific_options.lang.es.lang_specific_options_es import ( - LangSpecificOptionsEs, -) -from verbecc.src.defs.types.lang_specific_options.lang_specific_options_factory import ( - LangSpecificOptionsFactory, -) -from verbecc.src.defs.types.lang_specific_options.lang.es.voseo_options import ( - VoseoOptions, -) diff --git a/verbecc/src/defs/types/mood/__init__.py b/verbecc/src/defs/types/mood/__init__.py deleted file mode 100644 index 031ee74..0000000 --- a/verbecc/src/defs/types/mood/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -from verbecc.src.defs.types.mood.mood import Mood -from verbecc.src.defs.types.mood.moods import Moods -from verbecc.src.defs.types.mood.mood_factory import MoodFactory -from verbecc.src.defs.types.mood.lang.mood_ca import MoodCa -from verbecc.src.defs.types.mood.lang.mood_en import MoodEn -from verbecc.src.defs.types.mood.lang.mood_es import MoodEs -from verbecc.src.defs.types.mood.lang.mood_fr import MoodFr -from verbecc.src.defs.types.mood.lang.mood_it import MoodIt -from verbecc.src.defs.types.mood.lang.mood_pt import MoodPt -from verbecc.src.defs.types.mood.lang.mood_ro import MoodRo diff --git a/verbecc/src/defs/types/mood/moods.py b/verbecc/src/defs/types/mood/moods.py deleted file mode 100644 index 02591be..0000000 --- a/verbecc/src/defs/types/mood/moods.py +++ /dev/null @@ -1,17 +0,0 @@ -from verbecc.src.defs.types.mood.lang.mood_ca import MoodCa -from verbecc.src.defs.types.mood.lang.mood_en import MoodEn -from verbecc.src.defs.types.mood.lang.mood_es import MoodEs -from verbecc.src.defs.types.mood.lang.mood_fr import MoodFr -from verbecc.src.defs.types.mood.lang.mood_it import MoodIt -from verbecc.src.defs.types.mood.lang.mood_pt import MoodPt -from verbecc.src.defs.types.mood.lang.mood_ro import MoodRo - - -class Moods: - ca = MoodCa - en = MoodEn - es = MoodEs - fr = MoodFr - it = MoodIt - pt = MoodPt - ro = MoodRo diff --git a/verbecc/src/defs/types/pronoun/__init__.py b/verbecc/src/defs/types/pronoun/__init__.py deleted file mode 100644 index ffba431..0000000 --- a/verbecc/src/defs/types/pronoun/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -from verbecc.src.defs.types.pronoun.pronoun import Pronoun -from verbecc.src.defs.types.pronoun.pronouns import Pronouns -from verbecc.src.defs.types.pronoun.pronoun_factory import PronounFactory -from verbecc.src.defs.types.pronoun.lang.pronoun_ca import PronounCa -from verbecc.src.defs.types.pronoun.lang.pronoun_en import PronounEn -from verbecc.src.defs.types.pronoun.lang.pronoun_es import PronounEs -from verbecc.src.defs.types.pronoun.lang.pronoun_fr import PronounFr -from verbecc.src.defs.types.pronoun.lang.pronoun_it import PronounIt -from verbecc.src.defs.types.pronoun.lang.pronoun_pt import PronounPt -from verbecc.src.defs.types.pronoun.lang.pronoun_ro import PronounRo diff --git a/verbecc/src/defs/types/pronoun/pronouns.py b/verbecc/src/defs/types/pronoun/pronouns.py deleted file mode 100644 index f0da025..0000000 --- a/verbecc/src/defs/types/pronoun/pronouns.py +++ /dev/null @@ -1,17 +0,0 @@ -from verbecc.src.defs.types.pronoun.lang.pronoun_ca import PronounCa -from verbecc.src.defs.types.pronoun.lang.pronoun_en import PronounEn -from verbecc.src.defs.types.pronoun.lang.pronoun_es import PronounEs -from verbecc.src.defs.types.pronoun.lang.pronoun_fr import PronounFr -from verbecc.src.defs.types.pronoun.lang.pronoun_it import PronounIt -from verbecc.src.defs.types.pronoun.lang.pronoun_pt import PronounPt -from verbecc.src.defs.types.pronoun.lang.pronoun_ro import PronounRo - - -class Pronouns: - ca = PronounCa - en = PronounEn - es = PronounEs - fr = PronounFr - it = PronounIt - pt = PronounPt - ro = PronounRo diff --git a/verbecc/src/defs/types/tense/__init__.py b/verbecc/src/defs/types/tense/__init__.py deleted file mode 100644 index 0a2b8ed..0000000 --- a/verbecc/src/defs/types/tense/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -from verbecc.src.defs.types.tense.tense import Tense -from verbecc.src.defs.types.tense.tenses import Tenses -from verbecc.src.defs.types.tense.tense_factory import TenseFactory -from verbecc.src.defs.types.tense.lang.tense_ca import TenseCa -from verbecc.src.defs.types.tense.lang.tense_en import TenseEn -from verbecc.src.defs.types.tense.lang.tense_es import TenseEs -from verbecc.src.defs.types.tense.lang.tense_fr import TenseFr -from verbecc.src.defs.types.tense.lang.tense_it import TenseIt -from verbecc.src.defs.types.tense.lang.tense_pt import TensePt -from verbecc.src.defs.types.tense.lang.tense_ro import TenseRo diff --git a/verbecc/src/defs/types/tense/tenses.py b/verbecc/src/defs/types/tense/tenses.py deleted file mode 100644 index 1aade1a..0000000 --- a/verbecc/src/defs/types/tense/tenses.py +++ /dev/null @@ -1,17 +0,0 @@ -from verbecc.src.defs.types.tense.lang.tense_ca import TenseCa -from verbecc.src.defs.types.tense.lang.tense_en import TenseEn -from verbecc.src.defs.types.tense.lang.tense_es import TenseEs -from verbecc.src.defs.types.tense.lang.tense_fr import TenseFr -from verbecc.src.defs.types.tense.lang.tense_it import TenseIt -from verbecc.src.defs.types.tense.lang.tense_pt import TensePt -from verbecc.src.defs.types.tense.lang.tense_ro import TenseRo - - -class Tenses: - ca = TenseCa - en = TenseEn - es = TenseEs - fr = TenseFr - it = TenseIt - pt = TensePt - ro = TenseRo diff --git a/verbecc/src/parsers/conjugation_template_parser.py b/verbecc/src/parsers/conjugation_template_parser.py deleted file mode 100755 index 360c312..0000000 --- a/verbecc/src/parsers/conjugation_template_parser.py +++ /dev/null @@ -1,45 +0,0 @@ -from lxml import etree -from typing import Dict, Optional - - -from verbecc.src.defs.types.data.conjugation_template import ConjugationTemplate -from verbecc.src.defs.types.data.mood_template import MoodTemplate -from verbecc.src.defs.types.exceptions import ConjugationTemplateError -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 as Lang -from verbecc.src.defs.types.mood import Mood, MoodFactory -from verbecc.src.parsers.mood_template_parser import MoodTemplateParser -from verbecc.src.parsers.parser import Parser - - -class ConjugationTemplateParser(Parser): - def __init__(self, lang: Lang) -> None: - self.lang = lang - - def parse(self, elem: Optional[etree._Element] = None) -> ConjugationTemplate: - if elem is None: - raise ValueError("elem must not be None") - if elem.tag != "template": - raise ConjugationTemplateError("Unexpected element") - try: - name_attrib = elem.get("name", default=None) - name = str(name_attrib) - mood_templates: Dict[Mood, MoodTemplate] = {} - for mood_elem in elem: - mood_template = MoodTemplateParser(lang=self.lang).parse(mood_elem) - mood = MoodFactory.from_string(self.lang, mood_elem.tag.lower()) - mood_templates[mood] = mood_template - modify_stem = "" - modify_stem_attrib = elem.get("modify-stem", default=None) - if modify_stem_attrib is not None: - modify_stem = str(modify_stem_attrib) - if modify_stem not in ("strip-accents"): - raise ConjugationTemplateError( - "Invalid 'modify-stem' attribute value '{self.modify_stem}'" - ) - else: - modify_stem = "" - return ConjugationTemplate(self.lang, name, mood_templates, modify_stem) - except AttributeError as e: - raise ConjugationTemplateError( - "Error parsing {}: {}".format(etree.tostring(elem), str(e)) - ) diff --git a/verbecc/src/parsers/mood_template_parser.py b/verbecc/src/parsers/mood_template_parser.py deleted file mode 100755 index 82a40cb..0000000 --- a/verbecc/src/parsers/mood_template_parser.py +++ /dev/null @@ -1,28 +0,0 @@ -from lxml import etree -from typing import Dict, Optional - -from verbecc.src.defs.types.data.mood_template import MoodTemplate -from verbecc.src.defs.types.data.tense_template import TenseTemplate -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 as Lang -from verbecc.src.defs.types.mood import MoodFactory -from verbecc.src.defs.types.tense import TenseFactory -from verbecc.src.defs.types.tense import Tense -from verbecc.src.parsers.parser import Parser -from verbecc.src.parsers.tense_template_parser import TenseTemplateParser - - -class MoodTemplateParser(Parser): - def __init__(self, lang: Lang) -> None: - self.lang = lang - - def parse(self, elem: Optional[etree._Element] = None) -> MoodTemplate: - if elem is None: - raise ValueError - mood = MoodFactory.from_string(self.lang, elem.tag.lower()) - tense_templates: Dict[Tense, TenseTemplate] = {} - for tense_elem in elem: - tense = TenseFactory.from_string(self.lang, tense_elem.tag.lower()) - tense_templates[tense] = TenseTemplateParser( - lang=self.lang, mood=mood - ).parse(tense_elem) - return MoodTemplate(self.lang, mood, tense_templates) diff --git a/verbecc/src/parsers/parser.py b/verbecc/src/parsers/parser.py deleted file mode 100644 index 19b651f..0000000 --- a/verbecc/src/parsers/parser.py +++ /dev/null @@ -1,12 +0,0 @@ -from abc import ABC, abstractmethod -from lxml import etree -from typing import Optional - -from verbecc.src.defs.types.data.element import Element - - -class Parser(ABC): - - @abstractmethod - def parse(self, elem: Optional[etree._Element] = None) -> Element: - pass diff --git a/verbecc/src/parsers/verb_parser.py b/verbecc/src/parsers/verb_parser.py deleted file mode 100755 index 24eeda1..0000000 --- a/verbecc/src/parsers/verb_parser.py +++ /dev/null @@ -1,38 +0,0 @@ -from lxml import etree -from typing import Optional - -from verbecc.src.defs.types.data.verb import Verb -from verbecc.src.defs.types.exceptions import VerbsParserError -from verbecc.src.parsers.parser import Parser - - -class VerbParser(Parser): - def __init__(self) -> None: - pass - - def parse(self, elem: Optional[etree._Element] = None) -> Verb: - if elem is None: - raise ValueError("elem must not be None") - infinitive = "" - template = "" - translation_en = "" - if elem.tag != "v": - raise VerbsParserError("Unexpected element") - try: - infinitive = "" - e = elem.find("i", None) - if e is not None: - infinitive = e.text if e.text is not None else "" - template = "" - e = elem.find("t", None) - if e is not None: - template = e.text if e.text is not None else "" - translation_en = "" - e = elem.find("en", None) - if e is not None: - translation_en = e.text if e.text is not None else "" - except AttributeError as e: - raise VerbsParserError( - "Error parsing {}: {}".format(etree.tostring(elem), str(e)) - ) - return Verb(infinitive, template, translation_en) diff --git a/verbecc/src/parsers/verbs_parser.py b/verbecc/src/parsers/verbs_parser.py deleted file mode 100755 index 352295c..0000000 --- a/verbecc/src/parsers/verbs_parser.py +++ /dev/null @@ -1,59 +0,0 @@ -from __future__ import print_function -from lxml import etree -from importlib_resources import as_file, files - -# import gzip -import os - -# import tempfile -from typing import List - -from verbecc.src.defs.types.data.verb import Verb -from verbecc.src.defs.types.data.verbs import Verbs -from verbecc.src.defs.types.exceptions import VerbsParserError -from verbecc.src.defs.types.lang_code import LangCodeISO639_1 -from verbecc.src.parsers.verb_parser import VerbParser - - -class VerbsParser: - def __init__(self, lang: LangCodeISO639_1 = LangCodeISO639_1.fr) -> None: - self.lang = lang - - def parse(self) -> Verbs: - ret: List[Verb] = [] - parser = etree.XMLParser(encoding="utf-8", remove_blank_text=True, remove_comments=True) # type: ignore - source = files("verbecc.data.xml.verbs").joinpath( - "verbs-{}.xml".format(self.lang) - ) - with as_file(source) as fp: - """ - with gzip.open(fp, "rt") as zf: - with tempfile.NamedTemporaryFile( - prefix=f"/tmp/verbs-{lang}.xml.out.", - suffix=".xml", - mode="wt+", - encoding="utf-8", - delete=True, - ) as tf: - next(zf) # Skips the first line (gzip header plus xml header) - # Regenerate xml header - tf.write('' + os.linesep) - for line in zf: - # there are some null bytes at the end that must be stripped - for byte in line: - if not byte.endswith("\x00"): - tf.write(byte) - tf.flush() - tree = etree.parse(tf.name, parser) # type: ignore - """ - tree = etree.parse(fp, parser) # type: ignore - root = tree.getroot() - root_tag = "verbs-{}".format(self.lang) - if root.tag != root_tag: - raise VerbsParserError("Root XML Tag {} Not Found".format(root_tag)) - for child in root: - if child.tag == "v": - ret.append(VerbParser().parse(child)) # type: ignore - - ret = sorted(ret, key=lambda v: v.infinitive) - return Verbs(self.lang, ret) diff --git a/verbecc/src/utils/config/__init__.py b/verbecc/src/utils/config/__init__.py deleted file mode 100644 index 3a050db..0000000 --- a/verbecc/src/utils/config/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from verbecc.src.utils.config.base_config_util import BaseConfigUtil -from verbecc.src.utils.config.logging_config_util import LoggingConfigUtil -from verbecc.src.utils.config.verbecc_config_util import VerbeccConfigUtil