diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0690f69e..c4b8d074 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,18 +42,19 @@ jobs: echo "marker=$marker" >> "$GITHUB_OUTPUT" documentation: - name: Documentation (no compiler) + name: Documentation runs-on: ubuntu-24.04 - timeout-minutes: 15 + timeout-minutes: 30 needs: determine-gate - # The documentation is derivable from the sources alone: KConfig is pure - # Python and the documents are text. Only CMake's top-level project() - # call needs a C toolchain, and nothing here goes through it. So this - # gate installs a Python and the locked dependencies, and nothing else -- - # no poks, no scoop, no cross-compiler. It is the fastest signal in the - # workflow and it covers every variant, where the build jobs cover the - # variants they build. + # The documentation of every variant and kit, in both readers, in strict + # mode, with their needs compared (test/test_docs_gate.py). Nothing is + # compiled, but each cell is CONFIGURED: codelinks takes a variant's + # #ifdef branches from its build's compile database, which only CMake + # writes, and CMake's top-level project() call wants a C/C++ toolchain. + # The runner's gcc, g++, cmake and ninja are enough -- no poks, no scoop, + # no cross-compiler. It covers every variant, where the build jobs cover + # the variants they build. steps: - name: Checkout Code uses: actions/checkout@v6 @@ -71,6 +72,11 @@ jobs: poetry config virtualenvs.in-project true poetry install --no-root + # cmake and gcc are part of the runner image; Ninja is the generator + # the builds use. + - name: Install Ninja + run: sudo apt-get install -y --no-install-recommends ninja-build + # `ubc` is the second reader. Without it the parity tests skip, and # a guarantee that only holds on a developer machine is not a # guarantee -- so the gate installs it and CI_REQUIRE_UBC turns a diff --git a/.gitignore b/.gitignore index dda3759d..012f760d 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,8 @@ # Windows without Developer Mode, a copy) of the configured variant's build # output directory. Generated output, never committed. /generated +# The document rules tools/variant_data.py generates (see ubproject.toml). +/ubproject.variants.toml # Output directory of test results /test/output diff --git a/.vscode/settings.json b/.vscode/settings.json index fb6ee1a3..5da3c738 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -20,10 +20,10 @@ // the edit is the only guard rail that also applies to an assistant. "files.readonlyInclude": { "build/**": true, - "generated/**": true + "generated/**": true, + "ubproject.variants.toml": true }, "cmake.buildDirectory": "${workspaceFolder}/build/${variant:variant}/${buildKit}/${buildType}", - "cmake.copyCompileCommands": "${workspaceFolder}/build/compile_commands.json", "cmake.configureSettings": { "BUILD_KIT": "${buildKit}", "CMAKE_MESSAGE_LOG_LEVEL": "STATUS", diff --git a/AGENTS.md b/AGENTS.md index 62524b2d..9178b41f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -64,9 +64,10 @@ build everyone gets. The override is for the span of one change, not a working mode. `pyproject.toml` currently pins a **commit of the useblocks fork** of spl-core -(branch `feat/configurable-docs-pipeline`, based on spl-core 8.9.0). It carries +(branch `feat/docs-parity-sweep`, stacked on `feat/configurable-docs-pipeline`, based on spl-core 8.9.0). It carries the documentation changes this project relies on: `SPL_SOURCE_DOCS_JINJA_RAW_TAGS`, -`SPL_VARIANT_DATA_FILE_DOCS` / `_REPORTS`, `SPL_SPHINX_BINARY_DIR` and +`SPL_SPHINX_BINARY_DIR`, `SPL_SPHINX_OPTIONS` / `SPL_SPHINX_COMPONENT_OPTIONS`, +`SPL_TEST_RESULTS_AS_NEEDS` with its JUnit converter, and `KConfig.declared_boolean_symbols()`. Pinning a commit keeps every build on the same code. Switch back to a PyPI release once upstream spl-core has released them. @@ -124,7 +125,7 @@ CI runs on **GitHub Actions** (`.github/workflows/ci.yml`) for every push/PR to Jobs: - `determine-gate` — computes the `gate_*` quality-gate marker once (by event/branch) and shares it with all four jobs via `needs`. -- `documentation` (`ubuntu-24.04`) — the compiler-free gate: a Python and the locked dependencies, then `pytest -m "docs and "`. It generates the variant data for **every** variant and builds each one's documents, where the build jobs only cover the variants they build. No poks, no scoop, no cross-compiler, so it is also the fastest signal in the workflow. +- `documentation` (`ubuntu-24.04`) — the documentation gate: a Python and the locked dependencies, then `pytest -m "docs and "`. It configures **every** variant and kit (the runner's gcc, g++, cmake and ninja; no poks, no scoop, no compiling), so codelinks takes each variant's `#ifdef` branches, and builds each one's documents in both readers in strict mode, comparing their needs. It is also the fastest signal in the workflow. - `test-on-windows` (`windows-2025`) — `build.ps1 -install` then `-selftests -marker `. - `test-on-linux` (`ubuntu-24.04`) — bare-runner path: `bootstrap_ubuntu.sh` + `bootstrap_python.sh`, then `build.sh --install` and `--selftests --marker `. - `test-devcontainer` (`ubuntu-24.04`) — builds `.devcontainer/` via `devcontainers/ci` (which runs `onCreateCommand`, i.e. `build.sh --install`) and runs `build.sh --selftests --marker ` inside the container. @@ -183,41 +184,59 @@ clanguru wrap their code in Jinja `{% raw %}` markers for projects that do render through Jinja; `CMakeLists.txt` turns that off (`SPL_SOURCE_DOCS_JINJA_RAW_TAGS`), so no `source-read` handler exists at all. -Everything variant-dependent is decided from **one file**: the variant data -that `tools/variant_data.py` writes, exposed as `var.*`. The governing rule: +### What decides what a reader shows + +A selection step runs before any reader: CMake configure, or +`tools/variant_data.py` on its own. It writes every file that decides what +ubCode, `ubc` and the Sphinx build show, and each reader takes them from there. +Nothing is decided on the command line or in `conf.py`, and nothing per +component is maintained by hand. + +| File | Holds | Read by | +| --- | --- | --- | +| `build/variants///.json` | the variant data, `var.*`; one cell per variant, kit and build shape | both, through the selection | +| `build/variants////.json` | the same, for one component's report (`scope = "component"`) | both, through that report's selection | +| `ubproject.variants.toml` (project root, git-ignored) | one document rule per documented component, derived from where its documentation lives | ubCode through `extend` in ubproject.toml; sphinx-mounts through `sources_from_toml` | +| `build/selection.toml` | the selected build: its cell's variant data file and the mount of its build directory at `generated` | ubCode through the rules file's `extend`; Sphinx through conf.py | +| `/selection/[/].toml` | the same, for each documentation run spl-core starts in that build | Sphinx with `-D spl_selection=`, ubc with `-c "$(cat )"` | + +The governing rule is unchanged: > **Everything a condition may name has to be IN the variant data file.** A key that only `conf.py` knows is invisible to ubCode, `ubc` and a reviewer's -editor, so their view of the project silently disagrees with the build — -silently, because a condition a tool cannot evaluate gates content **off** -rather than failing. That is why `conf.py` does not touch the file at all: -sphinx-needs reads it, and which cell a build reads is a command-line override -(`-D needs_variant_data_file=...`), exactly as for `ubc`. +editor, so their view of the project disagrees with the build. A condition a +tool cannot evaluate gates its content **off**: the reader warns and carries on +without it. That is why `conf.py` computes nothing: it hands the selection's +keys to the two Sphinx extensions that cannot follow `extend`, and that is all. -### The three mechanisms +### The mechanisms -**Whole documents: `[[source.variant_sources]]` in `ubproject.toml`.** One rule -per component, gated on membership of the variant's component list: +**Whole documents: the generated rules.** `tools/variant_data.py` writes one rule +per component that has a `doc/index` page, gated on membership of the variant's +component list: ```toml [[source.variant_sources]] -if = "'components/auto_off' in var.build_config.components" -files = [ - "components/auto_off/doc/**", - "generated/components/auto_off/reports/**", - "generated/components/auto_off/__source_docs/**", -] +if = "'components/auto_off' in var.build_config.components and (var.build_config.scope == 'variant' or var.build_config.component == 'components/auto_off')" +files = ["components/auto_off/**"] ``` -Membership, never identity. The component list comes from that variant's +The one pattern names the component's documentation in the tree and its +generated pages in a mounted build alike: both readers match a rule's patterns +against the project tree and against each mount's files, relative to the mounted +directory. Membership, never identity. The component list comes from that variant's `parts.cmake`, so the product structure is stated once, in the file that already -states it. **Never gate on the variant name** — that is a second encoding of the -same fact, free to drift. +states it. **Never gate a document on the variant name** — that is a second +encoding of the same fact, free to drift. Rules are *subtractive*: a FALSE rule +removes the files it names, a TRUE rule does nothing. Two more rules decide the +shape of the report: the variant-wide documents (`index.md`, `doc/`) exist only +in a variant's report, `doc/component_report.md` only in a component's. -Rules are *subtractive*: a FALSE rule removes the files it names, a TRUE rule -does nothing. Two rules naming the same file therefore compose as AND, which is -how generated output is gated on both the build shape and the component. +The rules are the same for every variant, and they live in a file of their own +at the project root because sphinx-mounts reads rule patterns relative to the +file that declares them and refuses absolute or `..` ones. Do not edit the file: +change the generator. **Blocks inside a document: the `{if}` directive of Sphinx-Needs.** Four-backtick fence, condition as the argument: @@ -231,8 +250,38 @@ fence, condition as the argument: Content behind a false condition is never parsed, so its needs never enter the traceability data. -**External trees: `[[source.mounts]]`.** Currently unused. Everything this -project shows lives in the tree or under `generated/`. +**The generated pages: a mount of the selected build.** The selection mounts the +build directory at `generated`, where spl-core names every page it generates +(`SPL_SPHINX_BINARY_DIR` in CMakeLists.txt): + +```toml +[[source.mounts]] +dir = "/build/Disco/test/Debug" +mount_at = "generated" +include = ["components/**/*.rst", "test/**/*.rst", "reports/*.rst"] +gitignore = false +if = 'var.build_config.target == "reports" and var.build_config.variant == "Disco" and var.build_config.kit == "test"' +``` + +The mount's condition does name a variant: the build's own. A reader pointed at +another variant's data then reads none of this build's pages, instead of showing +them as that variant's. No link, no junction, no copy: each build keeps its +pages in its own directory, so two builds' reports can be built side by side, +and `ubc diff -c "$(cat build/Spa/test/Debug/selection/reports.toml)"` compares +the selected build with another. + +**Implementation needs in the code: one-line comments.** `// @need , <id>, +impl, [<implements>], [<fulfills>]` above the code, shown on the component's page +by `src-trace` (`:project: components`, `:directory: <component>`). codelinks +takes the `#ifdef` branches from `build/compile_commands.json`, which +`tools/compile_commands.py` copies from the selected build without the +`-save-temps` libclang rejects. + +**Test results: needs.json.** spl-core converts each component's JUnit XML into +`unit_test_results.needs.json` after the test run (`SPL_TEST_RESULTS_AS_NEEDS`) +and writes the page that imports it, with the test specifications' `results` +links as `needextend` blocks. Both readers import them; sphinx-test-reports and +the `sple_tr_link` needs function are gone. ### What the data holds @@ -243,23 +292,25 @@ project shows lives in the tree or under `generated/`. | `var.build_config.kit` | `prod` or `test` | | `var.build_config.target` | `docs` or `reports` | | `var.build_config.components` | the variant's component list, from `parts.cmake` | +| `var.build_config.scope` | `variant`, or `component` for a per-component report | +| `var.build_config.component` | that component's path, empty for a variant | ### Two differences between the engines The `{if}` directive takes a real Python expression, so a bare -`var.features.BLINKING` is enough. A `variant_sources` condition uses a -restricted grammar that needs `== True`. And a condition that cannot be -evaluated **excludes** what it gates, so a typo silently shrinks the document -set rather than failing loudly — which is what `test_ubproject_config.py` is -for. +`var.features.BLINKING` is enough. A rule condition uses a restricted grammar +that needs `== True`. And a condition that cannot be evaluated **excludes** what +it gates: Sphinx warns (sphinx-needs for an `{if}` block, sphinx-mounts for a +rule) and builds on without that content — which is what +`test_ubproject_config.py` is for. ### Checking with the other reader -The Sphinx build is only half the story: the point of keeping everything in the -variant data file is that a reader which never runs `conf.py` decides the same -things. `ubc` is that reader, and `pytest -m docs -k ubc` proves it — per -variant, it asserts that ubCode removes **exactly** the component documents the -variant's component list omits. +The Sphinx build is only half the story: the point of generating everything into +files is that a reader which never runs `conf.py` decides the same things. `ubc` +is that reader, and `pytest -m docs -k ubc` proves it — per variant, it asserts +that ubCode removes **exactly** the component documents the variant's component +list omits. `ubc` ships inside the ubCode VS Code extension and is on neither PyPI nor npm, so there is no install step this repository can own. The tests find it on @@ -271,73 +322,62 @@ export UBC="$HOME/.vscode/extensions/useblocks.ubcode-0.35.0-darwin-arm64/server pytest -m docs -k ubc ``` -To look at one variant by hand, override the data file rather than switching -the project: +To look at another cell without switching the project, override the data file, +or hand a build's own selection file over whole: ```bash ubc check -c "needs.variant_data_file = 'build/variants/Sleep/test/docs.json'" +ubc check -c "$(cat build/Spa/test/Debug/selection/reports.toml)" +sphinx-build -b html -D needs_variant_data_file=build/variants/Sleep/test/docs.json . out +sphinx-build -b html -D spl_selection=build/Spa/test/Debug/selection/reports.toml . out ``` -Two things to know about `ubproject.toml` when editing it. Configuring parsers +Three things to know about `ubproject.toml` when editing it. Configuring parsers puts ubCode in **parser mode**, where the document set comes from each `[parse.parsers.*].include` and `[source] extend_include` is *ignored* — so the parser includes have to stay in step with `include_patterns` in `conf.py`, or -the two readers are looking at different files. And `[[source.variant_sources]]` -rules are implemented as exclusions, which is why a rule that cannot be -evaluated removes what it gates. +the two readers are looking at different files. The rst include is written +relative to the mounted build directory, because that is what ubCode matches it +against. And `extend` merges tables key by key but replaces arrays, so the +committed file declares no rules and no mounts: they would replace the generated +ones. + +**Known gap.** ubCode does not mount a directory inside the project root, and +every CMake build lives under `build/`: until ubCode can, the IDE and `ubc` show +no generated page (test results, test specifications, listings). Sphinx reads +them. Everything else — the documents, the rules, the implementation needs — +agrees need for need. ### Adding a component 1. Add it to the variant's `parts.cmake`. -2. Add one `[[source.variant_sources]]` rule in `ubproject.toml`. -3. Add one line to the 150% toctree in `doc/components/index.md`. +2. Write its documentation in `<component>/doc/index.md`, with a `## Traceability` + section (`src-trace`) and a `## Verification` section inside + `{if} var.build_config.target == "reports"`, as the other components do. -Nothing is generated, no loop is edited, and nothing under `build/` is touched. +The next selection writes its rule, and the glob toctree in +`doc/components/index.md` lists it. Nothing else is edited, and nothing under +`build/` is touched. ### Generated output -`build/` and `generated/` are output. **Nobody edits them — not a person, not an -assistant.** The editor is configured to refuse it (`files.readonlyInclude`) and -`build/variants/GENERATED` says so on disk. - -`generated/` is the configured variant's build directory: a symlink (a junction -on Windows without Developer Mode) that `tools/variant_data.py` points at the -build CMake configures. `CMakeLists.txt` hands it to spl-core as -`SPL_SPHINX_BINARY_DIR`, so every page spl-core generates is named through it: -`generated/components/<c>/reports/coverage`, whatever the variant, kit or build -type. The report sections therefore name their pages directly, spl-core writes -each coverage report next to its page, and `SplBuild` finds the report -artifacts where the pages landed. - -The Sphinx build reads generated pages **only** through `generated`: `conf.py` -prunes `build` from its walk, so each page has exactly one name. -`test_generated_is_the_only_route_to_the_generated_pages` guards that. Because -the link is re-pointed on every configure, spl-core stops a documentation build -whose link leads to another build directory. Configure that build again first. - -ubCode does not descend the link, so the IDE shows no generated page. They are -output of the reports target, which stays Sphinx-only while its pages use the -sphinx-test-reports directive. +`build/`, `generated/` and `ubproject.variants.toml` are output. **Nobody edits +them — not a person, not an assistant.** The editor is configured to refuse it +(`files.readonlyInclude`), and `build/variants/GENERATED` and the files' own +headers say so. Regenerate without a compiler — KConfig is pure Python, and CMake's top-level `project()` call demands a C toolchain before it will configure at all: ```bash -python tools/variant_data.py --all # the whole matrix -python tools/variant_data.py --variant Sleep --kit test # ...and point at one cell -python tools/variant_data.py --all --check # CI: regenerate and diff -``` - -Preview a variant by pointing the build at its cell. It is a command-line -override of the same key `ubc check -c` overrides, and the way spl-core selects -the cell for the docs and reports targets; `conf.py` has no say in it: - -```bash -sphinx-build -b html -D needs_variant_data_file=build/variants/Sleep/test/docs.json . out +python tools/variant_data.py --all # the matrix and the rules +python tools/variant_data.py --all --current --variant Sleep --kit test # ...and select a cell +python tools/variant_data.py --all --check # CI: regenerate and diff ``` -Without the override, a build reads the pointer `build/autoconf.json`, which -exists once CMake or `tools/variant_data.py --variant ... --kit ...` has written it. +Selecting a cell this way writes `build/selection.toml` without a mount, so the +readers show the cell's documents and no generated page. Configuring a CMake +build selects that build, mount included. ## Project-Specific Conventions diff --git a/CMakeLists.txt b/CMakeLists.txt index 632614c4..48419d48 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,11 +49,12 @@ include("${SPL_CORE_DIR}/spl.cmake") # Variant data: one generation step, everything downstream declarative. # # tools/variant_data.py writes build/variants/<Variant>/<kit>/<target>.json for -# every variant, plus build/autoconf.json as the "current" pointer and a -# `generated` symlink to this build directory. It is invoked here so that -# configuring in the IDE keeps the pointer in step with whatever CMake Tools -# selected -- the same role cmake.copyCompileCommands plays for the compilation -# database. +# the variant (and one per component report), the document rules +# ubproject.variants.toml, and the selection of this build: build/selection.toml +# for the IDE and a bare run, and <build>/selection/... for every documentation +# run spl-core starts here. Configuring a build is selecting it, so configuring in +# the IDE keeps the selection in step with whatever CMake Tools selected. A test +# kit build shows its reports, a prod kit build its design documentation. # # It is deliberately a standalone script and not CMake code. KConfig is pure # Python, while the top-level project() call above demands a C toolchain before @@ -74,11 +75,16 @@ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${_SPLED_VARIANT_DATA_SCRIPT} ${CMAKE_SOURCE_DIR}/variants/${VARIANT}/parts.cmake ) +if(BUILD_KIT STREQUAL test) + set(_spled_selected_target reports) +else() + set(_spled_selected_target docs) +endif() execute_process( COMMAND "${_VENV_PYTHON}" ${_SPLED_VARIANT_DATA_SCRIPT} --variant ${VARIANT} --kit ${BUILD_KIT} - --target docs + --target ${_spled_selected_target} --current --build-dir ${CMAKE_BINARY_DIR} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} @@ -94,27 +100,31 @@ endif() # it has to be set before parts.cmake adds the components, which is where # spl-core computes the paths it writes for Sphinx. # -# The variant data file for each build shape. spl-core hands it to sphinx-build -# as `-D needs_variant_data_file=`, so a reports build evaluates its fences -# against the reports cell. `build/autoconf.json`, the pointer ubCode and a bare -# sphinx-build read, always holds the docs cell, so the IDE sees the report -# fences as a clean false. -set(SPL_VARIANT_DATA_FILE_DOCS ${CMAKE_SOURCE_DIR}/build/variants/${VARIANT}/${BUILD_KIT}/docs.json) -set(SPL_VARIANT_DATA_FILE_REPORTS ${CMAKE_SOURCE_DIR}/build/variants/${VARIANT}/${BUILD_KIT}/reports.json) +# Every documentation run spl-core starts names its own selection file, which +# tools/variant_data.py has just written for this build: the variant data file of +# its shape (and component), and the mount of this build directory. conf.py reads +# it, and ubc takes the same file with `-c "$(cat <file>)"`. No run depends on +# which build was configured last, so the reports of two builds can be built side +# by side. +set(SPL_SPHINX_OPTIONS -D spl_selection=${CMAKE_BINARY_DIR}/selection/@SHAPE@.toml) +set(SPL_SPHINX_COMPONENT_OPTIONS -D spl_selection=${CMAKE_BINARY_DIR}/selection/@COMPONENT_PATH@/@SHAPE@.toml) -# Sphinx reaches this build directory through `generated`, the link -# tools/variant_data.py has just pointed at it. The generated report pages are -# therefore named `generated/...` whatever the variant, kit or build type, and -# the report sections name them directly instead of globbing `/build/**`. -# spl-core writes each coverage report next to its page under that name, and -# stops a documentation build whose link has since been re-pointed at another -# build directory. +# The selection mounts this build directory at `generated`, so every page +# spl-core generates is named `generated/...` whatever the variant, kit or build +# type, and the report sections name them directly instead of globbing +# `/build/**`. spl-core writes each coverage report next to its page under that +# name. `generated` does not exist on disk: it is a mount, not a link. set(SPL_SPHINX_BINARY_DIR ${CMAKE_SOURCE_DIR}/generated) # No document is rendered through Jinja, so the source listings clanguru # generates need no `{% raw %}` armour. set(SPL_SOURCE_DOCS_JINJA_RAW_TAGS OFF) +# Test results as needs.json that every reader imports, instead of +# sphinx-test-reports' test-report directive, which only Sphinx knows. The +# results page also carries the `results` links of the test specifications. +set(SPL_TEST_RESULTS_AS_NEEDS ON) + # The object_deps_report extension is currently Windows-only: its index.cmake # hardcodes the runner as "object_deps_report.exe", which does not exist on # Linux/macOS (the console script is "object_deps_report"). Guard the include to @@ -135,3 +145,34 @@ endif() # Include variant specific parts/components definitions include(${PROJECT_SOURCE_DIR}/variants/${VARIANT}/parts.cmake) + +# codelinks reads the selected build's compile database from a fixed path, +# build/compile_commands.json, to take each variant's #ifdef branches. +# tools/compile_commands.py copies it there without `-save-temps`, which libclang +# rejects, and only for the selected build. CMake writes the database at the end +# of configuring, so this runs with every build; after a configure alone, build +# just this target. +add_custom_target(spled_codelinks_compile_commands ALL + COMMAND "${_VENV_PYTHON}" ${CMAKE_SOURCE_DIR}/tools/compile_commands.py --build-dir ${CMAKE_BINARY_DIR} + COMMENT "Handing codelinks the compile database of this build" + VERBATIM +) + +# Every documentation run reads the database, so it waits for the copy. spl-core +# creates those targets at the end of configuring, in a deferred call of its own, +# so this one is deferred as well and runs after it. +function(_spled_documentation_runs_need_the_database) + foreach(_target IN ITEMS docs reports) + if(TARGET ${_target}) + add_dependencies(${_target} spled_codelinks_compile_commands) + endif() + endforeach() + foreach(_component IN LISTS COMPONENT_NAMES) + foreach(_suffix IN ITEMS _docs _report) + if(TARGET ${_component}${_suffix}) + add_dependencies(${_component}${_suffix} spled_codelinks_compile_commands) + endif() + endforeach() + endforeach() +endfunction() +cmake_language(DEFER CALL _spled_documentation_runs_need_the_database) diff --git a/README.md b/README.md index 37abc7a1..59cdc0b8 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,8 @@ For the full testing strategy, marker definitions, and the gate assignment matri ## Variants and their documentation What a variant contains, and what its documentation shows, is decided by data, not by templates. +Selecting a variant generates everything the readers need, so nothing is maintained per component: +adding one is adding it to a variant's `parts.cmake` and writing its documentation. [VARIANTS.md](VARIANTS.md) walks through it by use case: switching the variant ubCode shows, previewing any variant, comparing two variants, trying a change without touching the product, and writing documentation that depends on the variant. diff --git a/VARIANTS.md b/VARIANTS.md index d501d4c8..119eaeaa 100644 --- a/VARIANTS.md +++ b/VARIANTS.md @@ -8,7 +8,10 @@ One set of documents describes every variant, and **data decides what one varian document is a template, and nothing in `conf.py` or CMake decides what a page contains: - a **variant data file** per variant says which features are on and which components are in; -- **conditions** in `ubproject.toml` and in the documents read that file; +- **conditions** read that file: in the documents, and in **rules** that `tools/variant_data.py` + generates from where each component's documentation lives, so no rule is written by hand; +- a **selection** file says which variant data file, and which build's generated pages, the editor + and a plain build show; - **Sphinx** and **ubCode**, with its command-line tool `ubc`, read the same files, so the editor shows what the build produces. @@ -27,7 +30,8 @@ document is a template, and nothing in `conf.py` or CMake decides what a page co | include a document only when its component is in the variant | [12](#12-include-a-document-only-when-its-component-is-in-the-variant) | | put one document in different places per variant | [13](#13-place-one-document-differently-per-variant) | | add a component, a feature or a variant | [14](#14-add-a-component), [15](#15-add-or-change-a-feature), [16](#16-add-a-variant) | -| check my work, or find out why something is missing | [17](#17-run-the-checks), [18](#18-when-something-looks-wrong) | +| link code to the design, per variant | [17](#17-trace-code-to-the-design-per-variant) | +| check my work, or find out why something is missing | [18](#18-run-the-checks), [19](#19-when-something-looks-wrong) | New to SPLed? Go through use cases 1 to 8 once, in order. @@ -40,19 +44,24 @@ flowchart LR C["variants/Sleep/config.txt<br/>the features of a variant"] P["variants/Sleep/parts.cmake<br/>the components of a variant"] end - G(["tools/variant_data.py"]) + G(["tools/variant_data.py<br/>run by CMake configure"]) subgraph gen["Generated, never edited"] V["build/variants/Sleep/test/docs.json<br/>one file per variant, kit and target"] - A["build/autoconf.json<br/>the variant you work on"] + RU["ubproject.variants.toml<br/>one rule per component"] + A["build/selection.toml<br/>the build you work on"] end - R["ubproject.toml and documents<br/>hold the conditions"] + R["documents<br/>hold the {if} conditions"] U["ubCode and ubc"] S["sphinx-build"] K --> G C --> G P --> G G --> V + G --> RU G --> A + A -->|names| V + RU --> U + RU --> S A --> U A --> S R --> U @@ -70,8 +79,9 @@ flowchart LR | **Component** | A folder under `components/`, plus the integration suite `test/spled_integration`. A variant lists its components in its `parts.cmake`. | | **Kit** | `prod`, the product, or `test`, which adds unit tests, coverage and, for Disco, the integration suite. | | **Target** | `docs`, the documents, or `reports`, the documents plus test results and coverage. | -| **Variant data file** | `build/variants/<variant>/<kit>/<target>.json`, one per combination: 5 variants × 2 kits × 2 targets = 20 files. | -| **Pointer** | `build/autoconf.json`, a copy of the variant data file you are working on. ubCode and a plain `sphinx-build` read it. | +| **Variant data file** | `build/variants/<variant>/<kit>/<target>.json`, one per combination: 5 variants × 2 kits × 2 targets = 20 files, plus one per component report under `<kit>/<component>/`. | +| **Rules** | `ubproject.variants.toml`, generated: one rule per component, which leaves the component's documents out of a variant that does not contain it. | +| **Selection** | `build/selection.toml`, generated when a variant is selected: which variant data file the editor and a plain `sphinx-build` read, and, for a CMake build, its generated pages, mounted at `generated`. | | **150 % documentation** | Every document of every variant lives in the tree. Conditions remove what one variant does not have. | | **`var.*`** | How a condition reads the variant data: `var.features.BLINKING`, `var.build_config.components`. | @@ -83,7 +93,9 @@ flowchart LR { "build_config": { "components": ["components/platform_types", "components/rte", "…", "components/brightness_controller", "components/auto_off"], + "component": "", "kit": "test", + "scope": "variant", "target": "docs", "variant": "Sleep" }, @@ -102,6 +114,8 @@ flowchart LR the ones that are off, so a condition on it always has an answer. - `build_config.components` is the variant's component list, read from its `parts.cmake`. - `build_config.variant`, `kit` and `target` say which combination the file describes. +- `build_config.scope` is `variant`, or `component` in the file of a per-component report, whose + `build_config.component` names the component. Everything under `build/` is generated, and nobody edits it; VS Code opens it read-only. To change a variant, change its sources ([15](#15-add-or-change-a-feature), [16](#16-add-a-variant)), or @@ -138,29 +152,31 @@ All commands below run from the repository root, with the virtualenv activated. python tools/variant_data.py --all ``` -- This writes all 20 variant data files under `build/variants/`, from `KConfig`, each variant's - `config.txt` and each variant's `parts.cmake`. KConfig is pure Python, so it needs neither a - compiler nor CMake. +- This writes the variant data files under `build/variants/`, from `KConfig`, each variant's + `config.txt` and each variant's `parts.cmake`, and the rules file `ubproject.variants.toml`. + KConfig is pure Python, so it needs neither a compiler nor CMake. - Run it again whenever `KConfig`, a `config.txt` or a `parts.cmake` changes. `python tools/variant_data.py --all --check` tells you whether the files are up to date; CI runs it. - Configuring a CMake build, with the build scripts or the CMake extension, writes the files of the - variant it configures, and makes that variant the current one ([4](#4-switch-the-variant-your-editor-shows)). + variant it configures, and selects that build ([4](#4-switch-the-variant-your-editor-shows)). ## Explore ### 3. See which variant you are working on -The pointer says it: +The selection says it: ```bash -python -c "import json; c = json.load(open('build/autoconf.json'))['build_config']; print(c['variant'], c['kit'], c['target'])" +python -c "import tomllib; print(tomllib.load(open('build/selection.toml', 'rb'))['needs']['variant_data_file'])" ``` ```text -Disco test docs +/home/you/SPLed/build/variants/Disco/test/reports.json ``` +If the selection also mounts a build, its `[[source.mounts]]` entry names the build directory. + The documentation says it as well: its start page shows **Variant: Disco**. The page takes that from the variant data file ([10](#10-print-a-variant-value-in-the-text)). @@ -174,14 +190,13 @@ from the variant data file ([10](#10-print-a-variant-value-in-the-text)). python tools/variant_data.py --variant Sleep --kit test --current ``` -Both copy the chosen variant's `docs` file to `build/autoconf.json`, so ubCode and a plain -`sphinx-build` now read Sleep. If the editor still shows the previous variant, reload the window -(*Command Palette → Developer: Reload Window*). +Both write `build/selection.toml`, which names the chosen variant's `docs` file, so ubCode and a +plain `sphinx-build` now read Sleep. If the editor still shows the previous variant, reload the +window (*Command Palette → Developer: Reload Window*). - The kit defaults to `prod`. Give `--kit test` for the test kit. -- Configuring a CMake build makes the same switch, to the variant you configure. -- The pointer always holds a `docs` file, so in the editor the report-only sections are inactive - ([11](#11-show-a-section-only-in-the-reports-build)). +- Configuring a CMake build selects that build: a `test` kit build its `reports` file and its + generated pages, mounted at `generated`; a `prod` kit build its `docs` file. ### 5. Look at another variant without switching @@ -206,8 +221,18 @@ You do not have to switch to look at a variant. Point the reader at its file ins rule that removed it. `ubc check` also lists the project's other warnings, so its exit code says nothing about the variant. -`-D` for Sphinx and `-c` for ubc override the same setting, `variant_data_file`. spl-core passes -the same `-D` when CMake builds the `docs` and `reports` targets. +`-D` for Sphinx and `-c` for ubc override the same setting, `variant_data_file`. + +To look at another **build**, with its generated pages, hand the readers that build's own +selection file. CMake writes one per documentation run into the build directory: + +```bash +python -m sphinx -b html -D spl_selection=build/Spa/test/Debug/selection/reports.toml . build/docs/Spa +ubc check -c "$(cat build/Spa/test/Debug/selection/reports.toml)" +``` + +spl-core does the same for every `docs` and `reports` run it starts, so the reports of two builds +can be built side by side. ### 6. See what differs between two variants @@ -230,6 +255,13 @@ Build both variants as in [5](#5-look-at-another-variant-without-switching), the The output lists every need that is new, removed or changed. For Disco against Sleep, it starts with `New need SWDD_AO-100`, the first of the auto-off requirements that only Sleep has. +- **Builds.** Every build keeps its own report pages and `needs.json` + (`build/<variant>/<kit>/<type>/reports/html/needs.json`), so two builds compare with `ubc diff -n`, + or directly with the other build's selection file: + + ```bash + ubc diff -c "$(cat build/Spa/test/Debug/selection/reports.toml)" + ``` ### 7. Try a change without touching the product @@ -270,9 +302,10 @@ use one of these, from the quickest to the most complete: ([12](#12-include-a-document-only-when-its-component-is-in-the-variant)). An entry for a component the variant does not have is reported as `toctree.variant_excluded`, with the rule that removed the document. -- **No generated report pages.** Test results and coverage exist only after a CMake build of the - `reports` target. ubCode does not follow the `generated` link to them, and the pointer holds a - `docs` file anyway. +- **No generated pages yet.** Test results, test specifications and source listings exist after a + CMake build of the test kit, and the selection mounts them at `generated`. Sphinx reads them; + ubCode does not yet, because it does not mount a directory that lies inside the project, and + every build lives under `build/`. ubCode's side is described in [ubCode's guide to variants](https://ubcode.useblocks.com/usage/variants.html). @@ -341,30 +374,28 @@ A `reports` build adds test results and coverage. Gate the section on the target ````` The component pages end with a block like this one. The `generated/…` names are the same in every -variant ([18](#18-when-something-looks-wrong) explains the `generated` link). +variant: the selection mounts the build directory there. ### 12. Include a document only when its component is in the variant -Whole documents are gated in `ubproject.toml`, with one rule per component: +You do not write anything for it. `tools/variant_data.py` generates one rule per component that has +a `doc/index` page, into `ubproject.variants.toml`: ```toml [[source.variant_sources]] -if = "'components/auto_off' in var.build_config.components" -files = [ - "components/auto_off/doc/**", - "generated/components/auto_off/reports/**", - "generated/components/auto_off/__source_docs/**", -] +if = "'components/auto_off' in var.build_config.components and (var.build_config.scope == 'variant' or var.build_config.component == 'components/auto_off')" +files = ["components/auto_off/**"] ``` - When the condition is false, the files are left out before anything is read: no page, no needs, and no warning about a page that no toctree lists. -- The components page, `doc/components/index.md`, lists every component anyway. Sphinx and ubCode - report an entry for a left-out document as information. +- The components page, `doc/components/index.md`, globs every component's documentation, so it + lists exactly the variant's components. +- The second half of the condition is for the per-component report, which shows one component. - **Gate on the component list, never on the variant name.** The list comes from the variant's `parts.cmake`, so the product structure is written down once. `test_no_rule_names_a_variant_by_name` fails if a rule names a variant. -- Rule conditions use a smaller grammar than `{if}`. A boolean needs `== True`, as in +- Rule conditions, such as those of use case 13, use a smaller grammar than `{if}`. A boolean needs `== True`, as in `if = "var.features.AUTO_OFF == True"`. `and`, `or`, `not`, `==`, `!=`, `<`, `>`, `in` and `not in` work. A condition outside the grammar stops the Sphinx build. A condition that names an unknown key is reported, and removes its files. @@ -386,7 +417,8 @@ changes its place per variant. If one ever has to: ``` ```` 3. Gate the two pages with a rule and its **negation**, so that every variant has exactly one of - them: + them. Hand-written rules go into `doc/variant_rules.toml`, which `tools/variant_data.py` adds to + the generated ones; `ubproject.toml` cannot hold rules, because `extend` replaces an array: ```toml [[source.variant_sources]] @@ -406,15 +438,15 @@ without a warning. ### 14. Add a component 1. Add `spl_add_component(components/<name>)` to the `parts.cmake` of every variant that has it. -2. Write its documentation in `components/<name>/doc/index.md`. -3. Add one rule to `ubproject.toml`, next to the others: copy the `auto_off` rule from - [12](#12-include-a-document-only-when-its-component-is-in-the-variant) and change its paths. -4. Add one line to the toctree in `doc/components/index.md`: `/components/<name>/doc/index`. -5. Regenerate the variant data: `python tools/variant_data.py --all`. - -Nothing is generated by hand, no loop is edited, and nothing under `build/` is touched. -`test_every_component_document_is_gated_by_a_rule` fails if step 3 is missing. To have the report -tasks in VS Code offer the component, add it to the `component` input in `.vscode/tasks.json`. For +2. Write its documentation in `components/<name>/doc/index.md`. If its sources implement design + needs, give that page a `## Traceability` section with a `src-trace` block + ([17](#17-trace-code-to-the-design-per-variant)), and end it with a `## Verification` section + for the reports, as the other components do ([11](#11-show-a-section-only-in-the-reports-build)). +3. Regenerate: `python tools/variant_data.py --all`, or configure a build. + +That is all. The generator writes the component's rule, and the glob toctree in +`doc/components/index.md` lists its page. No rule and no toctree line is written by hand, and +nothing under `build/` is touched. To have the report tasks in VS Code offer the component, add it to the `component` input in `.vscode/tasks.json`. For the code side of a component, see [AGENTS.md](AGENTS.md#spl-specific-cmake-patterns). ### 15. Add or change a feature @@ -454,9 +486,45 @@ CMake sees the same symbol as `NIGHT_MODE="True"` for conditional components; se No rule and no document has to change. The rules gate on components, so the new variant gets its documents from its `parts.cmake`. +### 17. Trace code to the design, per variant + +An implementation need lives in the source file, as a one-line comment right above the code it +describes: + +```c +// @need Periodic Brightness Adjustment, SWIMPL_BC-001c, impl, [SWDD_BC-100, SWDD_BC-102], [REQ_46, REQ_48] +``` + +The fields are the title, the ID, the type, the design needs it implements and the requirements it +fulfills. Each component's page shows its needs with one `src-trace` block, in a `## Traceability` +section: + +````text +```{src-trace} +:project: components +:directory: brightness_controller +``` +```` + +Both readers read the same comments, so the needs are part of the `docs` build, and ubCode shows +them without building anything. Each need links to its line on GitHub. Test specifications stay in +`@rst` blocks in the test sources. + +**The preprocessor decides per variant.** A need inside an `#ifdef` branch exists only in the +variants that compile that branch. A link that holds only in some variants therefore belongs to a +need inside that branch. `SWDD_BC-203` exists only with automatic brightness adjustment, so the +runnable's automatic branch carries `SWIMPL_BC-004c` for it, and the runnable's own need +`SWIMPL_BC-003c` does not link it. + +codelinks takes the branches from `build/compile_commands.json`. Every build of the selected CMake +build copies its compile database there (`tools/compile_commands.py`), without the `-save-temps` +option of the `test` kit, which libclang rejects. After configuring without building, run +`cmake --build <build dir> --target spled_codelinks_compile_commands`. Without the file, codelinks +treats every `#ifdef` as false, and Sphinx warns. + ## Check -### 17. Run the checks +### 18. Run the checks ```bash python -m pytest -m docs # the documentation gate @@ -470,19 +538,21 @@ python -m pytest test/test_ubproject_config.py test/test_variant_data.py # rul - The ubc tests find `ubc` through the `UBC` environment variable, on the `PATH` or in the ubCode extension folder, and are skipped when it is not there. CI installs ubc and fails instead of skipping. -- No compiler is needed. The tests regenerate `build/variants/`, and restore the `generated` link - when they have pointed it elsewhere. +- The tests regenerate `build/variants/` and the rules, and restore `build/selection.toml` when + they have selected another cell. -### 18. When something looks wrong +### 19. When something looks wrong | What you see | What to do | | --- | --- | | A block or a page is missing in one variant | Its condition is false there, or it names a key that is not in the variant data file. Look the key up in `build/variants/<variant>/<kit>/docs.json`, check the spelling, and look for `'if' directive expression failed` or a rule warning in the build output. In a rule, a boolean needs `== True`. | -| The editor shows another variant than you expect | Look at the pointer ([3](#3-see-which-variant-you-are-working-on)). Configuring a CMake build switches it too. Switch back ([4](#4-switch-the-variant-your-editor-shows)) and reload the window. | +| The editor shows another variant than you expect | Look at the selection ([3](#3-see-which-variant-you-are-working-on)). Configuring a CMake build selects that build. Switch back ([4](#4-switch-the-variant-your-editor-shows)) and reload the window. | +| Sphinx stops with `No variant is selected` | `build/selection.toml` does not exist yet. Configure a build, or select a cell ([4](#4-switch-the-variant-your-editor-shows)). ubc stops for the same reason, with `Configuration file could not be loaded`. | | A change to a file under `build/` is gone | `build/` is generated and rewritten on every run. Change `KConfig`, a `config.txt` or a `parts.cmake` instead, or try the change on a copy ([7](#7-try-a-change-without-touching-the-product)). | | `python tools/variant_data.py --all --check` fails | The variant data is older than its sources. Run `python tools/variant_data.py --all`. | -| A documentation build stops with `SPL_SPHINX_BINARY_DIR … leads to …, but this build writes to …` | `generated` is a link (a junction on Windows) to the build directory configured last. It gives every generated page the same name in every variant. Since another build was configured, it leads elsewhere: configure this build again, then build its documentation. | -| ubCode shows no test results or coverage | That is expected. Those pages exist only after a CMake build of the `reports` target, and ubCode does not follow the `generated` link. | +| A link from a need in the code is dead in one variant | The need sits outside the `#ifdef` that decides the link. Give the link to a need inside the branch that implements it ([17](#17-trace-code-to-the-design-per-variant)). | +| Sphinx warns `compile_commands … is not a readable file` | codelinks has no compile database and treats every `#ifdef` as false. Build the selected build, or its `spled_codelinks_compile_commands` target ([17](#17-trace-code-to-the-design-per-variant)). | +| ubCode shows no test results or listings | That is expected for now: ubCode does not mount a directory inside the project, and the build lives under `build/` ([8](#8-know-what-ubcode-shows-you)). Sphinx shows them. | ## Rules of thumb @@ -491,8 +561,11 @@ python -m pytest test/test_ubproject_config.py test/test_variant_data.py # rul - Gate whole documents on components, blocks on features, and report sections on the target. Never gate on the variant name. - No Jinja in documents, no conditions in toctree entries, and no variant selection in `conf.py`. - Select a variant with `-D` for Sphinx and `-c` for ubc. -- Do not edit `build/` or `generated/`. + Select a variant by configuring a build or with `tools/variant_data.py --current`; look at + another one with `-D` for Sphinx and `-c` for ubc. +- A link that holds only in some variants belongs to a need inside the `#ifdef` branch that + implements it. +- Do not edit `build/`, `generated/` or `ubproject.variants.toml`. - After changing a variant's sources, regenerate and run `python -m pytest -m docs`. The design behind all this is described under diff --git a/components/auto_off/doc/index.md b/components/auto_off/doc/index.md index f8cb62b0..3ecc418d 100644 --- a/components/auto_off/doc/index.md +++ b/components/auto_off/doc/index.md @@ -132,6 +132,7 @@ Key press detection and timer reset occur within one execution cycle (CONFIG_OS_ /generated/components/auto_off/reports/unit_test_spec /generated/components/auto_off/reports/unit_test_results /generated/components/auto_off/reports/coverage +/generated/components/auto_off/__source_docs/index ``` ```` diff --git a/components/brightness_controller/doc/index.md b/components/brightness_controller/doc/index.md index f2b94083..6ea40b19 100644 --- a/components/brightness_controller/doc/index.md +++ b/components/brightness_controller/doc/index.md @@ -66,7 +66,8 @@ The Brightness Controller is use the RTE interface `RteSetBrightnessAdjustmentCo ## Traceability ```{src-trace} -:project: brightness_controller +:project: components +:directory: brightness_controller ``` ````{if} var.build_config.target == "reports" @@ -79,6 +80,7 @@ The Brightness Controller is use the RTE interface `RteSetBrightnessAdjustmentCo /generated/components/brightness_controller/reports/unit_test_spec /generated/components/brightness_controller/reports/unit_test_results /generated/components/brightness_controller/reports/coverage +/generated/components/brightness_controller/__source_docs/index ``` ```` diff --git a/components/brightness_controller/src/brightness_controller.c b/components/brightness_controller/src/brightness_controller.c index c5dc26fa..5b507a11 100644 --- a/components/brightness_controller/src/brightness_controller.c +++ b/components/brightness_controller/src/brightness_controller.c @@ -53,11 +53,12 @@ static brightness_t manualBrightnessAdjustment(void) #endif /* CONFIG_BRIGHTNESS_ADJUSTMENT_AUTOMATIC */ -// @need Brightness Controller runnable, SWIMPL_BC-003c, impl, [SWDD_BC-200, SWDD_BC-202, SWDD_BC-203], [REQ_46, REQ_47, REQ_48] +// @need Brightness Controller runnable, SWIMPL_BC-003c, impl, [SWDD_BC-200, SWDD_BC-202], [REQ_46, REQ_47, REQ_48] void brightnessController(void) { brightness_t brightnessValue = 0; #ifdef CONFIG_BRIGHTNESS_ADJUSTMENT_AUTOMATIC + // @need Automatic brightness adjustment in the runnable, SWIMPL_BC-004c, impl, [SWDD_BC-203], [REQ_48] static BrightnessAdjustmentData data = { .ticksCounter = 0, .period = BRIGHTNESS_PERIOD_TICKS, diff --git a/components/examples/flight_controller/doc/index.md b/components/examples/flight_controller/doc/index.md index c4682094..c2b5b82f 100644 --- a/components/examples/flight_controller/doc/index.md +++ b/components/examples/flight_controller/doc/index.md @@ -91,3 +91,25 @@ flowchart TD off_course -- "False" --> FALSE ``` + +## Traceability + +```{src-trace} +:project: components +:directory: examples/flight_controller +``` + +````{if} var.build_config.target == "reports" + +## Verification + +```{toctree} +:maxdepth: 1 + +/generated/components/examples/flight_controller/reports/unit_test_spec +/generated/components/examples/flight_controller/reports/unit_test_results +/generated/components/examples/flight_controller/reports/coverage +/generated/components/examples/flight_controller/__source_docs/index +``` + +```` diff --git a/components/examples/flight_controller/src/flight_controller.c b/components/examples/flight_controller/src/flight_controller.c index 31a68259..b2432e66 100644 --- a/components/examples/flight_controller/src/flight_controller.c +++ b/components/examples/flight_controller/src/flight_controller.c @@ -5,13 +5,7 @@ // See this youtube video for more information: // https://www.youtube.com/watch?v=k0_PF8MtEEo -/** - * @rst - * .. impl:: Abort decision logic - * :id: SWIMPL_FC-001 - * :implements: SWDD_FC-100, SWDD_FC-101, SWDD_FC-102 - * @endrst - */ +// @need Abort decision logic, SWIMPL_FC-001, impl, [SWDD_FC-100, SWDD_FC-101, SWDD_FC-102], [] SPLE_TESTABLE_STATIC bool_t CheckAbort(bool_t abort_commanded, bool_t valid_abort_command, bool_t off_course) { bool_t result; @@ -26,13 +20,7 @@ SPLE_TESTABLE_STATIC bool_t CheckAbort(bool_t abort_commanded, bool_t valid_abor return result; } -/** - * @rst - * .. impl:: Flight Controller's main runnable - * :id: SWIMPL_FC-002 - * :implements: SWDD_FC-103, SWDD_FC-200, SWDD_FC-201, SWDD_FC-202, SWDD_FC-203, SWDD_FC-204 - * @endrst - */ +// @need Flight Controller's main runnable, SWIMPL_FC-002, impl, [SWDD_FC-103, SWDD_FC-200, SWDD_FC-201, SWDD_FC-202, SWDD_FC-203, SWDD_FC-204], [] void flightController(void) { /* Get all relevant signals */ diff --git a/components/examples/hello_gmock/doc/index.md b/components/examples/hello_gmock/doc/index.md index 73ba0585..10cf4319 100644 --- a/components/examples/hello_gmock/doc/index.md +++ b/components/examples/hello_gmock/doc/index.md @@ -95,3 +95,18 @@ My component sets the data by calling an interface that requires a pointer to be Verify that the set interface is called with the expected value through the pointer. ``` + +````{if} var.build_config.target == "reports" + +## Verification + +```{toctree} +:maxdepth: 1 + +/generated/components/examples/hello_gmock/reports/unit_test_spec +/generated/components/examples/hello_gmock/reports/unit_test_results +/generated/components/examples/hello_gmock/reports/coverage +/generated/components/examples/hello_gmock/__source_docs/index +``` + +```` diff --git a/components/light_controller/doc/index.md b/components/light_controller/doc/index.md index fe28c885..97bd4290 100644 --- a/components/light_controller/doc/index.md +++ b/components/light_controller/doc/index.md @@ -111,6 +111,13 @@ stateDiagram-v2 ``` ```` +## Traceability + +```{src-trace} +:project: components +:directory: light_controller +``` + ````{if} var.build_config.target == "reports" ## Verification @@ -121,6 +128,7 @@ stateDiagram-v2 /generated/components/light_controller/reports/unit_test_spec /generated/components/light_controller/reports/unit_test_results /generated/components/light_controller/reports/coverage +/generated/components/light_controller/__source_docs/index ``` ```` diff --git a/components/light_controller/src/light_controller.c b/components/light_controller/src/light_controller.c index 8e23b39a..466ddb9d 100644 --- a/components/light_controller/src/light_controller.c +++ b/components/light_controller/src/light_controller.c @@ -19,14 +19,8 @@ typedef enum COLOR_VAL_PURPLE } LightColor; +// @need Light state, SWIMPL_LC-001, impl, [SWDD_LC-100], [REQ_42] /** - * @rst - * .. impl:: Light state - * :id: SWIMPL_LC-001 - * :implements: SWDD_LC-100 - * :fulfills: REQ_42 - * @endrst - * * @enum LightState * @brief Represents the states of the light. */ @@ -73,13 +67,7 @@ static const uint8_t light_colors_count = (uint8_t)((uint32_t)sizeof(light_color static brightness_t getBrightnessValue(void) { #ifdef CONFIG_BRIGHTNESS_ADJUSTMENT_ENABLED - /** - * @rst - * .. impl:: Variable brightness - * :id: SWIMPL_LC-005 - * :implements: SWDD_LC-204 - * @endrst - */ + // @need Variable brightness, SWIMPL_LC-005, impl, [SWDD_LC-204], [] return RteGetBrightnessValue(); #else return 128; @@ -118,14 +106,7 @@ static RGBColor getRGBColorWithBrightness(LightColor colorEnum, brightness_t bri return color; } -/** - * @rst - * .. impl:: Turn light off - * :id: SWIMPL_LC-002 - * :implements: SWDD_LC-102 - * :fulfills: REQ_43 - * @endrst - */ +// @need Turn light off, SWIMPL_LC-002, impl, [SWDD_LC-102], [REQ_43] static void turnLightOff(void) { #ifdef CONFIG_BLINKING @@ -134,14 +115,7 @@ static void turnLightOff(void) RteSetLightValue(OFF_COLOR); } -/** - * @rst - * .. impl:: Turn light on - * :id: SWIMPL_LC-003 - * :implements: SWDD_LC-102 - * :fulfills: REQ_43 - * @endrst - */ +// @need Turn light on, SWIMPL_LC-003, impl, [SWDD_LC-102], [REQ_43] static void turnLightOn(void) { // Used to iterate through the light colors @@ -173,15 +147,7 @@ static void turnLightOn(void) } #ifdef CONFIG_BLINKING -/** - * @rst - * - * .. impl:: Calculate blink period - * :id: SWIMPL_LC-004 - * :implements: SWDD_LC-101 - * :fulfills: REQ_44 - * @endrst - */ +// @need Calculate blink period, SWIMPL_LC-004, impl, [SWDD_LC-101], [REQ_44] SPLE_TESTABLE_STATIC percentage_t calculateBlinkPeriod(percentage_t mainKnobValue) { // Calculate blink period based on main knob value @@ -194,14 +160,8 @@ SPLE_TESTABLE_STATIC percentage_t calculateBlinkPeriod(percentage_t mainKnobValu } #endif +// @need Light Controller's main function, SWIMPL_LC-006, impl, [SWDD_LC-100], [REQ_44] /** - * @rst - * .. impl:: Light Controller's main function - * :id: SWIMPL_LC-006 - * :implements: SWDD_LC-100 - * :fulfills: REQ_44 - * @endrst - * * @brief Controls the light state. * * Uses a state machine to determine the light state based on several inputs, diff --git a/components/main_control_knob/doc/index.md b/components/main_control_knob/doc/index.md index 58b399f7..656116e1 100644 --- a/components/main_control_knob/doc/index.md +++ b/components/main_control_knob/doc/index.md @@ -52,6 +52,13 @@ The main control knob component uses the RTE interface `RteGetMainKnobValue()` t The main control knob component uses the RTE interface `RteSetMainKnobValue()` to set the new value of the main control knob. ``` +## Traceability + +```{src-trace} +:project: components +:directory: main_control_knob +``` + ````{if} var.build_config.target == "reports" ## Verification @@ -62,6 +69,7 @@ The main control knob component uses the RTE interface `RteSetMainKnobValue()` t /generated/components/main_control_knob/reports/unit_test_spec /generated/components/main_control_knob/reports/unit_test_results /generated/components/main_control_knob/reports/coverage +/generated/components/main_control_knob/__source_docs/index ``` ```` diff --git a/components/main_control_knob/src/main_control_knob.c b/components/main_control_knob/src/main_control_knob.c index 60623a2f..b769b0c1 100644 --- a/components/main_control_knob/src/main_control_knob.c +++ b/components/main_control_knob/src/main_control_knob.c @@ -10,14 +10,7 @@ #define MIN_KNOB_VALUE 0u #define MAX_KNOB_VALUE 100u -/** - * @rst - * .. impl:: Main Control Knob's main function - * :id: SWIMPL_MCK-001 - * :implements: SWDD_MCK-100, SWDD_MCK-101, SWDD_MCK-200, SWDD_MCK-201, SWDD_MCK-202, SWDD_MCK-203 - * :fulfills: REQ_50 - * @endrst - */ +// @need Main Control Knob's main function, SWIMPL_MCK-001, impl, [SWDD_MCK-100, SWDD_MCK-101, SWDD_MCK-200, SWDD_MCK-201, SWDD_MCK-202, SWDD_MCK-203], [REQ_50] void mainControlKnob(void) { percentage_t currentValue = RteGetMainKnobValue(); diff --git a/components/power_button/doc/index.md b/components/power_button/doc/index.md index bb4fb559..8c3eac1c 100644 --- a/components/power_button/doc/index.md +++ b/components/power_button/doc/index.md @@ -80,6 +80,7 @@ stateDiagram-v2 /generated/components/power_button/reports/unit_test_spec /generated/components/power_button/reports/unit_test_results /generated/components/power_button/reports/coverage +/generated/components/power_button/__source_docs/index ``` ```` diff --git a/components/power_signal_processing/doc/index.md b/components/power_signal_processing/doc/index.md index 4908ca88..ddefd3af 100644 --- a/components/power_signal_processing/doc/index.md +++ b/components/power_signal_processing/doc/index.md @@ -109,6 +109,13 @@ graph TD ``` ```` +## Traceability + +```{src-trace} +:project: components +:directory: power_signal_processing +``` + ````{if} var.build_config.target == "reports" ## Verification @@ -119,6 +126,7 @@ graph TD /generated/components/power_signal_processing/reports/unit_test_spec /generated/components/power_signal_processing/reports/unit_test_results /generated/components/power_signal_processing/reports/coverage +/generated/components/power_signal_processing/__source_docs/index ``` ```` diff --git a/components/power_signal_processing/src/power_signal_processing.c b/components/power_signal_processing/src/power_signal_processing.c index 0ae932c0..9f553c17 100644 --- a/components/power_signal_processing/src/power_signal_processing.c +++ b/components/power_signal_processing/src/power_signal_processing.c @@ -6,15 +6,7 @@ #include "power_signal_processing.h" #include "rte.h" -/** - * @rst - * - * .. impl:: Power signal processing - * :id: SWIMPL_PSP-001 - * :implements: SWDD_PSP-001, SWDD_PSP-002, SWDD_PSP-003 - * :fulfills: REQ_38 - * @endrst - */ +// @need Power signal processing, SWIMPL_PSP-001, impl, [SWDD_PSP-001, SWDD_PSP-002, SWDD_PSP-003], [REQ_38] void powerSignalProcessing(void) { // Check if "P" key was pressed diff --git a/conf.py b/conf.py index d9495107..32e6de22 100644 --- a/conf.py +++ b/conf.py @@ -1,7 +1,12 @@ # -*- coding: utf-8 -*- """Configuration""" import datetime +import logging import os +import tomllib +from pathlib import Path + +from sphinx.errors import ConfigError from spl_core.report_generation.spl_sphinx import SplSphinx from spl_core.report_generation.spl_html_settings import html_theme, html_show_sourcelink, html_theme_options, html_sidebars, html_last_updated_fmt # noqa: F401 @@ -26,35 +31,38 @@ ".git", "**/test_results.rst", # We renamed this file, but nobody deletes it. # Build output is never read where it lies. The one build a Sphinx run - # documents is reached through `generated`, the link tools/variant_data.py - # points at the configured build directory, and spl-core names every page - # it generates through that link (SPL_SPHINX_BINARY_DIR in CMakeLists.txt). - # Pruning `build` keeps every other variant's output out of the walk and - # leaves exactly one route to each generated page, which is the invariant - # test_ubproject_config.py guards: with two, every page exists twice. + # documents comes in through its mount at `generated` (the selection below), + # and spl-core names every page it generates there (SPL_SPHINX_BINARY_DIR in + # CMakeLists.txt). Pruning `build` keeps every other variant's output out of + # the walk and leaves exactly one route to each generated page: + # with two, every page exists twice. # # get_matching_files applies these to directories as well as files, so each # entry prunes the walk rather than filtering its result. "build", - # ...and, inside the configured build, the directories that hold no - # documents: CMake's own state and the HTML the builds write. + # ...and, inside the mounted build, the directories that hold no documents: + # CMake's own state and the HTML the builds write. "generated/CMakeFiles", "generated/**/CMakeFiles", "generated/**/html", ] -# The 150% source set: every hand-written document the product line has. +# The 150% source set: every document the product line has, hand-written and +# generated. The same set ubCode's parser includes name in ubproject.toml; the +# generated pages there are written relative to the mount, here by their names. # -# Which of them the build actually contains is decided by the -# [[source.variant_sources]] rules in ubproject.toml, against the variant data. -# Narrowing the set here as well would put a second, invisible gate in front of -# the declared one -- and an invisible gate is the thing this whole design -# exists to remove. +# Which of them a build actually contains is decided by the rules in +# ubproject.variants.toml, against the variant data. Narrowing the set here as +# well would put a second, invisible gate in front of the declared one -- and an +# invisible gate is the thing this whole design exists to remove. include_patterns = [ "index.md", "doc/**", "components/**/doc/**", "test/**/doc/**", + "generated/components/**/*.rst", + "generated/test/**/*.rst", + "generated/reports/*.rst", ] # configuration of built-in stuff ########################################### @@ -73,15 +81,21 @@ html_logo = "doc/_figures/SPLED_logo.png" -# Get default SPL extensions and their configurations -extensions = [*SplSphinx.default_extensions, "sphinx_codelinks", "sphinx_mounts"] +# Get default SPL extensions and their configurations. The test results are +# needs.json that spl-core writes after each test run and both readers import +# (SPL_TEST_RESULTS_AS_NEEDS in CMakeLists.txt), so sphinx-test-reports' directive, +# which only Sphinx knows, is not loaded. +extensions = [ + *(extension for extension in SplSphinx.default_extensions if extension != "sphinxcontrib.test_reports"), + "sphinx_codelinks", + "sphinx_mounts", +] extension_configs = SplSphinx.default_extension_configs # sphinx-codelinks: extract one-line need definitions from source code comments src_trace_config_from_toml = "ubproject.toml" # Apply extension-specific configurations -tr_report_template = extension_configs["tr_report_template"] myst_enable_extensions = extension_configs["myst_enable_extensions"] source_suffix = extension_configs["source_suffix"] @@ -92,75 +106,121 @@ # spl-core's base configuration is vendored into it. needs_from_toml = "ubproject.toml" -# The same file, named again for the other extension that reads it. sphinx-mounts -# already defaults to this path; naming it makes the coupling visible in conf.py -# rather than resting on a library default. -sources_from_toml = "ubproject.toml" - -# Registers project Python that the configuration references by name. This is -# the last thing in the needs model that ubCode cannot see, because it cannot -# run project functions; it goes away with sple_tr_link. -needs_functions = SplSphinx.default_needs_functions -needs_global_options = SplSphinx.default_needs_global_options - -# variant data ############################################################## +# The document rules, generated by tools/variant_data.py, one per documented +# component. sphinx-mounts reads rules from one file, relative to that file, so +# they live in a file of their own at the project root; ubproject.toml reaches +# the same file through `extend`. +sources_from_toml = "ubproject.variants.toml" + +# The `results` links of the test specifications are data, written by spl-core's +# converter as needextend blocks on each results page, so no needs function and +# no computed default is registered: every need and every link is something +# ubCode reads as well. + +# One warning is dropped, and only that one. ubproject.toml has to declare the +# test results' `file` field, because ubc drops an undeclared field of an +# imported need without a word. sphinx-codelinks registers a field of the same +# name, and sphinx-needs compares field names only, so it warns +# "Duplicate need field 'file'" although both declarations agree. Sphinx can only +# suppress a whole warning type (`needs.config`), which would hide every other +# problem in the needs configuration; this filter matches the one message. +# Remove it once sphinx-needs accepts a matching declaration. +class _DropTheDuplicateFileFieldWarning(logging.Filter): + def filter(self, record: logging.LogRecord) -> bool: + if getattr(record, "type", "") != "needs" or getattr(record, "subtype", "") != "config": + return True + try: + return "Duplicate need field 'file'" not in record.getMessage() + except Exception: + return True + + +for _handler in logging.getLogger("sphinx").handlers: + _handler.filters.insert(0, _DropTheDuplicateFileFieldWarning()) + +# variant selection ######################################################### # -# ONE file, and nothing computed here. +# ONE file decides what a build shows, and nothing is computed here. # -# Everything a document's {if} directive or a condition in ubproject.toml may -# name -- the complete feature vector, the variant, the build kit, the build -# target, the component list -- is written by tools/variant_data.py and read -# from here verbatim. That is the whole point: ubCode, ubc and a reviewer's -# editor cannot execute this file, so anything synthesized here would be -# invisible to them and their view of the project would silently disagree with -# the build. The rule is "everything a condition may name has to be IN the -# file", and it only holds if this file adds nothing. +# tools/variant_data.py writes build/selection.toml whenever a variant is +# selected: the variant data file every condition is evaluated against, and, for +# a CMake build, the mount that brings that build's generated pages in at +# `generated`; for a per-component report also its root document. ubproject.toml +# reaches it through `extend` (by way of ubproject.variants.toml), which ubCode +# and ubc follow. sphinx-needs and sphinx-mounts each read one TOML file and do +# not follow `extend`, so this hands them the selection's keys: the same keys, +# from the same file, nothing added. # -# Which cell of the matrix a build reads is not decided here either. It is the -# sphinx-needs option `needs_variant_data_file`, and ubproject.toml sets it to -# the pointer `build/autoconf.json`, which is what the IDE and a bare -# `sphinx-build` read. A build that needs another cell overrides the option on -# the command line: +# The variant data file holds everything a document's {if} directive or a rule +# may name -- the complete feature vector, the variant, the build kit, the build +# target, the component list. ubCode, ubc and a reviewer's editor cannot execute +# this file, so anything synthesized here would be invisible to them, and their +# view of the project would disagree with the build. +# +# Each run spl-core starts names its own build's file (`-D spl_selection=...`, +# SPL_SPHINX_OPTIONS in CMakeLists.txt), so two builds' reports can be built side +# by side. An explicit `-D needs_variant_data_file=...` or `-D root_doc=...` still +# wins over the file, the way `-c` does for ubc: # # sphinx-build -D needs_variant_data_file=build/variants/Sleep/test/docs.json ... # -# spl-core does exactly that for the shape it is building -# (SPL_VARIANT_DATA_FILE_DOCS and _REPORTS in CMakeLists.txt), and so do the -# tests. sphinx-needs keeps a command-line override even though needs_from_toml -# names the pointer, and it is the same key `ubc check -c` overrides, so both -# readers select a variant the same way. Nothing in this file could do it as -# robustly: sphinx-needs replaces conf.py's values with the TOML's and resolves -# the variant data in the very next config-inited handler, so an assignment is -# lost and a handler would have to slot in between the two. - -# build shape ############################################################### +# The handler runs at config-inited priority 5: before sphinx-needs loads its +# TOML (10) and resolves the variant data (11), and before sphinx-mounts loads +# its rules (400) and mounts (500). + +root_doc = "index" + + +def _load_selection(app, config): + selection_path = Path(app.confdir) / config.spl_selection + overrides = getattr(config, "overrides", {}) + if not selection_path.is_file(): + if "needs_variant_data_file" in overrides: + return + raise ConfigError( + f"No variant is selected: {selection_path} does not exist. Configure a CMake build, " + "or run `python tools/variant_data.py --all --current --variant <variant> --kit <kit>`." + ) + selection = tomllib.loads(selection_path.read_text(encoding="utf-8")) + variant_data_file = selection.get("needs", {}).get("variant_data_file") + if variant_data_file is not None and "needs_variant_data_file" not in overrides: + config.needs_variant_data_file = variant_data_file + root = selection.get("project", {}).get("root_doc") + if root is not None and "root_doc" not in overrides: + config.root_doc = root + config.mounts = selection.get("source", {}).get("mounts", []) + # A per-component report's links to the rest of the product dangle by design; + # its selection says so in ubc's terms, and this is the same statement for + # sphinx-needs, for that report only. + if "needs.dead_link" in selection.get("lint", {}).get("ignore", []): + config.suppress_warnings = [*config.suppress_warnings, "needs.link_outgoing"] + + +# configuration checks ###################################################### # -# The rest of this file is Sphinx plumbing, not variant data: which documents -# are in the source set and which one is the root. No other tool needs to -# decide these, and none of it may leak into `var.*`. - -_build_config = SplSphinx.get_default_html_context()["build_config"] - -# Two shapes of build use this configuration: the variant-wide one, and the -# per-component report that spl-core builds for a single component. This is the -# only build-shape decision left here, and it is a Sphinx one -- which document -# is the root -- not variant data. No other reader has to decide it. -if _build_config.get("component_info"): - root_doc = "doc/component_report" - exclude_patterns.append("index.md") - # A per-component report builds one component and stitches its own table of - # contents, so the project-wide variant rules do not apply to it. - sources_from_toml = None - include_patterns.extend(_build_config.get("include_patterns", [])) -else: - root_doc = "index" - exclude_patterns.append("doc/component_report.md") - # The pages spl-core generated for the configured build, under the - # `generated/` names it gave them. Only those: the hand-written component - # trees are in the source set already, and admitting them a second time would - # parse every need in them twice. - # - # Nothing here decides which of them a build reads. spl-core lists the report - # pages for the docs shape too, and the `generated/**` rule in ubproject.toml - # removes them there -- declared once, where ubCode reads it as well. - include_patterns.extend(pattern for pattern in _build_config.get("include_patterns", []) if pattern.startswith("generated/")) +# The checks test_ubproject_config.py runs, run again whenever Sphinx reads this +# configuration (tools/config_checks.py): the vendored needs model against +# spl-core's, the two readers' document sets against each other, and the +# generated rules against the shared grammar. A finding is a warning, so a drift +# fails the build under -W instead of waiting for someone to run the tests. + + +def _check_configuration(app, config): + import sys + + from sphinx.util import logging as sphinx_logging + + tools = str(Path(app.confdir) / "tools") + if tools not in sys.path: + sys.path.insert(0, tools) + import config_checks + + logger = sphinx_logging.getLogger(__name__) + for finding in config_checks.run_all(Path(app.confdir), list(config.include_patterns)): + logger.warning(f"configuration check: {finding}", type="spled", subtype="config") + + +def setup(app): + app.add_config_value("spl_selection", "build/selection.toml", "env", types=(str,)) + app.connect("config-inited", _load_selection, priority=5) + app.connect("config-inited", _check_configuration, priority=900) diff --git a/doc/component_report.md b/doc/component_report.md index ba070bd3..2422dd5d 100644 --- a/doc/component_report.md +++ b/doc/component_report.md @@ -1,19 +1,13 @@ # Software Component Report -**Variant:** {variant}`build_config.variant` +**Variant:** {variant}`build_config.variant` · **Component:** {variant}`build_config.component` This is the root document of the per-component report that spl-core builds for -a single component. The build configuration restricts the source set to that -one component, so the glob below resolves to exactly its design document, which -in turn groups that component's verification pages -- and names the component, -which is why this page does not. - -The component name is deliberately not read from `build_config.component_info`. -That key is written per BUILD, by spl-core, for one component; the variant data -every other reader has cannot contain it, because the generator does not know -which component a per-component report is for. A role naming it resolves inside -that one build and nowhere else, which is the divergence between readers this -project's configuration exists to prevent. +a single component. Its variant data has `build_config.scope = "component"`, and +the rules in ubproject.variants.toml leave that component's documents only, so +the glob below resolves to exactly its design document, which in turn groups the +component's verification pages. ubCode builds the same report from the same +files (build/selection.toml, or the build's `selection/<component>/reports.toml`). ```{toctree} :maxdepth: 2 diff --git a/doc/components/index.md b/doc/components/index.md index 9ca703b1..93de37f5 100644 --- a/doc/components/index.md +++ b/doc/components/index.md @@ -1,18 +1,12 @@ # Components -This page lists every component the product line has. It is a 150% view: the -entries are always all of them, and the ones the built variant does not contain -are removed from the build by the `[[source.variant_sources]]` rules in -`ubproject.toml`, each gated on membership of that variant's component list. - -So this page needs no templating and no generated content. Adding a component -to the report means adding it to a variant's `parts.cmake` and adding one rule -plus one line here — never editing a loop, and never editing anything under -`build/`. - -An entry naming a document the current variant excludes is reported as INFO by -both Sphinx and ubCode, by design: the 150% tree is the source of truth, and a -variant showing less of it is the normal case rather than an error. +This page lists the components of the variant. The toctree globs every +component's documentation, and the rules in `ubproject.variants.toml` remove the +ones the variant does not contain, each gated on membership of that variant's +component list. `tools/variant_data.py` derives the rules from where each +component's documentation lives, so adding a component means adding it to a +variant's `parts.cmake` and writing its documentation: nothing to edit here, +and nothing under `build/`. Each entry is a group. A component's own document is the entry point and carries the toctree for its verification pages, so unit test results and @@ -21,14 +15,9 @@ list. ```{toctree} :maxdepth: 2 +:glob: -/components/light_controller/doc/index -/components/main_control_knob/doc/index -/components/power_button/doc/index -/components/power_signal_processing/doc/index -/components/brightness_controller/doc/index -/components/auto_off/doc/index -/components/examples/hello_gmock/doc/index -/components/examples/flight_controller/doc/index -/test/spled_integration/doc/index +/components/*/doc/index +/components/examples/*/doc/index +/test/*/doc/index ``` diff --git a/doc/cross-platform-alignment-proposal.md b/doc/cross-platform-alignment-proposal.md index 0e299229..2e6ba493 100644 --- a/doc/cross-platform-alignment-proposal.md +++ b/doc/cross-platform-alignment-proposal.md @@ -1,3 +1,7 @@ +--- +orphan: true +--- + # Cross-Platform Alignment Proposal: `hammocking` & `SPLed` **Goal:** Develop and build both projects consistently under **Windows**, **Linux**, and inside a @@ -123,7 +127,7 @@ toolchain layer; drop SPLed's `docker-compose` indirection unless multi-service Shared skeleton (identical in both repos except the `Dockerfile` toolchain layer and extensions): -```jsonc +```json { "name": "<project>", "build": { "dockerfile": "Dockerfile" }, diff --git a/doc/devcontainer-and-bootstrap-design.md b/doc/devcontainer-and-bootstrap-design.md index 7458191a..3a68231e 100644 --- a/doc/devcontainer-and-bootstrap-design.md +++ b/doc/devcontainer-and-bootstrap-design.md @@ -1,3 +1,7 @@ +--- +orphan: true +--- + # SPLed DevContainer, DevPod & Bare-Linux Bootstrap — Design **Status:** implemented and validated (see § Validation). @@ -207,7 +211,7 @@ the symptom (poks downloads timing out) points nowhere near `devcontainer.json`. `HTTP_PROXY`/`HTTPS_PROXY`/`NO_PROXY` for build-time egress (apt/pipx/uv). Rather than baking proxy config into a portable image, pass them as build args on demand: -```jsonc +```json // devcontainer.json build.args — only for a cold build behind the proxy: "HTTP_PROXY": "${localEnv:HTTP_PROXY}", "HTTPS_PROXY": "${localEnv:HTTPS_PROXY}", diff --git a/doc/sw_requirements/index.md b/doc/sw_requirements/index.md index 50621bb1..e744b91e 100644 --- a/doc/sw_requirements/index.md +++ b/doc/sw_requirements/index.md @@ -4,5 +4,4 @@ ``` ```{needimport} ../ubconnect/csv/needs.json -:template: csv_image ``` diff --git a/doc/testing_strategy.md b/doc/testing_strategy.md index ae3b53e7..138d843e 100644 --- a/doc/testing_strategy.md +++ b/doc/testing_strategy.md @@ -1,3 +1,7 @@ +--- +orphan: true +--- + # Testing Strategy This document describes the testing strategy for the SPLED project, including diff --git a/doc/ubconnect/csv/data.csv b/doc/ubconnect/csv/data.csv index da306451..055180e7 100644 --- a/doc/ubconnect/csv/data.csv +++ b/doc/ubconnect/csv/data.csv @@ -1,5 +1,13 @@ -level,type,id,text,image,status,implements,satisfies -1,req,REQ_CSV_1,Text Req 1,,new,, -2,req,REQ_CSV_2,Text Req 2,picture/pic1.jpg,open,,REQ_CSV_1 -2,req,REQ_CSV_3,Text Req 3,picture/pic1.jpg,open,,REQ_CSV_1|REQ_CSV_2 -1,spec,ARCH_CSV_1,Text Arch 1,,open,REQ_CSV_1|REQ_CSV_2|REQ_CSV_3, +level,type,id,text,status,implements,satisfies +1,req,REQ_CSV_1,Text Req 1,new,, +2,req,REQ_CSV_2,"Text Req 2 + +```{image} /doc/ubconnect/csv/picture/pic1.jpg +:width: 300px +```",open,,REQ_CSV_1 +2,req,REQ_CSV_3,"Text Req 3 + +```{image} /doc/ubconnect/csv/picture/pic1.jpg +:width: 300px +```",open,,REQ_CSV_1|REQ_CSV_2 +1,spec,ARCH_CSV_1,Text Arch 1,open,REQ_CSV_1|REQ_CSV_2|REQ_CSV_3, diff --git a/doc/ubconnect/csv/needs.json b/doc/ubconnect/csv/needs.json index e4c840b1..76d9be84 100644 --- a/doc/ubconnect/csv/needs.json +++ b/doc/ubconnect/csv/needs.json @@ -18,7 +18,6 @@ "status": "new", "links": [], "level": 1, - "image": "", "implements": "", "links_back": [ "REQ_CSV_2", @@ -29,13 +28,12 @@ "id": "REQ_CSV_2", "type": "req", "title": "", - "content": "Text Req 2", + "content": "Text Req 2\n\n```{image} /doc/ubconnect/csv/picture/pic1.jpg\n:width: 300px\n```", "status": "open", "links": [ "REQ_CSV_1" ], "level": 2, - "image": "picture/pic1.jpg", "implements": "", "links_back": [ "REQ_CSV_3" @@ -45,14 +43,13 @@ "id": "REQ_CSV_3", "type": "req", "title": "", - "content": "Text Req 3", + "content": "Text Req 3\n\n```{image} /doc/ubconnect/csv/picture/pic1.jpg\n:width: 300px\n```", "status": "open", "links": [ "REQ_CSV_1", "REQ_CSV_2" ], "level": 2, - "image": "picture/pic1.jpg", "implements": "" }, "ARCH_CSV_1": { @@ -63,7 +60,6 @@ "status": "open", "links": [], "level": 1, - "image": "", "implements": [ "REQ_CSV_1", "REQ_CSV_2", diff --git a/index.md b/index.md index 10fbc633..004b8a85 100644 --- a/index.md +++ b/index.md @@ -1,3 +1,7 @@ +--- +orphan: true +--- + # Variant Report **Variant:** {variant}`build_config.variant` @@ -10,6 +14,7 @@ doc/customer_requirements/index doc/software_architecture/index doc/sw_requirements/index doc/components/index +doc/results/index ``` ````{if} var.build_config.target == "reports" diff --git a/needs_templates/csv_image.need b/needs_templates/csv_image.need deleted file mode 100644 index 720712ae..00000000 --- a/needs_templates/csv_image.need +++ /dev/null @@ -1,9 +0,0 @@ -{# Place the original content here #} -{{content}} - -{% if image %} - -```{image} /doc/ubconnect/csv/{{ image }} -:width: 300px -``` -{% endif %} diff --git a/poetry.lock b/poetry.lock index 4e4096a6..ab4dd85f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4201,8 +4201,8 @@ typer = ">=0,<1" [package.source] type = "git" url = "https://github.com/useblocks/spl-core.git" -reference = "010727d08b27ca73994772444d25d7bc6e028c31" -resolved_reference = "010727d08b27ca73994772444d25d7bc6e028c31" +reference = "1181c0a636ac4e85ffab02d52ede21dc8cc7da45" +resolved_reference = "1181c0a636ac4e85ffab02d52ede21dc8cc7da45" [[package]] name = "text-unidecode" @@ -4802,4 +4802,4 @@ cffi = ["cffi (>=1.17,<2.0) ; platform_python_implementation != \"PyPy\" and pyt [metadata] lock-version = "2.1" python-versions = "<3.14,>=3.12" -content-hash = "c4fca35edababcd6d4b502ede808ffd05224e8d2fa83cda55228e9f69890d7f5" +content-hash = "59c523049113a748592982df85c52f241c1995f92f97b6605e5ee6892b273442" diff --git a/pyproject.toml b/pyproject.toml index 47f4a0a0..b43e46ce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ authors = [{ name = "Avengineers" }] requires-python = "<3.14,>=3.12" dependencies = [ - "spl-core @ git+https://github.com/useblocks/spl-core.git@010727d08b27ca73994772444d25d7bc6e028c31", + "spl-core @ git+https://github.com/useblocks/spl-core.git@1181c0a636ac4e85ffab02d52ede21dc8cc7da45", "pypeline-runner>=1.33,<2", "pytest>=8,<9", "myst-parser>=4.0,<5", diff --git a/test/docs_exceptions.toml b/test/docs_exceptions.toml new file mode 100644 index 00000000..0e6d0c2b --- /dev/null +++ b/test/docs_exceptions.toml @@ -0,0 +1,18 @@ +# What the two readers of the documentation may differ in -- and nothing else. +# +# test_docs_gate.py builds every variant and kit with Sphinx and with ubc and +# fails on any warning and any difference in the needs that is not listed here. +# Every entry names its reason; remove it the day the reason is gone. + +[[needs]] +id = "REQ_37" +reason = "Imported from the ubConnect ReqIF export without a title (upstream data). Sphinx imports it with an empty title; ubc refuses an untitled need." + +[[needs]] +id = "REQ_58" +reason = "As REQ_37." + +[[ubc_warnings]] +code = "needs.import" +count = 2 +reason = "ubc's warnings about REQ_37 and REQ_58, see above." diff --git a/test/spled_integration/doc/index.md b/test/spled_integration/doc/index.md index 3d7394c0..40dfdd4e 100644 --- a/test/spled_integration/doc/index.md +++ b/test/spled_integration/doc/index.md @@ -10,6 +10,7 @@ /generated/test/spled_integration/reports/unit_test_spec /generated/test/spled_integration/reports/unit_test_results /generated/test/spled_integration/reports/coverage +/generated/test/spled_integration/__source_docs/index ``` ```` diff --git a/test/test_docs_gate.py b/test/test_docs_gate.py new file mode 100644 index 00000000..d91e1d50 --- /dev/null +++ b/test/test_docs_gate.py @@ -0,0 +1,212 @@ +"""The documentation gate: every variant and kit, both readers, strict, the same needs. + +For each cell this selects the build CMake configures for it -- configure only, +nothing is compiled -- so codelinks evaluates that build's `#ifdef` branches with +its compile database. Then it builds the documents with `sphinx-build -W` and with +ubc, and compares the two needs.json files need by need: IDs, types, titles, +fields and links. Whatever the two readers may differ in is listed, with its +reason, in docs_exceptions.toml; any other warning or difference fails. + +Both build times go into the job summary on CI (`GITHUB_STEP_SUMMARY`), so the +speed of the second reader is visible next to the first. + +The configure needs CMake, Ninja and a C/C++ compiler: on CI the runner's, here +whatever is on PATH. Without them the tests skip, and on CI (`CI` is set) they +fail instead, because a gate that only runs on a developer machine is none. +""" + +from __future__ import annotations + +import json +import os +import platform +import shutil +import subprocess +import sys +import time +import tomllib +from pathlib import Path + +import pytest + +PROJECT_ROOT = Path(__file__).resolve().parent.parent + +VARIANTS = ["Base/Dev", "Disco", "IDEA/Sloemada", "Sleep", "Spa"] +KITS = ["prod", "test"] + +pytestmark = [ + pytest.mark.docs, + pytest.mark.gate_develop_pr, + pytest.mark.gate_develop_push, + pytest.mark.gate_develop_nightly, + pytest.mark.gate_release_pr, + pytest.mark.gate_release, +] + +EXCEPTIONS = tomllib.loads((PROJECT_ROOT / "test" / "docs_exceptions.toml").read_text(encoding="utf-8")) +EXCEPTED_NEEDS = {entry["id"] for entry in EXCEPTIONS.get("needs", [])} +EXCEPTED_UBC_WARNINGS = {entry["code"]: entry["count"] for entry in EXCEPTIONS.get("ubc_warnings", [])} + +#: Build times per cell, for the job summary. +TIMINGS: list[tuple[str, str, float, float, int]] = [] + + +def _find_ubc() -> str | None: + for candidate in (os.environ.get("UBC"), shutil.which("ubc")): + if candidate and Path(candidate).is_file(): + return candidate + for extension in sorted((Path.home() / ".vscode" / "extensions").glob("useblocks.ubcode-*"), reverse=True): + for name in ("ubc", "ubc.exe"): + candidate = extension / "server" / "cli" / name + if candidate.is_file(): + return str(candidate) + return None + + +def _require(what: str, available: bool) -> None: + if available: + return + if os.environ.get("CI"): + pytest.fail(f"{what} is required on CI") + pytest.skip(f"{what} is not available") + + +@pytest.fixture(scope="module", autouse=True) +def _restore_the_developers_selection(): + """The gate selects every cell in turn; what the developer had selected comes back.""" + saved = {} + for name in ("build/selection.toml", "build/compile_commands.json"): + path = PROJECT_ROOT / name + saved[path] = path.read_bytes() if path.is_file() else None + yield + for path, content in saved.items(): + if content is None: + path.unlink(missing_ok=True) + else: + path.write_bytes(content) + if os.environ.get("GITHUB_STEP_SUMMARY") and TIMINGS: + with open(os.environ["GITHUB_STEP_SUMMARY"], "a", encoding="utf-8") as summary: + summary.write("### Documentation build time per cell\n\n| Variant | Kit | Sphinx | ubc | Needs |\n| --- | --- | ---: | ---: | ---: |\n") + for variant, kit, sphinx_s, ubc_s, needs in TIMINGS: + summary.write(f"| {variant} | {kit} | {sphinx_s:.2f} s | {ubc_s:.2f} s | {needs} |\n") + + +def _select_build(variant: str, kit: str) -> Path: + """Configure the cell's build, which selects it, and hand codelinks its database.""" + build_dir = PROJECT_ROOT / "build" / variant / kit / "Debug" + command = [ + "cmake", "-S", str(PROJECT_ROOT), "-B", str(build_dir), "-G", "Ninja", + f"-DVARIANT={variant}", f"-DBUILD_KIT={kit}", "-DCMAKE_BUILD_TYPE=Debug", + ] + if kit == "test": + toolchain = "toolchain.cmake" if platform.system() == "Windows" else "toolchain_linux.cmake" + command.append(f"-DCMAKE_TOOLCHAIN_FILE={PROJECT_ROOT / 'tools' / 'toolchains' / 'gcc' / toolchain}") + configured = subprocess.run(command, cwd=PROJECT_ROOT, capture_output=True, text=True) + assert configured.returncode == 0, f"configuring {variant}/{kit} failed:\n{configured.stdout[-3000:]}\n{configured.stderr[-3000:]}" + copied = subprocess.run( + ["cmake", "--build", str(build_dir), "--target", "spled_codelinks_compile_commands"], + cwd=PROJECT_ROOT, capture_output=True, text=True, + ) + assert copied.returncode == 0, f"copying the compile database of {variant}/{kit} failed:\n{copied.stdout[-3000:]}" + return build_dir + + +def _needs(path: Path) -> dict[str, dict]: + data = json.loads(path.read_text(encoding="utf-8")) + return data["versions"][data.get("current_version", "")]["needs"] + + +def _compared_fields() -> list[str]: + config = tomllib.loads((PROJECT_ROOT / "ubproject.toml").read_text(encoding="utf-8"))["needs"] + return ["type", "title", "status", "tags", *config.get("links", {}), *config.get("fields", {})] + + +def _normalized(value): + if value in (None, "", [], {}): + return None + return sorted(value) if isinstance(value, list) else value + + +def _component_reports() -> list[tuple[str, str]]: + """(variant, component) for every component report spl-core builds: the test kit's.""" + sys.path.insert(0, str(PROJECT_ROOT / "tools")) + import variant_data # noqa: PLC0415 + + return [(variant, component) for variant in VARIANTS for component in variant_data.reported_components(PROJECT_ROOT, variant, "test")] + + +@pytest.mark.parametrize("kit", KITS) +@pytest.mark.parametrize("variant", VARIANTS) +def test_both_readers_build_the_same_documentation_strictly(variant: str, kit: str, tmp_path: Path) -> None: + _check_one_run(variant, kit, "docs.toml", tmp_path) + + +@pytest.mark.parametrize(("variant", "component"), _component_reports()) +def test_both_readers_build_the_same_component_report_strictly(variant: str, component: str, tmp_path: Path) -> None: + """spl-core's per-component report, in the docs shape, which upstream tests nowhere.""" + _check_one_run(variant, "test", f"{component}/docs.toml", tmp_path, label=f"{variant}/{component}") + + +#: The cell selected last. codelinks reads the selected build's compile database, +#: so a run of another cell selects that cell first. +_SELECTED: dict[str, tuple[str, str, Path]] = {} + + +def _check_one_run(variant: str, kit: str, selection_name: str, tmp_path: Path, label: str | None = None) -> None: + ubc = _find_ubc() + _require("ubc", ubc is not None) + _require("CMake and Ninja", bool(shutil.which("cmake") and shutil.which("ninja"))) + + current = _SELECTED.get("cell") + if current is None or current[:2] != (variant, kit): + _SELECTED["cell"] = (variant, kit, _select_build(variant, kit)) + build_dir = _SELECTED["cell"][2] + selection = build_dir / "selection" / selection_name + label = label or f"{variant}/{kit}" + + started = time.perf_counter() + sphinx = subprocess.run( + [sys.executable, "-m", "sphinx", "-W", "--keep-going", "-q", "-b", "html", + "-D", f"spl_selection={selection}", "-d", str(tmp_path / "doctrees"), str(PROJECT_ROOT), str(tmp_path / "sphinx")], + cwd=PROJECT_ROOT, capture_output=True, text=True, env={**os.environ, "VARIANT": variant}, + ) + sphinx_seconds = time.perf_counter() - started + warnings = [line for line in sphinx.stderr.splitlines() if "WARNING" in line or "ERROR" in line] + if (PROJECT_ROOT / ".git").is_file(): + # A linked git worktree, where `.git` is a file: sphinx-codelinks does not + # find the git root there and warns once per source (codelinks.git_ref). + # A clone, as on CI, does not have the problem, so it is tolerated here only. + warnings = [line for line in warnings if "[codelinks.git_ref]" not in line] + tolerated_only = (PROJECT_ROOT / ".git").is_file() and not warnings + assert (sphinx.returncode == 0 or tolerated_only) and not warnings, f"{label}: Sphinx is not clean in strict mode:\n" + "\n".join(warnings or [sphinx.stderr[-3000:]]) + + override = selection.read_text(encoding="utf-8") + checked = subprocess.run([ubc, "check", "--no-cache", "--output-format", "json", "-c", override], cwd=PROJECT_ROOT, capture_output=True, text=True) + counts: dict[str, int] = {} + for diagnostic in json.loads(checked.stdout or "{}").get("diagnostics", []): + if diagnostic["severity"] != "info": + counts[diagnostic["code"]] = counts.get(diagnostic["code"], 0) + 1 + unexpected = {code: count for code, count in counts.items() if EXCEPTED_UBC_WARNINGS.get(code) != count} + assert not unexpected, f"{label}: ubc reports findings docs_exceptions.toml does not name: {unexpected}" + + started = time.perf_counter() + built = subprocess.run([ubc, "build", "html", "--no-cache", "--deny", "none", "-o", str(tmp_path / "ubc"), "-c", override], cwd=PROJECT_ROOT, capture_output=True, text=True) + ubc_seconds = time.perf_counter() - started + assert built.returncode == 0, f"{label}: ubc build html failed:\n{built.stdout[-3000:]}\n{built.stderr[-3000:]}" + + sphinx_needs = _needs(tmp_path / "sphinx" / "needs.json") + ubc_needs = _needs(tmp_path / "ubc" / "needs.json") + TIMINGS.append((variant, label.split("/", 1)[1] if label != f"{variant}/{kit}" else kit, sphinx_seconds, ubc_seconds, len(sphinx_needs))) + + only_sphinx = sorted(set(sphinx_needs) - set(ubc_needs) - EXCEPTED_NEEDS) + only_ubc = sorted(set(ubc_needs) - set(sphinx_needs) - EXCEPTED_NEEDS) + assert not only_sphinx and not only_ubc, f"{label}: needs in one reader only: Sphinx {only_sphinx}, ubc {only_ubc}" + + fields = _compared_fields() + differences = [ + f"{need_id}.{field}: Sphinx {_normalized(sphinx_needs[need_id].get(field))!r}, ubc {_normalized(ubc_needs[need_id].get(field))!r}" + for need_id in sorted(set(sphinx_needs) & set(ubc_needs)) + for field in fields + if _normalized(sphinx_needs[need_id].get(field)) != _normalized(ubc_needs[need_id].get(field)) + ] + assert not differences, f"{label}: the readers disagree about {len(differences)} values:\n" + "\n".join(differences[:40]) diff --git a/test/test_documentation.py b/test/test_documentation.py index 30dc194a..2d790c99 100644 --- a/test/test_documentation.py +++ b/test/test_documentation.py @@ -13,16 +13,19 @@ - Sphinx builds the variant's documents without error; - the documents present are exactly the ones the variant's component list says, which is the property the whole variant-gating design exists to provide. + +And, with `ubc`, that a second reader which never runs conf.py decides the same +document set. """ import ast -import contextlib import json import os import re import shutil import subprocess import sys +from collections.abc import Iterator from pathlib import Path import pytest @@ -59,6 +62,15 @@ "components/examples/flight_controller": "components/examples/flight_controller/doc/index.html", } +#: The toctree globs of doc/components/index.md. ubCode reports a glob that +#: matched only documents a variant excludes, so these are what the parity +#: comparison has to evaluate. +COMPONENT_TOCTREE_GLOBS = ( + "components/*/doc/index", + "components/examples/*/doc/index", + "test/*/doc/index", +) + @pytest.fixture(scope="module") def all_variant_data() -> None: @@ -71,12 +83,49 @@ def all_variant_data() -> None: ) +@pytest.fixture(scope="module", autouse=True) +def selected_cell(all_variant_data: None) -> Iterator[None]: + """Select one cell for the readers that cannot take one on the command line. + + `ubc` loads the project through ubproject.toml -> ubproject.variants.toml -> + build/selection.toml, and refuses to load it when that file is missing. The + developer's own build/selection.toml -- which points at the build they + configured -- is put back byte for byte, because this test must not repoint + their IDE at a test selection. + """ + selection = PROJECT_ROOT / "build" / "selection.toml" + original = selection.read_bytes() if selection.is_file() else None + + subprocess.run( + [ + sys.executable, + str(PROJECT_ROOT / "tools" / "variant_data.py"), + "--all", + "--current", + "--variant", + "Disco", + "--kit", + "test", + ], + cwd=PROJECT_ROOT, + check=True, + capture_output=True, + ) + try: + yield + finally: + if original is None: + selection.unlink(missing_ok=True) + else: + selection.write_bytes(original) + + def _select_cell(variant: str, kit: str, target: str) -> list[str]: """The sphinx-build option that selects one cell of the matrix. A command-line override of `needs_variant_data_file`, which sphinx-needs keeps - even though needs_from_toml names the pointer. It is what spl-core passes for - the shape it builds, and the key `ubc check -c` overrides as well. + even though conf.py reads a selection. It is what spl-core passes for the + shape it builds, and the key `ubc check -c` overrides as well. """ return ["-D", f"needs_variant_data_file={PROJECT_ROOT / 'build' / 'variants' / variant / kit / f'{target}.json'}"] @@ -290,59 +339,85 @@ def test_ubc_finds_no_configuration_problem(all_variant_data: None) -> None: assert not problems, "; ".join(f"{d['code']}: {d['message']}" for d in problems) +def _glob_matches(pattern: str, document: str) -> bool: + """A path glob, where `*` does not cross `/` (Sphinx's and ubCode's rule).""" + regex = re.escape(pattern).replace(r"\*\*", ".*").replace(r"\*", "[^/]*") + return re.fullmatch(regex, document) is not None + + @needs_ubc @pytest.mark.parametrize("variant", VARIANTS) def test_ubc_excludes_exactly_what_sphinx_excludes(all_variant_data: None, variant: str) -> None: """The property the whole design exists to provide, proven across readers. - ubCode never runs conf.py. If it removes exactly the component documents - that the variant's component list omits -- the same set the Sphinx build - omits, asserted above -- then both readers are deciding from the same data - and agreeing. That is the claim; this is the test of it. + ubCode never runs conf.py. The component list is what gates the documents, + and doc/components/index.md globs its toctree. ubCode 0.35 reports a glob + that matched ONLY documents the variant excludes, with one example rather + than its members -- so the exact property is checked per glob: a glob is + reported exactly when every component it matches is missing from the + variant, and the example it names belongs to one of them. """ diagnostics = _ubc_check(variant, "test", "docs") - excluded_by_ubc = set() + reported_globs: set[str] = set() for diagnostic in diagnostics: if diagnostic["code"] != "toctree.variant_excluded": continue - match = re.search(r"toctree entry '([^']+)'", diagnostic["message"]) - assert match, diagnostic["message"] - excluded_by_ubc.add(match.group(1)) + message = diagnostic["message"] + glob = re.search(r"glob pattern '([^']+)'", message) + if glob: + reported_globs.add(glob.group(1)) + example = re.search(r"example '([^']+)'", message) + assert example, message + component = example.group(1).split("/doc/", 1)[0] + assert component in COMPONENT_DOCS, message + continue + entry = re.search(r"toctree entry '([^']+)'", message) + assert entry, message + component = entry.group(1).split("/doc/", 1)[0] + assert component in COMPONENT_DOCS, message components = set(variant_data.components(PROJECT_ROOT, variant, "test")) - expected = { - f"{component}/doc/index" for component in COMPONENT_DOCS if component not in components + covered = { + component + for glob in COMPONENT_TOCTREE_GLOBS + for component in COMPONENT_DOCS + if _glob_matches(glob, f"{component}/doc/index") } - - assert excluded_by_ubc == expected, ( - f"{variant}: ubCode and the component list disagree.\n" - f" ubCode excluded : {sorted(excluded_by_ubc)}\n" - f" expected : {sorted(expected)}" + assert covered == set(COMPONENT_DOCS), ( + "the toctree globs must name every documented component, or the parity " + f"check silently skips {sorted(set(COMPONENT_DOCS) - covered)}" ) + for glob in COMPONENT_TOCTREE_GLOBS: + matched = {component for component in COMPONENT_DOCS if _glob_matches(glob, f"{component}/doc/index")} + assert matched, f"the toctree glob {glob!r} matched no known component" + all_excluded = all(component not in components for component in matched) + assert (glob in reported_globs) == all_excluded, ( + f"{variant}: ubCode {'reported' if glob in reported_globs else 'did not report'} " + f"{glob!r}, but it matches " + ", ".join(sorted(matched)) + ) + + +def test_the_component_toctree_globs_are_the_ones_checked() -> None: + """The globs the parity test evaluates are the ones the page actually has.""" + page = (PROJECT_ROOT / "doc" / "components" / "index.md").read_text(encoding="utf-8") + for glob in COMPONENT_TOCTREE_GLOBS: + assert f"/{glob}" in page, f"doc/components/index.md no longer toctrees {glob}" + # --- the build shape must select its own cell ------------------------------- -def _build_with_spl_core_env(shape: str, out_dir: Path, tmp_path: Path, config: dict | None = None) -> subprocess.CompletedProcess: - """Build the way spl-core starts Sphinx, environment and options. +def _build_with_cell(shape: str, out_dir: Path) -> subprocess.CompletedProcess: + """Build the way spl-core starts Sphinx: one cell per build shape. - spl-core names the per-target config.json in SPHINX_BUILD_CONFIGURATION_FILE - and selects the variant data cell for the shape with - `-D needs_variant_data_file=`, which CMakeLists.txt configures through - SPL_VARIANT_DATA_FILE_DOCS and _REPORTS. The cell is what the - `{if} var.build_config.target` fences evaluate against. + conf.py reads the `-D needs_variant_data_file` override ahead of any + selection, and the cell is what the `{if} var.build_config.target` fences + evaluate against. """ - config_dir = tmp_path / "cfg" / shape - config_dir.mkdir(parents=True, exist_ok=True) - (config_dir / "config.json").write_text(json.dumps(config or {}), encoding="utf-8") - - env = { - **os.environ, - "SPHINX_BUILD_CONFIGURATION_FILE": str(config_dir / "config.json"), - "VARIANT": "Disco", - } + env = {**os.environ, "VARIANT": "Disco"} + env.pop("SPHINX_BUILD_CONFIGURATION_FILE", None) return subprocess.run( [sys.executable, "-m", "sphinx", "-b", "html", *_select_cell("Disco", "test", shape), str(PROJECT_ROOT), str(out_dir)], cwd=PROJECT_ROOT, @@ -359,21 +434,22 @@ def _cmake_set(cmake: str, variable: str) -> str: return match.group(1).strip() -def test_cmake_passes_spl_core_the_cell_for_each_shape() -> None: - """The helper mirrors a contract that lives in CMakeLists.txt. +def test_cmake_points_each_documentation_run_at_its_selection() -> None: + """spl-core hands every run its own build's selection file. - If the helper and the CMake configuration disagree, the tests would prove - the behaviour of an environment spl-core never builds in. This reads the + `-D spl_selection=<build>/selection/<shape>.toml` is what makes a run read + the cell of its shape (and, for a component, its own component's cell) + without depending on which build was configured last. This reads the `set(...)` calls rather than searching for the variable name, so a stray mention in a comment cannot satisfy it. """ cmake = (PROJECT_ROOT / "CMakeLists.txt").read_text(encoding="utf-8") - expected = { - "SPL_VARIANT_DATA_FILE_DOCS": "${CMAKE_SOURCE_DIR}/build/variants/${VARIANT}/${BUILD_KIT}/docs.json", - "SPL_VARIANT_DATA_FILE_REPORTS": "${CMAKE_SOURCE_DIR}/build/variants/${VARIANT}/${BUILD_KIT}/reports.json", - } - for variable, value in expected.items(): - assert _cmake_set(cmake, variable) == value, f"CMakeLists.txt must pass {variable}={value}" + assert _cmake_set(cmake, "SPL_SPHINX_OPTIONS") == ( + "-D spl_selection=${CMAKE_BINARY_DIR}/selection/@SHAPE@.toml" + ) + assert _cmake_set(cmake, "SPL_SPHINX_COMPONENT_OPTIONS") == ( + "-D spl_selection=${CMAKE_BINARY_DIR}/selection/@COMPONENT_PATH@/@SHAPE@.toml" + ) def test_the_reports_shape_reads_the_reports_cell(all_variant_data: None, tmp_path: Path) -> None: @@ -390,7 +466,7 @@ def test_the_reports_shape_reads_the_reports_cell(all_variant_data: None, tmp_pa """ for shape, expect_verification in (("reports", True), ("docs", False)): out = tmp_path / f"{shape}_html" - result = _build_with_spl_core_env(shape, out, tmp_path) + result = _build_with_cell(shape, out) assert result.returncode == 0, (result.stdout + result.stderr)[-2000:] page = (out / "components" / "light_controller" / "doc" / "index.html").read_text(encoding="utf-8") assert ("Verification" in page) is expect_verification, ( @@ -398,114 +474,101 @@ def test_the_reports_shape_reads_the_reports_cell(all_variant_data: None, tmp_pa ) -# --- the generated report pages -------------------------------------------- +# --- the generated report pages, through the mount ------------------------- #: The three pages spl-core writes per component at CONFIGURE time, and lists #: among its include patterns for BOTH build shapes. SPL_CORE_REPORT_PAGES = ("unit_test_spec", "unit_test_results", "coverage") -#: A fake build directory the `generated` link is pointed at for the duration of -#: a test. It is gitignored and pruned from the Sphinx walk, so the only route -#: to it is `generated` -- which is exactly the route under test. -FAKE_GENERATED_BUILD = PROJECT_ROOT / "build" / "_test_generated_build" - - -def _link(link: Path, target: Path) -> None: - """Create `generated` the way tools/variant_data.py does: a symlink, or a junction where Windows refuses one.""" - try: - link.symlink_to(target, target_is_directory=True) - except OSError: - variant_data._create_junction(target, link) - - -@contextlib.contextmanager -def _generated_points_at(fake_build: Path): - """Point `generated` at a fake build, then point it back where it was. - - Several tests need `generated` to lead somewhere the real build is not, so - they can assert on pages the real build does not contain. The link is - restored on the way out whatever happens, because leaving a developer's - pointer re-pointed at a removed test directory would break their next build - in a way they did not cause. It never calls variant_data.write_pointer: - that would overwrite build/autoconf.json, which belongs to the developer. - """ - generated = PROJECT_ROOT / "generated" - if generated.is_symlink() or generated.is_junction(): - # A junction's target can come back in the \\?\ form, which a new - # junction cannot be created from. - original: tuple[str, str | None] = ("link", os.readlink(generated).removeprefix("\\\\?\\")) - elif generated.is_dir(): - # A plain directory only ever holds the explanation variant_data.py - # writes when neither a symlink nor a junction could be created. - marker = generated / "NO_SYMLINK" - original = ("directory", marker.read_text(encoding="utf-8") if marker.is_file() else None) - else: - original = ("absent", None) - - variant_data._remove_link(generated) - shutil.rmtree(fake_build, ignore_errors=True) - fake_build.mkdir(parents=True, exist_ok=True) - _link(generated, fake_build) - - try: - yield generated - finally: - variant_data._remove_link(generated) - if original[0] == "link": - _link(generated, Path(original[1])) - elif original[0] == "directory": - generated.mkdir(parents=True, exist_ok=True) - if original[1] is not None: - (generated / "NO_SYMLINK").write_text(original[1], encoding="utf-8") - shutil.rmtree(fake_build, ignore_errors=True) - -def _fake_spl_core_report_tree(component: str) -> str: - """Write what spl-core's configure step writes, and the pattern naming it. +def _fake_spl_core_report_tree(build_dir: Path, component: str) -> None: + """Write what spl-core's configure step writes into a build directory. `component` is a path such as `components/light_controller`, so the pages - land where spl-core writes them and the returned include pattern is the - `generated/...` name it now passes for both build shapes. + land where spl-core writes them. The component's `__source_docs/index` and + the variant-wide `reports/coverage` are included because the pages link + them, and a report toctree that cannot resolve is the failure these tests + are watching for. """ - root = FAKE_GENERATED_BUILD / component / "reports" - root.mkdir(parents=True, exist_ok=True) + reports = build_dir / component / "reports" + reports.mkdir(parents=True, exist_ok=True) for page in SPL_CORE_REPORT_PAGES: - (root / f"{page}.rst").write_text( + (reports / f"{page}.rst").write_text( f"{page}\n{'=' * len(page)}\n\nGenerated by spl-core at configure time.\n", encoding="utf-8", ) - return f"generated/{component}/reports/**" + + listings = build_dir / component / "__source_docs" + listings.mkdir(parents=True, exist_ok=True) + (listings / "index.rst").write_text( + "Source Files\n============\n\nNo listing in this fixture.\n", + encoding="utf-8", + ) + + variant_reports = build_dir / "reports" + variant_reports.mkdir(parents=True, exist_ok=True) + (variant_reports / "coverage.rst").write_text( + "Coverage\n========\n\nVariant-wide coverage.\n", + encoding="utf-8", + ) + + +def _selection_file(tmp_path: Path, build_dir: Path, shape: str) -> Path: + """A selection naming a fake build, as `tools/variant_data.py` would write it.""" + selection = tmp_path / f"selection-{shape}.toml" + selection.write_text( + variant_data.selection_toml( + variant_data.cell_path(PROJECT_ROOT, "Disco", "test", shape), + "Disco", + "test", + build_dir, + ), + encoding="utf-8", + ) + return selection + + +def _build_with_selection(selection: Path, out_dir: Path) -> subprocess.CompletedProcess: + """Build with `-D spl_selection=<file>`, the way a build's own run does.""" + env = {**os.environ, "VARIANT": "Disco"} + env.pop("SPHINX_BUILD_CONFIGURATION_FILE", None) + return subprocess.run( + [sys.executable, "-m", "sphinx", "-b", "html", "-D", f"spl_selection={selection}", str(PROJECT_ROOT), str(out_dir)], + cwd=PROJECT_ROOT, + env=env, + capture_output=True, + text=True, + ) def test_the_docs_shape_does_not_read_the_generated_report_pages(all_variant_data: None, tmp_path: Path) -> None: - """spl-core lists the report pages for both shapes; the variant rule keeps - them out of a docs build. + """spl-core writes the report pages for both shapes; a docs build must not read them. They exist from configure time, and in a docs build the fences that would link them are false -- so reading them yields three documents per component - that no toctree references. The `if = 'var.build_config.target == "reports"'` - rule over `generated/**` in ubproject.toml is what removes them now, declared - once where ubCode reads it too, instead of a Sphinx-only filter. - - This needs no compiler: the only thing a CMake build contributes here is the - config.json, and that is three lines of JSON. + that no toctree references. The mount's condition, which names the build's + own target, is what keeps them out now: the selection is the same file a + reports build reads, and the condition gates the mount off. Declared once, + where ubCode reads it too, instead of a Sphinx-only filter. """ - with _generated_points_at(FAKE_GENERATED_BUILD): - pattern = _fake_spl_core_report_tree("components/light_controller") - out = tmp_path / "docs_html" - result = _build_with_spl_core_env("docs", out, tmp_path, {"target": "docs", "include_patterns": [pattern]}) - assert result.returncode == 0, (result.stdout + result.stderr)[-2000:] + build_dir = tmp_path / "build" / "Disco" / "test" / "Debug" + _fake_spl_core_report_tree(build_dir, "components/light_controller") + selection = _selection_file(tmp_path, build_dir, "docs") + + out = tmp_path / "docs_html" + result = _build_with_selection(selection, out) + assert result.returncode == 0, (result.stdout + result.stderr)[-2000:] - # Sphinx writes warnings to stderr, so scanning stdout alone made an - # earlier version of this test pass with the fix reverted. - log = result.stdout + result.stderr - offenders = [line for line in log.splitlines() if "generated/" in line and "WARNING" in line] - assert not offenders, "the docs shape read the generated report pages:\n" + "\n".join(offenders) + # Sphinx writes warnings to stderr, so scanning stdout alone made an + # earlier version of this test pass with the fix reverted. + log = result.stdout + result.stderr + offenders = [line for line in log.splitlines() if "generated/" in line and "WARNING" in line] + assert not offenders, "the docs shape read the generated report pages:\n" + "\n".join(offenders) - for page in SPL_CORE_REPORT_PAGES: - built = out / "generated" / "components" / "light_controller" / "reports" / f"{page}.html" - assert not built.is_file(), f"the docs shape built {page}" + for page in SPL_CORE_REPORT_PAGES: + built = out / "generated" / "components" / "light_controller" / "reports" / f"{page}.html" + assert not built.is_file(), f"the docs shape built {page}" def test_the_reports_shape_still_reads_them(all_variant_data: None, tmp_path: Path) -> None: @@ -514,27 +577,29 @@ def test_the_reports_shape_still_reads_them(all_variant_data: None, tmp_path: Pa The fixed `/generated/...` toctree names have to resolve, or Sphinx reports a nonexisting document and the page links nothing at all. """ - with _generated_points_at(FAKE_GENERATED_BUILD): - pattern = _fake_spl_core_report_tree("components/light_controller") - out = tmp_path / "reports_html" - result = _build_with_spl_core_env("reports", out, tmp_path, {"target": "reports", "include_patterns": [pattern]}) - assert result.returncode == 0, (result.stdout + result.stderr)[-2000:] + build_dir = tmp_path / "build" / "Disco" / "test" / "Debug" + _fake_spl_core_report_tree(build_dir, "components/light_controller") + selection = _selection_file(tmp_path, build_dir, "reports") - log = result.stdout + result.stderr - unresolved = [ - line - for line in log.splitlines() - if "nonexisting document" in line and "generated/components/light_controller/reports" in line - ] - assert not unresolved, "the report toctree did not resolve:\n" + "\n".join(unresolved) + out = tmp_path / "reports_html" + result = _build_with_selection(selection, out) + assert result.returncode == 0, (result.stdout + result.stderr)[-2000:] + + log = result.stdout + result.stderr + unresolved = [ + line + for line in log.splitlines() + if "nonexisting document" in line and "generated/components/light_controller/reports" in line + ] + assert not unresolved, "the report toctree did not resolve:\n" + "\n".join(unresolved) - for page in SPL_CORE_REPORT_PAGES: - assert (out / "generated" / "components" / "light_controller" / "reports" / f"{page}.html").is_file() + for page in SPL_CORE_REPORT_PAGES: + assert (out / "generated" / "components" / "light_controller" / "reports" / f"{page}.html").is_file() - document = (out / "components" / "light_controller" / "doc" / "index.html").read_text(encoding="utf-8") - for page in SPL_CORE_REPORT_PAGES: - href = f"generated/components/light_controller/reports/{page}.html" - assert href in document, f"the light_controller page does not link {page}" + document = (out / "components" / "light_controller" / "doc" / "index.html").read_text(encoding="utf-8") + for page in SPL_CORE_REPORT_PAGES: + href = f"generated/components/light_controller/reports/{page}.html" + assert href in document, f"the light_controller page does not link {page}" # --- the generated listings must not show their Jinja armour ---------------- @@ -546,8 +611,8 @@ def test_generated_source_listings_carry_no_jinja_markers(all_variant_data: None The global Jinja pass used to consume those markers. It is gone, so the flag is what keeps them out: CMakeLists.txt sets SPL_SOURCE_DOCS_JINJA_RAW_TAGS OFF, and spl-core then invokes clanguru without `--jinja-raw-tags`. This - generates the fixture the same way and builds it, so it tracks what the - build actually emits rather than a hand-written idea of it. + generates the fixture the same way and builds it through the mount, so it + tracks what the build actually emits rather than a hand-written idea of it. """ cmake = (PROJECT_ROOT / "CMakeLists.txt").read_text(encoding="utf-8") assert _cmake_set(cmake, "SPL_SOURCE_DOCS_JINJA_RAW_TAGS") == "OFF", ( @@ -561,37 +626,37 @@ def test_generated_source_listings_carry_no_jinja_markers(all_variant_data: None source = tmp_path / "sample.c" source.write_text("int add(int a, int b) { return a + b; }\n", encoding="utf-8") - with _generated_points_at(FAKE_GENERATED_BUILD): - component = "components/light_controller" - listing_dir = FAKE_GENERATED_BUILD / component / "__source_docs" - listing_dir.mkdir(parents=True, exist_ok=True) - listing = listing_dir / "sample_c.rst" - subprocess.run( - [clanguru, "docs", "--source-file", str(source), "--output-file", str(listing), "--format", "rst"], - check=True, - capture_output=True, - ) - assert "{% raw %}" not in listing.read_text(encoding="utf-8"), ( - "this is not what spl-core generates with the raw-tag flag off" - ) - (listing_dir / "index.rst").write_text( - "Source Files\n============\n\n.. toctree::\n :maxdepth: 1\n\n sample_c\n", - encoding="utf-8", - ) + build_dir = tmp_path / "build" / "Disco" / "test" / "Debug" + component = "components/light_controller" + _fake_spl_core_report_tree(build_dir, component) + listing_dir = build_dir / component / "__source_docs" + listing = listing_dir / "sample_c.rst" + subprocess.run( + [clanguru, "docs", "--source-file", str(source), "--output-file", str(listing), "--format", "rst"], + check=True, + capture_output=True, + ) + assert "{% raw %}" not in listing.read_text(encoding="utf-8"), ( + "this is not what spl-core generates with the raw-tag flag off" + ) + (listing_dir / "index.rst").write_text( + "Source Files\n============\n\n.. toctree::\n :maxdepth: 1\n\n sample_c\n", + encoding="utf-8", + ) - pattern = f"generated/{component}/__source_docs/**" - out = tmp_path / "html" - result = _build_with_spl_core_env("reports", out, tmp_path, {"target": "reports", "include_patterns": [pattern]}) - assert result.returncode == 0, (result.stdout + result.stderr)[-2000:] + selection = _selection_file(tmp_path, build_dir, "reports") + out = tmp_path / "html" + result = _build_with_selection(selection, out) + assert result.returncode == 0, (result.stdout + result.stderr)[-2000:] - page = out / "generated" / component / "__source_docs" / "sample_c.html" - assert page.is_file(), "the listing was not built" - rendered = page.read_text(encoding="utf-8") - for marker in ("{% raw %}", "{% endraw %}"): - assert marker not in rendered, f"{marker} reached the reader" - - # Syntax highlighting splits the code across spans, so assert on the - # text rather than the markup -- checking the raw HTML for a contiguous - # "int add" is how an earlier version of this test fooled itself. - text = re.sub(r"<[^>]+>", "", rendered) - assert "int" in text and "add" in text, "the listing did not contain the code" + page = out / "generated" / component / "__source_docs" / "sample_c.html" + assert page.is_file(), "the listing was not built" + rendered = page.read_text(encoding="utf-8") + for marker in ("{% raw %}", "{% endraw %}"): + assert marker not in rendered, f"{marker} reached the reader" + + # Syntax highlighting splits the code across spans, so assert on the text + # rather than the markup -- checking the raw HTML for a contiguous "int add" + # is how an earlier version of this test fooled itself. + text = re.sub(r"<[^>]+>", "", rendered) + assert "int" in text and "add" in text, "the listing did not contain the code" diff --git a/test/test_ubproject_config.py b/test/test_ubproject_config.py index 6431fba3..f69a5be1 100644 --- a/test/test_ubproject_config.py +++ b/test/test_ubproject_config.py @@ -14,7 +14,6 @@ """ import json -import os import re import runpy import subprocess @@ -27,6 +26,9 @@ from sphinx.util.matching import Matcher PROJECT_ROOT = Path(__file__).resolve().parent.parent +sys.path.insert(0, str(PROJECT_ROOT / "tools")) + +import variant_data # noqa: E402 pytestmark = [ pytest.mark.unittests, @@ -54,15 +56,34 @@ def spl_core_config() -> dict: # --- the file has to stand on its own -------------------------------------- -def test_does_not_extend_anything(project_config: dict) -> None: - """No `extend`, because only one of the two readers implements it. +def test_ubproject_extends_the_generated_rules(project_config: dict) -> None: + """The committed configuration extends exactly the generated rules file. - The path it used to name also had the Python minor version baked into it - and pointed at an interpreter that does not exist, so the base - configuration silently failed to resolve for ubCode while conf.py resolved - it a second time through importlib. + ubproject.toml has to keep its `[needs]` table complete for sphinx-needs, + which does not follow `extend`, but the document rules are generated and + live in a file of their own. This is the one `extend` left, and it names + only the file tools/variant_data.py writes. """ - assert "extend" not in project_config + assert project_config["extend"] == "ubproject.variants.toml" + + +def test_the_generated_rules_extend_the_selection() -> None: + """ubproject.toml -> ubproject.variants.toml -> build/selection.toml.""" + rules = tomllib.loads((PROJECT_ROOT / "ubproject.variants.toml").read_text(encoding="utf-8")) + assert rules["extend"] == "build/selection.toml" + + +def test_conf_py_names_both_generated_files_for_sphinx() -> None: + """sphinx-needs and sphinx-mounts read one TOML file each, no `extend`. + + conf.py hands each the file it needs: the complete needs model and the + generated rules. The selection it reads at config-inited defaults to + build/selection.toml, and `-D spl_selection=<file>` names a build's own. + """ + conf = (PROJECT_ROOT / "conf.py").read_text(encoding="utf-8") + assert 'needs_from_toml = "ubproject.toml"' in conf + assert 'sources_from_toml = "ubproject.variants.toml"' in conf + assert 'app.add_config_value("spl_selection", "build/selection.toml", "env", types=(str,))' in conf def test_sphinx_reads_this_exact_file() -> None: @@ -126,22 +147,57 @@ def test_build_output_is_not_indexed(project_config: dict) -> None: assert "build/**" in project_config["source"]["extend_exclude"] -def test_the_per_component_report_root_is_hidden_from_ubcode(project_config: dict) -> None: - """conf.py excludes it from every variant build, so ubCode must too. +def _removed_by_rules(rules: list[dict], data: dict, path: str) -> bool: + """Whether a document at `path` is removed for this cell. - doc/component_report.md is the root document of spl-core's PER-COMPONENT - report -- a build shape ubCode never performs. conf.py drops it from the - variant-wide source set, so Sphinx never sees it; ubCode indexed it anyway - and reported it as an orphan. Four orphans in one reader and five in the - other is the two of them disagreeing about the document set, which is the - one thing this configuration exists to prevent. + Rules are subtractive: a path is removed when a rule whose condition is FALSE + has a pattern matching it. Patterns are matched the way both readers match + them (sphinx-mounts' own dialect): against paths in the project tree, and + against a mounted build's files, relative to the mounted directory. + """ + from sphinx_mounts import dialect, variants - `[parse.parsers.*]` has no `exclude`, but `extend_exclude` is honoured in - parser mode -- unlike `extend_include` -- so that is where it belongs. + return any( + dialect.matches(pattern, path) + for rule in rules + if not variants.interpret(variants.validate(rule["if"]), data) + for pattern in rule["files"] + ) + + +def test_the_scope_rules_split_variant_and_component_documents(rules: list[dict]) -> None: + """A variant shows the variant-wide documents and the components it has. + + A component's report shows one component -- its documentation and generated + pages, under doc/component_report.md -- and none of the variant-wide + documents. The two facts are two rules over `var.build_config.scope`, + evaluated here with sphinx-mounts' own interpreter against the real + generated cells. """ - conf = (PROJECT_ROOT / "conf.py").read_text(encoding="utf-8") - assert 'exclude_patterns.append("doc/component_report.md")' in conf - assert "doc/component_report.md" in project_config["source"]["extend_exclude"] + variant_cell = _variant_data("Disco", "test", "reports") + component_cell = _component_variant_data("Disco", "test", "reports", "components/light_controller") + + # The variant cell: the variant-wide documents and its components' pages, + # in the tree and in the mounted build (whose paths are relative to it). + for path in ("index.md", "doc/components/index.md", "components/light_controller/doc/index.md", + "components/light_controller/reports/coverage.rst", "reports/coverage.rst"): + assert not _removed_by_rules(rules, variant_cell, path), f"the variant removes {path}" + for path in ("doc/component_report.md", "components/auto_off/doc/index.md"): + assert _removed_by_rules(rules, variant_cell, path), f"the variant keeps {path}" + + # The component cell: exactly the one component, and none of the + # variant-wide documents. The root index.md is not named by any rule -- a + # pattern without a slash would match every index.md -- and is an orphan + # page there, whose toctree entries are all excluded. + for path in ("doc/component_report.md", "components/light_controller/doc/index.md", + "components/light_controller/reports/coverage.rst", "components/light_controller/__source_docs/index.rst"): + assert not _removed_by_rules(rules, component_cell, path), f"the component report removes {path}" + for path in ("doc/components/index.md", "doc/sw_requirements/index.md", "reports/coverage.rst", + "components/main_control_knob/doc/index.md", "components/main_control_knob/reports/coverage.rst", + "components/auto_off/doc/index.md"): + assert _removed_by_rules(rules, component_cell, path), f"the component report keeps {path}" + assert not _removed_by_rules(rules, component_cell, "index.md") + assert "orphan: true" in (PROJECT_ROOT / "index.md").read_text(encoding="utf-8").split("---")[1] def test_extend_include_is_not_used_because_it_would_be_inert(project_config: dict, spl_core_config: dict) -> None: @@ -156,7 +212,9 @@ def test_extend_include_is_not_used_because_it_would_be_inert(project_config: di """ assert spl_core_config["source"]["extend_include"] == ["build/**/__source_docs/**"] assert "extend_include" not in project_config["source"] - assert project_config["parse"]["parsers"]["rst"]["include"] == ["generated/**/*.rst"] + # The generated listings are named by the rst parser instead, relative to the + # mounted directory (sphinx-mounts matches them inside the mount). + assert project_config["parse"]["parsers"]["rst"]["include"] == list(variant_data.MOUNTED_PAGES) def test_ubcode_and_sphinx_see_the_same_documents(project_config: dict) -> None: @@ -181,13 +239,30 @@ def test_ubcode_and_sphinx_see_the_same_documents(project_config: dict) -> None: for tree in ("index.md", "doc/**", "components/**/doc/**", "test/**/doc/**"): assert f'"{tree}"' in conf, f"conf.py does not include {tree}, which the md parser reads" + # The rst parser reads the mounted build, which Sphinx names `generated/`. + assert project_config["parse"]["parsers"]["rst"]["include"] == list(variant_data.MOUNTED_PAGES) + for pattern in project_config["parse"]["parsers"]["rst"]["include"]: + assert f'"generated/{pattern}"' in conf, ( + f"conf.py does not include generated/{pattern}, which the rst parser reads" + ) + # --- what the variant machinery needs -------------------------------------- -def test_variant_data_file_is_the_current_pointer(project_config: dict) -> None: - """What ubCode reads, and what a bare sphinx-build falls back to.""" - assert project_config["needs"]["variant_data_file"] == "build/autoconf.json" +def test_variant_data_is_named_by_the_selection_not_the_committed_config(project_config: dict) -> None: + """The committed configuration names no cell; a rendered selection does.""" + assert "variant_data_file" not in project_config.get("needs", {}) + + rendered = variant_data.selection_toml( + PROJECT_ROOT / "build" / "variants" / "Disco" / "test" / "reports.json", + "Disco", + "test", + None, + ) + selection = tomllib.loads(rendered) + assert selection["needs"]["variant_data_file"].endswith("build/variants/Disco/test/reports.json") + assert selection["source"]["mounts"] == [] def test_needs_json_is_written(project_config: dict) -> None: @@ -203,8 +278,10 @@ def test_needs_json_is_written(project_config: dict) -> None: @pytest.fixture(scope="module") -def rules(project_config: dict) -> list[dict]: - return project_config["source"]["variant_sources"] +def rules(generated_variant_data: None) -> list[dict]: + """The document rules, as tools/variant_data.py wrote them.""" + text = (PROJECT_ROOT / "ubproject.variants.toml").read_text(encoding="utf-8") + return tomllib.loads(text)["source"]["variant_sources"] @pytest.fixture(scope="module", autouse=True) @@ -228,6 +305,12 @@ def _variant_data(variant: str, kit: str, target: str) -> dict: return json.load(handle) +def _component_variant_data(variant: str, kit: str, target: str, component: str) -> dict: + path = PROJECT_ROOT / "build" / "variants" / variant / kit / component / f"{target}.json" + with path.open(encoding="utf-8") as handle: + return json.load(handle) + + def test_every_component_document_is_gated_by_a_rule(rules: list[dict]) -> None: """A hand-written component document with no rule is 150% in every variant. @@ -235,10 +318,14 @@ def test_every_component_document_is_gated_by_a_rule(rules: list[dict]) -> None: every need in it would enter their traceability data. The failure is additive and silent, which is why it needs a test rather than a review. """ - gated = {pattern for rule in rules for pattern in rule["files"]} + from sphinx_mounts import dialect + + patterns = [pattern for rule in rules for pattern in rule["files"]] for doc_dir in sorted(PROJECT_ROOT.glob("components/**/doc")) + sorted(PROJECT_ROOT.glob("test/*/doc")): rel = doc_dir.relative_to(PROJECT_ROOT).as_posix() - assert f"{rel}/**" in gated, f"{rel} is not gated by any [[source.variant_sources]] rule" + assert any(dialect.matches(pattern, f"{rel}/index.md") for pattern in patterns), ( + f"{rel} is not gated by any generated rule" + ) def test_no_rule_names_a_variant_by_name(rules: list[dict]) -> None: @@ -269,47 +356,51 @@ def test_every_rule_condition_is_inside_the_grammar(rules: list[dict]) -> None: [ # Disco: BLINKING, so no brightness; no auto-off; integration suite in # the test kit only. - ("Disco", "test", ["components/light_controller/doc/**", "test/spled_integration/doc/**"], ["components/auto_off/doc/**", "components/brightness_controller/doc/**"]), - ("Disco", "prod", ["components/light_controller/doc/**"], ["test/spled_integration/doc/**", "components/auto_off/doc/**"]), + ("Disco", "test", ["components/light_controller/doc/index.md", "test/spled_integration/doc/index.md"], ["components/auto_off/doc/index.md", "components/brightness_controller/doc/index.md"]), + ("Disco", "prod", ["components/light_controller/doc/index.md"], ["test/spled_integration/doc/index.md", "components/auto_off/doc/index.md"]), # Sleep: manual brightness and auto-off, no integration suite. - ("Sleep", "test", ["components/auto_off/doc/**", "components/brightness_controller/doc/**"], ["test/spled_integration/doc/**"]), + ("Sleep", "test", ["components/auto_off/doc/index.md", "components/brightness_controller/doc/index.md"], ["test/spled_integration/doc/index.md"]), # Spa: brightness but no auto-off. - ("Spa", "test", ["components/brightness_controller/doc/**"], ["components/auto_off/doc/**"]), + ("Spa", "test", ["components/brightness_controller/doc/index.md"], ["components/auto_off/doc/index.md"]), # Base/Dev: the example components, none of the product ones. - ("Base/Dev", "test", ["components/examples/hello_gmock/doc/**"], ["components/light_controller/doc/**", "components/auto_off/doc/**"]), + ("Base/Dev", "test", ["components/examples/hello_gmock/doc/index.md"], ["components/light_controller/doc/index.md", "components/auto_off/doc/index.md"]), ], ) def test_rules_select_the_expected_documents(rules: list[dict], variant: str, kit: str, expect_present: list[str], expect_absent: list[str]) -> None: - from sphinx_mounts import variants - data = _variant_data(variant, kit, "docs") - included: set[str] = set() - excluded: set[str] = set() - for rule in rules: - ok = variants.interpret(variants.validate(rule["if"]), data) - (included if ok else excluded).update(rule["files"]) - - for pattern in expect_present: - assert pattern in included, f"{variant}/{kit}: expected {pattern} to be included" - assert pattern not in excluded, f"{variant}/{kit}: {pattern} is both included and excluded" - for pattern in expect_absent: - assert pattern in excluded, f"{variant}/{kit}: expected {pattern} to be excluded" + for path in expect_present: + assert not _removed_by_rules(rules, data, path), f"{variant}/{kit}: expected {path} to be included" + for path in expect_absent: + assert _removed_by_rules(rules, data, path), f"{variant}/{kit}: expected {path} to be excluded" -def test_generated_output_is_gated_on_the_reports_target(rules: list[dict]) -> None: - """A docs build must not read report pages it will not show. +def test_the_mount_condition_names_the_builds_own_cell(tmp_path: Path) -> None: + """The mount's condition does name a variant -- the build's own. - Rules are subtractive -- a FALSE rule removes the files it names, a TRUE - one does nothing -- so this rule and the per-component ones compose as AND. + A reader pointed at another variant's data then reads none of this build's + pages, instead of showing them as that variant's. `selection_toml` renders + the condition; this evaluates it against the real cells. """ from sphinx_mounts import variants - shape_rule = next(r for r in rules if "target" in r["if"]) - assert shape_rule["files"] == ["generated/**"] + build_dir = tmp_path / "build" / "Disco" / "test" / "Debug" + build_dir.mkdir(parents=True) - tree = variants.validate(shape_rule["if"]) + rendered = variant_data.selection_toml( + PROJECT_ROOT / "build" / "variants" / "Disco" / "test" / "reports.json", + "Disco", + "test", + build_dir, + ) + mount = tomllib.loads(rendered)["source"]["mounts"][0] + assert mount["mount_at"] == variant_data.MOUNT_AT + assert mount["include"] == list(variant_data.MOUNTED_PAGES) + assert mount["gitignore"] is False + + tree = variants.validate(mount["if"]) assert variants.interpret(tree, _variant_data("Disco", "test", "reports")) is True assert variants.interpret(tree, _variant_data("Disco", "test", "docs")) is False + assert variants.interpret(tree, _variant_data("Sleep", "test", "reports")) is False #: The report pages spl-core writes per component, and the names a report @@ -385,11 +476,14 @@ def test_report_sections_name_the_generated_pages() -> None: ) if component is not None: expected = {f"/generated/{component}/reports/{page}" for page in REPORT_PAGES} + expected.add(f"/generated/{component}/__source_docs/index") assert set(entries) == expected, ( f"{document.relative_to(PROJECT_ROOT)}: expected {sorted(expected)}, got {sorted(entries)}" ) - assert report_documents == 8, f"expected 8 report toctrees, found {report_documents}" + # Nine component documents (the two examples included) plus index.md's + # coverage toctree. + assert report_documents == 10, f"expected 10 report toctrees, found {report_documents}" def _excluded(matcher: Matcher, path: str) -> bool: @@ -407,7 +501,7 @@ def _excluded(matcher: Matcher, path: str) -> bool: return False -def test_generated_is_the_only_route_to_the_generated_pages(tmp_path: Path, monkeypatch: pytest.MonkeyPatch, project_config: dict) -> None: +def test_generated_is_the_only_route_to_the_generated_pages(monkeypatch: pytest.MonkeyPatch) -> None: """With two routes, every generated page exists under two docnames. spl-core's include patterns name the build directory both ways in a SPLed @@ -415,27 +509,16 @@ def test_generated_is_the_only_route_to_the_generated_pages(tmp_path: Path, monk `generated/...` name. conf.py must forward only the `generated/` one and prune the whole `build` tree from the Sphinx walk, or each report page is discovered twice -- once per name -- and every link and need in it is - duplicated. This executes conf.py against a controlled configuration rather - than grepping its text, because the property is the resulting source set and - the resulting matcher. + duplicated. This executes conf.py rather than grepping its text, because the + property is the resulting source set and the resulting matcher. """ - config = { - "include_patterns": [ - "components/light_controller/doc/**", - "build/Disco/test/Debug/components/light_controller/reports/**", - "generated/components/light_controller/reports/**", - ], - } - config_file = tmp_path / "config.json" - config_file.write_text(json.dumps(config), encoding="utf-8") - - monkeypatch.setenv("SPHINX_BUILD_CONFIGURATION_FILE", str(config_file)) monkeypatch.setenv("VARIANT", "Disco") module = runpy.run_path(str(PROJECT_ROOT / "conf.py")) include_patterns = module["include_patterns"] - assert "generated/components/light_controller/reports/**" in include_patterns + for pattern in variant_data.MOUNTED_PAGES: + assert f"generated/{pattern}" in include_patterns assert not [pattern for pattern in include_patterns if pattern.startswith("build/")] matcher = Matcher(module["exclude_patterns"]) @@ -449,6 +532,38 @@ def test_generated_is_the_only_route_to_the_generated_pages(tmp_path: Path, monk cmake = (PROJECT_ROOT / "CMakeLists.txt").read_text(encoding="utf-8") assert re.search(r"set\(\s*SPL_SPHINX_BINARY_DIR\s+\$\{CMAKE_SOURCE_DIR\}/generated\s*\)", cmake), ( - "CMakeLists.txt must name the generated link as SPL_SPHINX_BINARY_DIR" + "CMakeLists.txt must mount the build at the stable generated/ name" ) - assert project_config["parse"]["parsers"]["rst"]["include"] == ["generated/**/*.rst"] + assert re.search( + r"set\(\s*SPL_SPHINX_OPTIONS\s+-D\s+spl_selection=\$\{CMAKE_BINARY_DIR\}/selection/@SHAPE@\.toml\s*\)", + cmake, + ), "CMakeLists.txt must point the variant-wide runs at this build's selection" + assert re.search( + r"set\(\s*SPL_SPHINX_COMPONENT_OPTIONS\s+-D\s+spl_selection=\$\{CMAKE_BINARY_DIR\}/selection/@COMPONENT_PATH@/@SHAPE@\.toml\s*\)", + cmake, + ), "CMakeLists.txt must point the per-component runs at this build's selection" + + +# --- the same checks, as conf.py runs them ------------------------------------ + + +def test_the_checks_conf_py_runs_find_nothing() -> None: + """conf.py runs tools/config_checks.py whenever Sphinx reads its configuration. + + The tests above are the detailed form of those checks; this one runs exactly + what a Sphinx build runs, with the include patterns conf.py really ends up + with, so a build under -W and this suite cannot disagree about whether the + configuration is intact. + """ + import config_checks # noqa: PLC0415 - tools/ is on sys.path, see above + + module = runpy.run_path(str(PROJECT_ROOT / "conf.py")) + assert config_checks.run_all(PROJECT_ROOT, list(module["include_patterns"])) == [] + + +def test_the_checks_notice_a_hand_written_rule(project_config: dict) -> None: + """A rule in ubproject.toml would replace every generated one: `extend` replaces arrays.""" + import config_checks # noqa: PLC0415 + + tampered = {**project_config, "source": {**project_config["source"], "variant_sources": [{"if": "True", "files": ["x"]}]}} + assert any("declares rules" in finding for finding in config_checks.generated_half(tampered)) diff --git a/test/test_variant_data.py b/test/test_variant_data.py index 1de89c89..c7c4a9ff 100644 --- a/test/test_variant_data.py +++ b/test/test_variant_data.py @@ -13,7 +13,9 @@ """ import json +import os import sys +import tomllib from pathlib import Path import pytest @@ -193,107 +195,239 @@ def test_every_cell_carries_the_whole_contract(variant: str, kit: str, target: s assert data["build_config"]["kit"] == kit assert data["build_config"]["target"] == target assert data["build_config"]["components"] + assert data["build_config"]["scope"] == "variant" + assert data["build_config"]["component"] == "" assert data["features"] # It has to survive the round trip to the file both tools read. assert json.loads(json.dumps(data)) == data -# --- the current-variant pointer ------------------------------------------- +@pytest.mark.parametrize("variant", ["Base/Dev", "Disco", "IDEA/Sloemada", "Sleep", "Spa"]) +@pytest.mark.parametrize("kit", variant_data.KITS) +@pytest.mark.parametrize("target", variant_data.TARGETS) +def test_every_component_cell_carries_the_whole_contract(variant: str, kit: str, target: str) -> None: + """A component's report gets the same complete contract, one scope deeper. + + The component list stays the variant's, so a block conditioned on another + component's presence reads the same in a component's report as in the + variant's documentation; only `scope` and `component` differ. + """ + documented = variant_data.reported_components(PROJECT_ROOT, variant, kit) + assert documented, f"{variant}/{kit} has no documented component to report on" + + for component in documented: + data = variant_data.variant_data(PROJECT_ROOT, variant, kit, target, component) + + assert set(data) == {"features", "build_config"} + assert data["build_config"]["variant"] == variant + assert data["build_config"]["kit"] == kit + assert data["build_config"]["target"] == target + assert data["build_config"]["scope"] == "component" + assert data["build_config"]["component"] == component + assert data["build_config"]["components"] == variant_data.components(PROJECT_ROOT, variant, kit) + assert data["features"] + assert json.loads(json.dumps(data)) == data + + +# --- the rendered selection ------------------------------------------------ + + +def _tmp_project(tmp_path: Path) -> Path: + """A small project root with a parts.cmake and two documented components.""" + root = tmp_path / "project" + parts = root / "variants" / "Test" + parts.mkdir(parents=True) + (parts / "parts.cmake").write_text( + "spl_add_component(components/a)\nspl_add_component(test/suite)\n", + encoding="utf-8", + ) + for component in ("components/a", "test/suite"): + doc = root / component / "doc" + doc.mkdir(parents=True) + (doc / "index.md").write_text(f"# {component}\n", encoding="utf-8") + return root + + +def test_selection_toml_without_a_build_dir_mounts_nothing(tmp_path: Path) -> None: + """Selecting a cell on its own shows its documents and no generated page.""" + cell = variant_data.cell_path(PROJECT_ROOT, "Disco", "test", "reports") + selection = tomllib.loads(variant_data.selection_toml(cell, "Disco", "test", None)) + assert selection["needs"]["variant_data_file"] == cell.resolve().as_posix() + assert selection["source"]["mounts"] == [] + assert "project" not in selection -def test_the_pointer_is_a_symlink_where_the_platform_allows_one(tmp_path: Path) -> None: - """A symlink is cheap and clear where the OS permits one.""" - build_dir = tmp_path / "build" / "V" / "test" / "Debug" + +def test_selection_toml_with_a_build_dir_mounts_it(tmp_path: Path) -> None: + """A CMake build mounts its own directory at the stable `generated` name.""" + build_dir = tmp_path / "build" / "Disco" / "test" / "Debug" build_dir.mkdir(parents=True) - (build_dir / "payload.txt").write_text("x", encoding="utf-8") + cell = variant_data.cell_path(PROJECT_ROOT, "Disco", "test", "reports") - variant_data.write_pointer(tmp_path, {"features": {}, "build_config": {}}, build_dir) + selection = tomllib.loads(variant_data.selection_toml(cell, "Disco", "test", build_dir)) + mount = selection["source"]["mounts"][0] - generated = tmp_path / "generated" - assert generated.is_symlink() - assert (generated / "payload.txt").is_file() + assert mount["dir"] == build_dir.resolve().as_posix() + assert mount["mount_at"] == variant_data.MOUNT_AT + assert mount["include"] == list(variant_data.MOUNTED_PAGES) + assert mount["gitignore"] is False + assert "Disco" in mount["if"] and "test" in mount["if"] and "reports" in mount["if"] -def test_a_refused_symlink_falls_back_to_a_junction(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: - """Windows without Developer Mode refuses a symlink but allows a junction. +def test_selection_toml_can_name_a_component_root_doc(tmp_path: Path) -> None: + """A per-component report renders under its own root document.""" + cell = variant_data.cell_path(PROJECT_ROOT, "Disco", "test", "reports", "components/light_controller") + selection = tomllib.loads( + variant_data.selection_toml(cell, "Disco", "test", None, variant_data.COMPONENT_ROOT_DOC) + ) + assert selection["project"]["root_doc"] == variant_data.COMPONENT_ROOT_DOC - The junction is the fallback that keeps Sphinx able to walk `generated` - without copying the binary directory. Only Windows takes this path, which is - why it needs a test rather than the platform nobody develops on finding out. + +def test_write_selection_writes_the_project_selection_and_every_run(tmp_path: Path) -> None: + """A selected build gets one selection file per spl-core documentation run. + + build/selection.toml is what the IDE and a bare run read; every shape and + every component of the build gets its own file, so two builds' reports can + be built side by side and each names the cell of its own shape. """ - build_dir = tmp_path / "build" / "V" / "test" / "Debug" - (build_dir / "CMakeFiles").mkdir(parents=True) - (build_dir / "CMakeFiles" / "huge.o").write_text("x" * 1000, encoding="utf-8") + root = _tmp_project(tmp_path) + build_dir = root / "build" / "Test" / "test" / "Debug" + build_dir.mkdir(parents=True) - calls: list[tuple[Path, Path]] = [] + variant_data.write_selection(root, "Test", "test", "reports", build_dir) - def refuse(*args, **kwargs): - raise OSError("symlinks not permitted") + selection = tomllib.loads((root / variant_data.SELECTION_FILE).read_text(encoding="utf-8")) + assert selection["needs"]["variant_data_file"] == variant_data.cell_path( + root, "Test", "test", "reports" + ).resolve().as_posix() - def fake_junction(target: Path, link: Path) -> None: - calls.append((target, link)) - link.mkdir(parents=True, exist_ok=True) + for shape in variant_data.TARGETS: + run = build_dir / "selection" / f"{shape}.toml" + assert run.is_file(), f"the variant-wide {shape} run has no selection" + assert tomllib.loads(run.read_text(encoding="utf-8"))["needs"]["variant_data_file"] == ( + variant_data.cell_path(root, "Test", "test", shape).resolve().as_posix() + ) - monkeypatch.setattr(Path, "symlink_to", refuse) - monkeypatch.setattr(variant_data, "_create_junction", fake_junction) + for component in variant_data.reported_components(root, "Test", "test"): + for shape in variant_data.TARGETS: + run = build_dir / "selection" / component / f"{shape}.toml" + assert run.is_file(), f"{component}'s {shape} run has no selection" + parsed = tomllib.loads(run.read_text(encoding="utf-8")) + assert parsed["needs"]["variant_data_file"] == ( + variant_data.cell_path(root, "Test", "test", shape, component).resolve().as_posix() + ) + assert parsed["project"]["root_doc"] == variant_data.COMPONENT_ROOT_DOC - variant_data.write_pointer(tmp_path, {"features": {}, "build_config": {}}, build_dir) - generated = tmp_path / "generated" - assert calls == [(build_dir.resolve(), generated)], "the junction must lead to the resolved build directory" - assert generated.is_dir() and not generated.is_symlink() - assert not (generated / "NO_SYMLINK").exists(), "the junction is a real link, not an explanation" - assert not (generated / "CMakeFiles").exists(), "the fallback copied the binary directory" +def test_selecting_removes_an_old_generated_symlink_without_touching_its_target(tmp_path: Path) -> None: + """The old link is removed; the build it led to is somebody's and stays.""" + root = _tmp_project(tmp_path) + target = tmp_path / "old_build" + target.mkdir() + (target / "keep.txt").write_text("keep", encoding="utf-8") + generated = root / "generated" + generated.symlink_to(target, target_is_directory=True) + variant_data.write_selection(root, "Test", "prod", "docs", None) -def test_neither_link_leaves_an_explained_directory(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: - """When both link types fail, the path still exists and says why. + assert not generated.exists(), "the stale link must be removed" + assert (target / "keep.txt").read_text(encoding="utf-8") == "keep", "the target must survive" - spl-core stops a documentation build whose `generated` does not lead to its - build directory, so the failure has to be a named one rather than a missing - path -- and copying the binary directory, as the old fallback did, would - leak build objects into the source tree without producing the reports. - """ - build_dir = tmp_path / "build" / "V" / "test" / "Debug" - (build_dir / "CMakeFiles").mkdir(parents=True) - (build_dir / "CMakeFiles" / "huge.o").write_text("x" * 1000, encoding="utf-8") - def refuse(*args, **kwargs): - raise OSError("no links here") +def test_selecting_removes_the_old_autoconf_pointer(tmp_path: Path) -> None: + """`build/autoconf.json` was the pointer; nothing reads it any more.""" + root = _tmp_project(tmp_path) + pointer = root / "build" / "autoconf.json" + pointer.parent.mkdir(parents=True) + pointer.write_text("{}", encoding="utf-8") + + variant_data.write_selection(root, "Test", "prod", "docs", None) + + assert not pointer.exists() + + +def test_selecting_removes_a_no_symlink_placeholder(tmp_path: Path) -> None: + """A directory holding NO_SYMLINK is the old placeholder, and goes.""" + root = _tmp_project(tmp_path) + generated = root / "generated" + generated.mkdir() + (generated / "NO_SYMLINK").write_text("no link here\n", encoding="utf-8") + + variant_data.write_selection(root, "Test", "prod", "docs", None) - monkeypatch.setattr(Path, "symlink_to", refuse) - monkeypatch.setattr(variant_data, "_create_junction", refuse) + assert not generated.exists() - variant_data.write_pointer(tmp_path, {"features": {}, "build_config": {}}, build_dir) - generated = tmp_path / "generated" - assert generated.is_dir() and not generated.is_symlink() - assert [p.name for p in generated.iterdir()] == ["NO_SYMLINK"] - assert str(build_dir.resolve()) in (generated / "NO_SYMLINK").read_text(encoding="utf-8") - assert not (generated / "CMakeFiles").exists(), "the fallback copied the binary directory" +def test_selecting_leaves_a_plain_generated_directory_alone(tmp_path: Path) -> None: + """A real directory somebody put there is not ours to remove.""" + root = _tmp_project(tmp_path) + generated = root / "generated" + generated.mkdir() + (generated / "somebody.txt").write_text("mine", encoding="utf-8") + variant_data.write_selection(root, "Test", "prod", "docs", None) -def test_repointing_generated_leaves_the_old_build_untouched(tmp_path: Path) -> None: - """Re-pointing the link must never touch the directory it used to lead to. + assert (generated / "somebody.txt").read_text(encoding="utf-8") == "mine" - `_remove_link` removes the link itself, not its target, so switching from - one configured variant to another does not delete the previous build. A - `shutil.rmtree` on the resolved target would, silently, on every reconfigure. + +# --- the generated rules --------------------------------------------------- + + +def _parsed_rules(root: Path) -> list[dict]: + return tomllib.loads(variant_data.rules_toml(root))["source"]["variant_sources"] + + +def test_rules_toml_covers_every_documented_component_exactly_once(tmp_path: Path) -> None: + """A hand-written component with no rule is 150% in every variant. + + The failure is additive and silent -- its documents appear in variants that + do not contain the component -- so each documented component has exactly one + rule naming it. """ - first = tmp_path / "build" / "first" - second = tmp_path / "build" / "second" - for build_dir, name in ((first, "first.txt"), (second, "second.txt")): - build_dir.mkdir(parents=True, exist_ok=True) - (build_dir / name).write_text(name, encoding="utf-8") - - variant_data.write_pointer(tmp_path, {"features": {}, "build_config": {}}, first) - generated = tmp_path / "generated" - assert (generated / "first.txt").is_file() - - variant_data.write_pointer(tmp_path, {"features": {}, "build_config": {}}, second) - assert generated.resolve() == second.resolve() - assert (generated / "second.txt").is_file() - - assert first.is_dir(), "the old build directory was removed" - assert (first / "first.txt").read_text(encoding="utf-8") == "first.txt" + root = _tmp_project(tmp_path) + rules = _parsed_rules(root) + documented = variant_data.documented_components(root) + assert documented == ["components/a", "test/suite"] + + for component in documented: + matching = [rule for rule in rules if f"'{component}'" in rule["if"]] + assert len(matching) == 1, f"{component} is gated by {len(matching)} rules" + # One pattern, matched in the tree and inside a mounted build alike. + assert matching[0]["files"] == [f"{component}/**"] + + +def test_every_generated_rule_condition_is_inside_the_grammar(tmp_path: Path) -> None: + """A condition outside the grammar is refused rather than evaluated.""" + from sphinx_mounts import variants + + for rule in _parsed_rules(_tmp_project(tmp_path)): + variants.validate(rule["if"]) + + +def test_hand_written_rules_are_appended(tmp_path: Path) -> None: + """Numbers a component's membership cannot decide come from a hand file.""" + root = _tmp_project(tmp_path) + (root / "doc").mkdir() + (root / variant_data.HAND_WRITTEN_RULES).write_text( + '[[source.variant_sources]]\nif = "var.build_config.scope == \'variant\'"\nfiles = ["extra/**"]\n', + encoding="utf-8", + ) + + rules = _parsed_rules(root) + assert rules[-1]["if"] == "var.build_config.scope == 'variant'" + assert rules[-1]["files"] == ["extra/**"] + + +def test_write_text_if_changed_does_not_rewrite_identical_content(tmp_path: Path) -> None: + """A reader's cache stays valid when the content has not changed.""" + path = tmp_path / "file.txt" + assert variant_data.write_text_if_changed(path, "same") is True + + os.utime(path, (1_000_000, 1_000_000)) + before = path.stat().st_mtime_ns + assert variant_data.write_text_if_changed(path, "same") is False + assert path.stat().st_mtime_ns == before, "identical content was rewritten" + + assert variant_data.write_text_if_changed(path, "different") is True + assert path.read_text(encoding="utf-8") == "different" diff --git a/tools/compile_commands.py b/tools/compile_commands.py new file mode 100644 index 00000000..0d9b4f22 --- /dev/null +++ b/tools/compile_commands.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +"""Hand codelinks the selected build's compile database. + +codelinks evaluates each source file's `#ifdef` branches with the build's compile +database, so a variant's one-line needs are the ones that variant compiles. Both +readers take the database from one fixed path, `build/compile_commands.json` +(ubproject.toml), because the path cannot follow the selection: `extend` and +ubc's `-c` both replace a codelinks project's whole table rather than one key in +it. CMake writes the database only into its build directory, so this copies it +to that path -- for the selected build only, the one `build/selection.toml` +mounts, so building another variant leaves the editor's database alone. + +The test kit compiles with `-save-temps`, which libclang cannot load a file with: +codelinks would skip every file, and its needs would disappear. The copy leaves +that option out. Once codelinks drops it itself, the filter can go. + +Run by the `spled_codelinks_compile_commands` target (CMakeLists.txt) on every +build, and after a configure without a build: + + cmake --build <build dir> --target spled_codelinks_compile_commands +""" + +from __future__ import annotations + +import argparse +import json +import re +import sys +import tomllib +from pathlib import Path +from typing import Any + +PROJECT_ROOT = Path(__file__).resolve().parent.parent + +#: Where codelinks reads the database (ubproject.toml). +TARGET = "build/compile_commands.json" + +#: The selection whose build directory is the one to copy from. +SELECTION = "build/selection.toml" + +#: `-save-temps` and `-save-temps=obj|cwd`, as a whole token. +_SAVE_TEMPS = re.compile(r"(?<!\S)-save-temps(?:=\S+)?(?:\s+|$)") + + +def selected_build_dir(project_root: Path) -> Path | None: + """The build directory the selection mounts, or None if it names no build.""" + path = project_root / SELECTION + if not path.is_file(): + return None + mounts = tomllib.loads(path.read_text(encoding="utf-8")).get("source", {}).get("mounts", []) + return Path(mounts[0]["dir"]).resolve() if mounts else None + + +def without_save_temps(entries: list[dict[str, Any]]) -> list[dict[str, Any]]: + result = [] + for entry in entries: + entry = dict(entry) + if "command" in entry: + entry["command"] = _SAVE_TEMPS.sub("", entry["command"]).rstrip() + if "arguments" in entry: + entry["arguments"] = [argument for argument in entry["arguments"] if not _SAVE_TEMPS.fullmatch(argument)] + result.append(entry) + return result + + +def main(argv: list[str] | None = None) -> int: + parser = argparse.ArgumentParser(description=__doc__.splitlines()[0]) + parser.add_argument("--project-root", type=Path, default=PROJECT_ROOT) + parser.add_argument("--build-dir", type=Path, required=True, help="CMake binary dir whose database to copy") + args = parser.parse_args(argv) + + project_root: Path = args.project_root.resolve() + build_dir: Path = args.build_dir.resolve() + if selected_build_dir(project_root) != build_dir: + print(f"{build_dir} is not the selected build; {TARGET} is left as it is") + return 0 + source = build_dir / "compile_commands.json" + if not source.is_file(): + print(f"{source} does not exist yet; {TARGET} is left as it is") + return 0 + + text = json.dumps(without_save_temps(json.loads(source.read_text(encoding="utf-8"))), indent=2) + "\n" + target = project_root / TARGET + if not target.is_file() or target.read_text(encoding="utf-8") != text: + target.parent.mkdir(parents=True, exist_ok=True) + target.write_text(text, encoding="utf-8") + print(f"wrote {TARGET} from {source}") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tools/config_checks.py b/tools/config_checks.py new file mode 100644 index 00000000..60a87068 --- /dev/null +++ b/tools/config_checks.py @@ -0,0 +1,115 @@ +"""Checks that the configuration both readers read is still intact. + +conf.py runs them whenever Sphinx reads its configuration and reports each +finding as a warning, so a drift fails the build under `-W` instead of waiting +for someone to run the tests; test_ubproject_config.py calls the same functions. +needs-config-writer does the same for the configuration it writes +(`needscfg_warn_on_diff`). + +Each check returns a list of findings, one sentence each, and nothing when all +is well. +""" + +from __future__ import annotations + +import tomllib +from importlib.resources import files +from pathlib import Path +from typing import Any + +import variant_data + +#: The Markdown documents both readers read: ubCode's md parser include, and the +#: trees conf.py names in `include_patterns`. +MARKDOWN_INCLUDES = ["index.md", "doc/**/*.md", "components/**/doc/**/*.md", "test/**/doc/**/*.md"] +MARKDOWN_TREES = ["index.md", "doc/**", "components/**/doc/**", "test/**/doc/**"] + + +def spl_core_config() -> dict[str, Any]: + """The base configuration spl-core ships, as installed.""" + with files("spl_core.report_generation").joinpath("ubproject.toml").open("rb") as handle: + return tomllib.load(handle) + + +def vendored_needs_model(project: dict[str, Any], spl_core: dict[str, Any]) -> list[str]: + """spl-core's needs model is vendored into ubproject.toml; a copy has to stay a copy.""" + findings: list[str] = [] + expected_links = { + link["option"]: {"incoming": link["incoming"], "outgoing": link["outgoing"]} + for link in spl_core["needs"]["extra_links"] + } + if project["needs"].get("links") != expected_links: + findings.append("the link types in ubproject.toml differ from spl-core's extra_links") + fields = project["needs"].get("fields", {}) + for option in spl_core["needs"]["extra_options"]: + if option not in fields: + findings.append(f"spl-core declares the field {option!r}, ubproject.toml does not") + ours = {need_type["directive"]: need_type for need_type in project["needs"].get("types", [])} + for need_type in spl_core["needs"]["types"]: + if ours.get(need_type["directive"]) != need_type: + findings.append(f"the need type {need_type['directive']!r} differs from spl-core's, or is missing") + for key in ("exclude", "respect_gitignore"): + if project["source"].get(key) != spl_core["source"].get(key): + findings.append(f"[source] {key} differs from spl-core's") + return findings + + +def document_sets(project: dict[str, Any], include_patterns: list[str]) -> list[str]: + """ubCode's parser includes and conf.py's include_patterns name the same documents.""" + findings: list[str] = [] + parsers = project.get("parse", {}).get("parsers", {}) + if parsers.get("md", {}).get("include") != MARKDOWN_INCLUDES: + findings.append(f"the md parser include is not {MARKDOWN_INCLUDES}") + for tree in MARKDOWN_TREES: + if tree not in include_patterns: + findings.append(f"conf.py does not include {tree!r}, which the md parser reads") + if parsers.get("rst", {}).get("include") != list(variant_data.MOUNTED_PAGES): + findings.append(f"the rst parser include is not the mounted pages {list(variant_data.MOUNTED_PAGES)}") + for pattern in variant_data.MOUNTED_PAGES: + if f"{variant_data.MOUNT_AT}/{pattern}" not in include_patterns: + findings.append(f"conf.py does not include {variant_data.MOUNT_AT}/{pattern}, which the mount brings in") + return findings + + +def generated_half(project: dict[str, Any]) -> list[str]: + """What the generated files decide, ubproject.toml must not decide as well. + + `extend` merges tables key by key but replaces arrays: a rule or a mount in + ubproject.toml would replace every generated one, silently. + """ + findings: list[str] = [] + if project.get("extend") != variant_data.RULES_FILE: + findings.append(f"ubproject.toml has to extend {variant_data.RULES_FILE}, the generated rules") + if project.get("source", {}).get("variant_sources"): + findings.append(f"ubproject.toml declares rules; they would replace the generated ones (use {variant_data.HAND_WRITTEN_RULES})") + if project.get("source", {}).get("mounts"): + findings.append("ubproject.toml declares mounts; they would replace the selection's") + if "variant_data_file" in project.get("needs", {}): + findings.append("ubproject.toml names a variant data file; the selection names it") + return findings + + +def rule_grammar(project_root: Path) -> list[str]: + """Every generated rule is inside the grammar both engines share.""" + rules_file = project_root / variant_data.RULES_FILE + if not rules_file.is_file(): + return [] + from sphinx_mounts import variants + + findings: list[str] = [] + for rule in tomllib.loads(rules_file.read_text(encoding="utf-8")).get("source", {}).get("variant_sources", []): + try: + variants.validate(rule["if"]) + except Exception as error: # noqa: BLE001 - the finding names whatever the grammar refused + findings.append(f"the rule {rule['if']!r} is outside the shared grammar: {error}") + return findings + + +def run_all(project_root: Path, include_patterns: list[str]) -> list[str]: + project = tomllib.loads((project_root / "ubproject.toml").read_text(encoding="utf-8")) + return [ + *vendored_needs_model(project, spl_core_config()), + *document_sets(project, include_patterns), + *generated_half(project), + *rule_grammar(project_root), + ] diff --git a/tools/variant_data.py b/tools/variant_data.py index 012a14e0..1ab7658a 100644 --- a/tools/variant_data.py +++ b/tools/variant_data.py @@ -1,25 +1,40 @@ #!/usr/bin/env python3 -"""Write the variant data files that every documentation tool reads. +"""Write the files that decide what every documentation tool shows. -One generation step, one artefact per build shape, and nothing downstream needs -Python to decide anything: `ubproject.toml` conditions and the `{if}` directives -in the documents read these files, and so do `sphinx-build`, `ubc` and the -ubCode language server. The rule that follows from that is the only one worth -remembering here: +One generation step before any reader runs, and nothing downstream needs Python +to decide anything: the rules, the `{if}` directives in the documents and the +selected build all come out of the files written here, and `sphinx-build`, +`ubc` and the ubCode language server read the same ones. The rule that follows +from that is the only one worth remembering here: - everything a condition may name has to be IN the file. + everything a condition may name has to be IN the variant data file. A key that only `conf.py` knows is invisible to every other reader, and their -view of the project then silently disagrees with the build. That is why this -writes the complete feature vector -- including the booleans KConfig omits -- -plus the build shape, rather than leaving any of it to be synthesized later. +view of the project then disagrees with the build. That is why this writes the +complete feature vector -- including the booleans KConfig omits -- plus the +build shape, rather than leaving any of it to be synthesized later. Layout:: - build/variants/<Variant>/<kit>/<target>.json the matrix - build/variants/GENERATED marker; nobody edits generated output - build/autoconf.json the "current" pointer, one cell of the matrix - generated/ symlink to the current cell's build directory + build/variants/<Variant>/<kit>/<target>.json the matrix: one variant data file per cell + build/variants/<Variant>/<kit>/<component>/<target>.json the same, for one component's report + build/variants/GENERATED marker; nobody edits generated output + ubproject.variants.toml the document rules, one per documented component + build/selection.toml the selected build, for the IDE and a bare run + <build dir>/selection/[<component>/]<target>.toml the same for each run spl-core starts there + +Nothing needs maintaining by hand for a component. Its rule is derived from +where its documentation lives and gated on the variant's component list, which +comes from `parts.cmake`: adding a component is adding it to `parts.cmake` and +writing its documentation. + +The rules are the same for every variant, so they live in one file, at the +project root: sphinx-mounts reads rule patterns relative to the file that +declares them and refuses absolute or `..` ones. A selection file names a +variant data file and, for a CMake build, mounts that build's directory at +`generated`, where every page spl-core generates is named. ubproject.toml +reaches both files through `extend`; conf.py hands the selection's keys to +Sphinx, whose extensions each read one TOML file and do not follow `extend`. Nothing here needs a compiler. KConfig is pure Python, while CMake's top-level `project()` call demands a C toolchain before it will even configure -- so with @@ -43,6 +58,36 @@ from pathlib import Path from typing import Any +#: The generated rule file, at the project root (see the module docstring). +RULES_FILE = "ubproject.variants.toml" + +#: The selection the IDE and a bare `sphinx-build` or `ubc` read. +SELECTION_FILE = "build/selection.toml" + +#: The root document of a per-component report. +COMPONENT_ROOT_DOC = "doc/component_report" + +#: Rules written by hand, for the cases a component's membership does not decide +#: (VARIANTS.md, use case 13). Appended to the generated ones: ubproject.toml +#: cannot hold rules of its own, because `extend` replaces arrays rather than +#: merging them. +HAND_WRITTEN_RULES = "doc/variant_rules.toml" + +#: Where the generated pages of the selected build appear. spl-core names every +#: page it generates below it (SPL_SPHINX_BINARY_DIR in CMakeLists.txt). +MOUNT_AT = "generated" + +#: The pages a build directory contributes, relative to it: spl-core's report +#: pages and the clanguru listings. The same patterns as ubCode's rst parser +#: include in ubproject.toml; everything else in a build directory (CMake state, +#: HTML output, spl-core's navigation wrappers, fetched dependencies) stays out. +MOUNTED_PAGES = ("components/**/*.rst", "test/**/*.rst", "reports/*.rst") + +GENERATED_HEADER = ( + "# GENERATED by tools/variant_data.py -- do not edit. It is rewritten whenever a\n" + "# variant is selected, and whatever is changed here is lost.\n" +) + PROJECT_ROOT = Path(__file__).resolve().parent.parent #: Components a variant's `parts.cmake` adds only for the test build kit. @@ -185,8 +230,34 @@ def components(project_root: Path, variant: str, kit: str) -> list[str]: return result -def variant_data(project_root: Path, variant: str, kit: str, target: str) -> dict[str, Any]: - """One cell of the matrix: everything a condition anywhere may name.""" +def documented_components(project_root: Path) -> list[str]: + """Every component with documentation: a directory with a `doc/index` page. + + The same test spl-core applies before it creates a component's docs and + report builds. Components without documentation need no rule, because they + contribute no page. + """ + found: set[str] = set() + for top in ("components", "test"): + base = project_root / top + if not base.is_dir(): + continue + for index in base.rglob("index.*"): + if index.suffix in (".md", ".rst") and index.parent.name == "doc": + found.add(index.parent.parent.relative_to(project_root).as_posix()) + return sorted(found) + + +def variant_data( + project_root: Path, variant: str, kit: str, target: str, component: str | None = None +) -> dict[str, Any]: + """One cell of the matrix: everything a condition anywhere may name. + + `component` makes it the cell of that component's report. The component list + stays the variant's, so a block conditioned on another component's presence + reads the same in the component's report as in the variant's documentation; + only `scope` and `component` differ, and the rules gate the documents on them. + """ return { "features": features(project_root, variant), "build_config": { @@ -194,105 +265,204 @@ def variant_data(project_root: Path, variant: str, kit: str, target: str) -> dic "kit": kit, "target": target, "components": components(project_root, variant, kit), + "scope": "component" if component else "variant", + "component": component or "", }, } -def cell_path(project_root: Path, variant: str, kit: str, target: str) -> Path: - return project_root / "build" / "variants" / variant / kit / f"{target}.json" +def cell_path(project_root: Path, variant: str, kit: str, target: str, component: str | None = None) -> Path: + base = project_root / "build" / "variants" / variant / kit + return (base / component if component else base) / f"{target}.json" -def write_cell(project_root: Path, variant: str, kit: str, target: str, data: dict[str, Any]) -> Path: - path = cell_path(project_root, variant, kit, target) +def write_cell( + project_root: Path, variant: str, kit: str, target: str, data: dict[str, Any], component: str | None = None +) -> Path: + path = cell_path(project_root, variant, kit, target, component) path.parent.mkdir(parents=True, exist_ok=True) path.write_text(json.dumps(data, indent=2, sort_keys=True) + "\n", encoding="utf-8") return path -def write_pointer(project_root: Path, data: dict[str, Any], build_dir: Path | None) -> None: - """Point `build/autoconf.json` and `generated` at one cell. +def reported_components(project_root: Path, variant: str, kit: str) -> list[str]: + """The components of this cell that get a per-component report.""" + documented = set(documented_components(project_root)) + return [component for component in components(project_root, variant, kit) if component in documented] - `ubproject.toml` names the data file as `variant_data_file`, so the pointer - is the variant the IDE shows. - `generated` is the configured build directory, and CMakeLists.txt hands it - to spl-core as SPL_SPHINX_BINARY_DIR. Every page spl-core generates is then - named `generated/...` in the Sphinx build, whatever the variant, kit or build - type, and the report sections name those pages directly. Re-pointing the link - is safe: spl-core stops a documentation build whose link no longer leads to - its own build directory, rather than letting it read another build's pages. +def cells(project_root: Path, variant: str) -> list[tuple[str, str, str | None]]: + """Every (kit, target, component) cell of one variant, the component ones included.""" + result: list[tuple[str, str, str | None]] = [] + for kit in KITS: + for target in TARGETS: + result.append((kit, target, None)) + result.extend((kit, target, component) for component in reported_components(project_root, variant, kit)) + return result + - The link sits at the project root rather than inside `build/`, because - `build` is pruned from the Sphinx walk and excluded by ubCode: each - generated page has to be reachable under exactly one name. +def rules_toml(project_root: Path) -> str: + """The document rules: which documents a variant data file admits. - ubCode does not descend symlinked directories, so the IDE does not show the - generated pages. They are build output of the reports target, which is - Sphinx-only anyway. + Rules are subtractive: a rule whose condition is FALSE removes the files it + names, a TRUE rule does nothing, so two rules naming the same file compose as + AND. Gated on membership of the variant's component list, never on the + variant's name: the product structure is stated once, in parts.cmake. + + A per-component report (`scope == "component"`) shows one component: its own + documentation and generated pages, under doc/component_report.md, and none of + the variant-wide documents. + + Patterns follow gitignore rules, and both readers match them twice: against + the project tree, and against each mount's own files, relative to the mounted + directory. So `components/auto_off/**` names the component's documentation + in the tree and its generated pages in a mounted build alike, and + `reports/**` the variant's pages spl-core writes under `reports/`. A pattern + without a slash would match at every depth, which is why the root `index.md` + is not named: in a component's report it is an orphan page (its front matter + says so) whose every toctree entry is excluded. """ - pointer = project_root / "build" / "autoconf.json" - pointer.parent.mkdir(parents=True, exist_ok=True) - pointer.write_text(json.dumps(data, indent=2, sort_keys=True) + "\n", encoding="utf-8") + doc_dir = project_root / "doc" + variant_wide: list[str] = [] + for entry in sorted(doc_dir.iterdir()) if doc_dir.is_dir() else []: + if entry.name == Path(COMPONENT_ROOT_DOC).name + ".md": + continue + variant_wide.append(f"doc/{entry.name}/**" if entry.is_dir() else f"doc/{entry.name}") + variant_wide.append("reports/**") - if build_dir is None: - return - - current = project_root / "generated" - _remove_link(current) - target = build_dir.resolve() - try: - current.symlink_to(target, target_is_directory=True) - return - except OSError: - pass - - # Windows refuses a symlink without Developer Mode, but creates a junction - # without any privilege, and Sphinx walks a junction like a directory. - try: - _create_junction(target, current) - return - except OSError: - pass - - # Neither could be created. A plain directory keeps the path present and - # says why it is empty; spl-core then stops the documentation builds with a - # message naming both paths, instead of building them without their reports. - current.mkdir(parents=True, exist_ok=True) - (current / "NO_SYMLINK").write_text( - "Neither a symlink nor a junction could be created here, so `generated`\n" - "is a plain directory.\n" - f"It should lead to: {target}\n" + def rule(condition: str, files: list[str], comment: str) -> str: + listed = "".join(f' "{pattern}",\n' for pattern in files) + return f"\n# {comment}\n[[source.variant_sources]]\nif = \"{condition}\"\nfiles = [\n{listed}]\n" + + text = GENERATED_HEADER + ( + "#\n" + "# Which documents a variant data file admits. The same for every variant; the\n" + "# selected build comes in through the `extend` below.\n" "\n" - "The documentation builds read the generated report pages through this\n" - "path, and spl-core stops them until it leads to the build directory. On\n" - "Windows, keep the checkout on an NTFS volume, or enable Developer Mode.\n", - encoding="utf-8", + f'extend = "{SELECTION_FILE}"\n' + ) + text += rule("var.build_config.scope == 'variant'", variant_wide, "The variant-wide documents.") + text += rule("var.build_config.scope == 'component'", [f"{COMPONENT_ROOT_DOC}.md"], "The root of a per-component report.") + for component in documented_components(project_root): + condition = ( + f"'{component}' in var.build_config.components and " + f"(var.build_config.scope == 'variant' or var.build_config.component == '{component}')" + ) + text += rule(condition, [f"{component}/**"], component) + hand_written = project_root / HAND_WRITTEN_RULES + if hand_written.is_file(): + import tomllib + + for entry in tomllib.loads(hand_written.read_text(encoding="utf-8")).get("source", {}).get("variant_sources", []): + if set(entry) != {"if", "files"} or not isinstance(entry["files"], list): + raise ValueError(f"{HAND_WRITTEN_RULES}: a rule has exactly `if` and `files`, got {sorted(entry)}") + text += rule(entry["if"].replace('"', "'"), entry["files"], f"from {HAND_WRITTEN_RULES}") + return text + + +def selection_toml( + variant_data_file: Path, variant: str, kit: str, build_dir: Path | None, root_doc: str | None = None +) -> str: + """One selection: which variant data file a reader evaluates, and which build it shows. + + The mount's condition names the build's own variant and kit. A reader pointed + at another variant's data then reads none of this build's pages, instead of + showing them as that variant's. + """ + text = GENERATED_HEADER + f'\n[needs]\nvariant_data_file = "{variant_data_file.resolve().as_posix()}"\n' + if root_doc: + # A component's report shows one component, so its links to the rest of + # the product dangle by design. ubc's lint code says so; conf.py turns it + # into suppressing sphinx-needs' `needs.link_outgoing` for Sphinx. + text += f'\n[project]\nroot_doc = "{root_doc}"\n\n[lint]\nignore = ["needs.dead_link"]\n' + if build_dir is None: + text += "\n[source]\nmounts = []\n" + else: + condition = f'var.build_config.target == "reports" and var.build_config.variant == "{variant}" and var.build_config.kit == "{kit}"' + included = ", ".join(f'"{pattern}"' for pattern in MOUNTED_PAGES) + text += ( + "\n[[source.mounts]]\n" + f'dir = "{build_dir.resolve().as_posix()}"\n' + f'mount_at = "{MOUNT_AT}"\n' + f"include = [{included}]\n" + "gitignore = false\n" + f"if = '{condition}'\n" + ) + return text + + +def write_text_if_changed(path: Path, text: str) -> bool: + """Write only when the content changes, so a reader's cache stays valid.""" + if path.exists() and path.read_text(encoding="utf-8") == text: + return False + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(text, encoding="utf-8") + return True + + +def write_rules(project_root: Path) -> Path: + path = project_root / RULES_FILE + write_text_if_changed(path, rules_toml(project_root)) + return path + + +def write_selection(project_root: Path, variant: str, kit: str, target: str, build_dir: Path | None) -> None: + """Select one cell: build/selection.toml, and one file per spl-core run of the build. + + Every documentation run spl-core starts in the build names its own file + (`-D spl_selection=...`, SPL_SPHINX_OPTIONS in CMakeLists.txt), so two builds' + reports can be built side by side. build/selection.toml is what the IDE and a + bare run read; it is written last, so it names the build configured last. + """ + _remove_stale_selection(project_root) + if build_dir is not None: + runs = build_dir / "selection" + for shape in TARGETS: + write_text_if_changed( + runs / f"{shape}.toml", + selection_toml(cell_path(project_root, variant, kit, shape), variant, kit, build_dir), + ) + for component in reported_components(project_root, variant, kit): + write_text_if_changed( + runs / component / f"{shape}.toml", + selection_toml( + cell_path(project_root, variant, kit, shape, component), variant, kit, build_dir, COMPONENT_ROOT_DOC + ), + ) + write_text_if_changed( + project_root / SELECTION_FILE, + selection_toml(cell_path(project_root, variant, kit, target), variant, kit, build_dir), ) +def _remove_stale_selection(project_root: Path) -> None: + """Remove what earlier versions of this script wrote to select a variant. + + `build/autoconf.json` was the pointer, and `generated` a link (a junction on + Windows) to the configured build directory. Nothing reads either any more, + and a stale link would still lead Sphinx's walk into a build directory. + """ + pointer = project_root / "build" / "autoconf.json" + if pointer.is_file(): + pointer.unlink() + _remove_link(project_root / MOUNT_AT) + + def _remove_link(path: Path) -> None: - """Remove whatever `generated` was, without ever touching what it led to.""" + """Remove the `generated` link earlier versions made, never what it led to. + + A real directory is only removed when it is the placeholder those versions + left where no link could be made (it holds `NO_SYMLINK`); anything else there + is somebody's, and stays. + """ if path.is_symlink() or path.is_file(): path.unlink() elif path.is_junction(): path.rmdir() # removes the junction itself, not the directory it leads to - elif path.is_dir(): + elif path.is_dir() and (path / "NO_SYMLINK").is_file(): shutil.rmtree(path) -def _create_junction(target: Path, link: Path) -> None: - """Create a directory junction at `link` leading to `target`. - - Raises OSError where junctions do not exist, which is everywhere but Windows. - """ - try: - import _winapi # CPython's Windows API module - except ImportError as error: - raise OSError("directory junctions exist on Windows only") from error - - _winapi.CreateJunction(str(target), str(link)) - - #: Dropped into every directory this script owns. `build/` itself gets one too, #: because that is the directory somebody is most likely to open and edit in. GENERATED_MARKER = ( @@ -316,16 +486,20 @@ def _check(project_root: Path, selected: list[str]) -> int: meant to catch and report success. """ stale: list[str] = [] + expected_files: list[tuple[Path, str]] = [] for variant in selected: - for kit in KITS: - for target in TARGETS: - expected = json.dumps(variant_data(project_root, variant, kit, target), indent=2, sort_keys=True) + "\n" - path = cell_path(project_root, variant, kit, target) - rel = path.relative_to(project_root) - if not path.exists(): - stale.append(f"{rel}: missing") - elif path.read_text(encoding="utf-8") != expected: - stale.append(f"{rel}: stale") + for kit, target, component in cells(project_root, variant): + data = variant_data(project_root, variant, kit, target, component) + expected_files.append( + (cell_path(project_root, variant, kit, target, component), json.dumps(data, indent=2, sort_keys=True) + "\n") + ) + expected_files.append((project_root / RULES_FILE, rules_toml(project_root))) + for path, expected in expected_files: + rel = path.relative_to(project_root) + if not path.exists(): + stale.append(f"{rel}: missing") + elif path.read_text(encoding="utf-8") != expected: + stale.append(f"{rel}: stale") if stale: print("variant data is not up to date:", file=sys.stderr) @@ -334,7 +508,7 @@ def _check(project_root: Path, selected: list[str]) -> int: print("\nrun: python tools/variant_data.py --all", file=sys.stderr) return 1 - print(f"variant data up to date ({len(selected)} variants x {len(KITS)} kits x {len(TARGETS)} targets)") + print(f"variant data up to date ({len(expected_files) - 1} cells, and the rules)") return 0 @@ -348,12 +522,12 @@ def main(argv: list[str] | None = None) -> int: parser.add_argument( "--current", action="store_true", - help="also write build/autoconf.json and the `generated` link for the selected cell", + help=f"also select the cell: write {SELECTION_FILE}", ) parser.add_argument( "--build-dir", type=Path, - help="CMake binary dir of the selected cell; `generated` points at it", + help="CMake binary dir of the selected cell: mounted at `generated`, with one selection file per run", ) parser.add_argument( "--check", @@ -372,19 +546,21 @@ def main(argv: list[str] | None = None) -> int: if args.check: return _check(project_root, selected) + written = 0 for variant in selected: - for kit in KITS: - for target in TARGETS: - data = variant_data(project_root, variant, kit, target) - path = write_cell(project_root, variant, kit, target, data) - print(f"wrote {path.relative_to(project_root)}") + for kit, target, component in cells(project_root, variant): + data = variant_data(project_root, variant, kit, target, component) + write_cell(project_root, variant, kit, target, data, component) + written += 1 + print(f"wrote {written} variant data files") mark_generated(project_root) + print(f"wrote {write_rules(project_root).relative_to(project_root)}") if args.current or not args.all: - data = variant_data(project_root, args.variant or selected[0], args.kit, args.target) - write_pointer(project_root, data, args.build_dir) - print(f"current -> {args.variant or selected[0]} / {args.kit} / {args.target}") + variant = args.variant or selected[0] + write_selection(project_root, variant, args.kit, args.target, args.build_dir) + print(f"selected {variant} / {args.kit} / {args.target}" + (f" in {args.build_dir}" if args.build_dir else "")) return 0 diff --git a/ubproject.toml b/ubproject.toml index df7065d8..a1769c0b 100644 --- a/ubproject.toml +++ b/ubproject.toml @@ -1,5 +1,12 @@ "$schema" = "https://ubcode.useblocks.com/ubproject.schema.json" +# The generated half of the configuration: the document rules, one per +# documented component, and through them the selected build (build/selection.toml). +# tools/variant_data.py writes both whenever a variant is selected, so nothing in +# this file has to change when a component is added. ubCode and ubc follow the +# `extend`; conf.py hands the same files to Sphinx, whose extensions do not. +extend = "ubproject.variants.toml" + # --------------------------------------------------------------------------- # The one configuration file. Both readers of this project's documentation read # it: ubCode and ubc directly, and the Sphinx build through `needs_from_toml` @@ -15,7 +22,8 @@ # # spl-core's base needs configuration is therefore vendored below rather than # referenced. test_ubproject_config.py fails if it drifts from what the -# installed spl-core ships, so vendoring cannot rot quietly. +# installed spl-core ships, so vendoring cannot rot quietly. The one `extend` +# left names files this project generates itself, which every reader is handed. # --------------------------------------------------------------------------- [server] @@ -41,18 +49,16 @@ include = [ ] # Every .rst in this project is generated: the clanguru source listings and the -# report pages spl-core writes into the configured build directory. The build -# tree itself is excluded below (`build/**`): indexing every variant and kit -# ever built is the problem that exclusion solves. +# report pages spl-core writes into the selected build directory, which the +# selection mounts at `generated` (build/selection.toml). The build tree itself +# is excluded below (`build/**`): indexing every variant and kit ever built is +# the problem that exclusion solves. # -# The include names `generated`, the link to the configured build through which -# the Sphinx build reads those pages (SPL_SPHINX_BINARY_DIR in CMakeLists.txt). -# For ubCode it is inert, because ubCode does not descend symlinked directories -# ("directories are skipped and symlinked directories are not descended"), so -# the IDE shows no generated page. They are output of the reports target, which -# stays Sphinx-only while its pages use the sphinx-test-reports directive. +# The patterns are written relative to the mounted directory, because that is +# what ubCode matches a parser include against inside a mount, not the mounted +# name. conf.py names the same pages as `generated/...` in `include_patterns`. [parse.parsers.rst] -include = ["generated/**/*.rst"] +include = ["components/**/*.rst", "test/**/*.rst", "reports/*.rst"] [source] exclude = [".bzr", ".direnv", ".eggs", ".git", ".git-rewrite", ".hg", ".svn", ".venv", ".vscode", "_build", "dist", "node_modules", "site-packages"] @@ -61,23 +67,14 @@ respect_gitignore = false # output. Without the exclude, ubCode indexes every variant and every kit ever # built, so need IDs appear many times over and the IDE disagrees with any one # build about what the project contains. conf.py prunes `build` from the Sphinx -# walk for the same reason, and reads the configured build through `generated`. +# walk for the same reason; the selected build comes in through its mount. # `extend_include` is deliberately absent: it is ignored in parser mode, so the # generated listings are named by [parse.parsers.rst] instead. extend_exclude = [ "build/**", - # The root document of spl-core's PER-COMPONENT report, a build shape - # ubCode never performs. conf.py excludes it from every variant-wide - # build, so Sphinx never sees it either; without this line ubCode indexed - # it and reported it as an orphan -- the two readers disagreeing about the - # document set, which is the one thing this configuration exists to - # prevent. `[parse.parsers.*]` has no `exclude`, and extend_exclude IS - # honoured in parser mode (unlike extend_include), so this is the knob. - "doc/component_report.md", ] [needs] -variant_data_file = "build/autoconf.json" src_trace_config_from_toml = "ubproject.toml" @@ -118,6 +115,13 @@ outgoing = "verifies" incoming = "is tested by" outgoing = "tests" +# The CSV requirements carry their image in their content (doc/sw_requirements). +# ubc refuses an asset in imported content unless its source is listed here; +# Sphinx needs no such permission and ignores the key. +[[needs.import_sources]] +json_path = "doc/ubconnect/csv/needs.json" +allow_assets = true + [needs.fields.integrity] # spl-core declares this through the deprecated `extra_options` list. That form # implies an empty-string default, which is what every existing need carries, so @@ -167,54 +171,213 @@ style = "node" # --- end vendored ----------------------------------------------------------- -[needs.fields.image] -description = "Image associated with the need" +# Test results. spl-core converts each component's JUnit XML into needs.json +# after the test run (SPL_TEST_RESULTS_AS_NEEDS in CMakeLists.txt), with the +# types, IDs and fields sphinx-test-reports' test-report directive used to +# create, so both readers import them. Declared here because no extension +# registers them any more. +[[needs.types]] +directive = "testfile" +title = "Test-File" +prefix = "TF_" +color = "#ffffff" +style = "node" + +[[needs.types]] +directive = "testsuite" +title = "Test-Suite" +prefix = "TS_" +color = "#cccccc" +style = "folder" + +[[needs.types]] +directive = "testcase" +title = "Test-Case" +prefix = "TC_" +color = "#999999" +style = "rectangle" + +[needs.fields.suites] +description = "Test result: suites" +nullable = true + +[needs.fields.suites.schema] +type = "integer" + +[needs.fields.cases] +description = "Test result: cases" +nullable = true + +[needs.fields.cases.schema] +type = "integer" + +[needs.fields.passed] +description = "Test result: passed" +nullable = true + +[needs.fields.passed.schema] +type = "integer" + +[needs.fields.skipped] +description = "Test result: skipped" +nullable = true + +[needs.fields.skipped.schema] +type = "integer" + +[needs.fields.failed] +description = "Test result: failed" +nullable = true + +[needs.fields.failed.schema] +type = "integer" + +[needs.fields.errors] +description = "Test result: errors" +nullable = true + +[needs.fields.errors.schema] +type = "integer" + +[needs.fields.file] +description = "Test result: file" +nullable = true + +[needs.fields.file.schema] +type = "string" + +[needs.fields.suite] +description = "Test result: suite" +nullable = true + +[needs.fields.suite.schema] +type = "string" + +[needs.fields.case] +description = "Test result: case" +nullable = true + +[needs.fields.case.schema] +type = "string" + +[needs.fields.case_name] +description = "Test result: case_name" +nullable = true + +[needs.fields.case_name.schema] +type = "string" + +[needs.fields.case_parameter] +description = "Test result: case_parameter" +nullable = true + +[needs.fields.case_parameter.schema] +type = "string" + +[needs.fields.classname] +description = "Test result: classname" +nullable = true + +[needs.fields.classname.schema] +type = "string" + +[needs.fields.result] +description = "Test result: result" +nullable = true + +[needs.fields.result.schema] +type = "string" + +[needs.fields.time] +description = "Test result: time" +nullable = true + +[needs.fields.time.schema] +type = "string" + +[needs.fields.configuration] +description = "Configuration, from the ubConnect ReqIF export" +nullable = true + +[needs.fields.configuration.schema] +type = "string" + +[needs.fields.origin] +description = "Origin, from the ubConnect ReqIF export" nullable = true -[needs.fields.image.schema] +[needs.fields.origin.schema] type = "string" +[needs.fields.priority] +description = "Priority, from the ubConnect ReqIF export" +nullable = true + +[needs.fields.priority.schema] +type = "string" + +[needs.fields.reqif_uuid] +description = "ReqIF identifier, from the ubConnect ReqIF export" +nullable = true + +[needs.fields.reqif_uuid.schema] +type = "string" + +[needs.fields.level] +description = "Hierarchy level, from the CSV import" +nullable = true + +[needs.fields.level.schema] +type = "integer" + +# clanguru documents declarations from system headers in the test listings, and +# their tabs trip ubc. Ignored for the generated listings only, until clanguru +# documents just the declarations of the file itself. The key is spelled with +# hyphens: ubc silently ignores `per_file_ignores`. +[lint.per-file-ignores] +"generated/**/__source_docs/**" = ["source.tab_in_line"] + [codelinks] outdir = "output" set_remote_url = true -[codelinks.projects.brightness_controller] +[codelinks.projects.components] remote_url_pattern = "https://github.com/avengineers/SPLed/blob/{commit}/{path}#L{line}" -[codelinks.projects.brightness_controller.source_discover] -src_dir = "components/brightness_controller/src" -include = ["**/*.c", "**/*.h"] +[codelinks.projects.components.source_discover] +src_dir = "components" +include = ["**/src/**/*.c", "**/src/**/*.h"] comment_type = "cpp" -[codelinks.projects.brightness_controller.analyse] +[codelinks.projects.components.analyse] get_oneline_needs = true get_need_id_refs = false get_rst = false -[codelinks.projects.brightness_controller.analyse.preprocessor] +[codelinks.projects.components.analyse.preprocessor] compile_commands = "build/compile_commands.json" -[codelinks.projects.brightness_controller.analyse.oneline_comment_style] +[codelinks.projects.components.analyse.oneline_comment_style] start_sequence = "@need" end_sequence = "\n" field_split_char = "," -[[codelinks.projects.brightness_controller.analyse.oneline_comment_style.needs_fields]] +[[codelinks.projects.components.analyse.oneline_comment_style.needs_fields]] name = "title" -[[codelinks.projects.brightness_controller.analyse.oneline_comment_style.needs_fields]] +[[codelinks.projects.components.analyse.oneline_comment_style.needs_fields]] name = "id" -[[codelinks.projects.brightness_controller.analyse.oneline_comment_style.needs_fields]] +[[codelinks.projects.components.analyse.oneline_comment_style.needs_fields]] name = "type" default = "impl" -[[codelinks.projects.brightness_controller.analyse.oneline_comment_style.needs_fields]] +[[codelinks.projects.components.analyse.oneline_comment_style.needs_fields]] name = "implements" type = "list[str]" default = [] -[[codelinks.projects.brightness_controller.analyse.oneline_comment_style.needs_fields]] +[[codelinks.projects.components.analyse.oneline_comment_style.needs_fields]] name = "fulfills" type = "list[str]" default = [] @@ -222,119 +385,11 @@ default = [] # --------------------------------------------------------------------------- # Variant-dependent documentation. # -# Two mechanisms, one data source. Both read the file named by -# `[needs] variant_data_file` above, which tools/variant_data.py writes, so -# ubCode, ubc and the Sphinx build decide every condition identically. -# -# `[[source.variant_sources]]` gates whole documents that live IN this tree, -# including the generated output, which the `generated` link brings into it. -# `[[source.mounts]]`, for trees outside it, is not needed. Blocks inside a -# document are gated by the {if} directive of Sphinx-Needs, which reads the -# same `var.*`. -# -# A condition may only name what the variant data file declares. Naming -# anything else makes it unevaluable, and an unevaluable condition EXCLUDES -# what it gates -- so a typo silently shrinks the document set rather than -# failing loudly. +# Nothing here. Which documents a variant has is decided by the rules in +# ubproject.variants.toml, which tools/variant_data.py derives from where each +# component's documentation lives, gated on the variant's component list from +# parts.cmake. Which build a reader shows is build/selection.toml: the variant +# data file it evaluates, and the build directory it mounts at `generated`. +# Blocks inside a document are gated by the {if} directive of Sphinx-Needs, +# which reads the same `var.*`. # --------------------------------------------------------------------------- - -# Rules are subtractive: a rule whose condition is FALSE removes the files it -# names, and a TRUE rule does nothing. Two rules naming the same file therefore -# compose as AND, which is what gates the generated report pages on both the -# build shape and the component being part of the variant. - -# Generated output belongs to the `reports` build shape only. -# -# `generated` is the configured variant's build directory, maintained by -# tools/variant_data.py. spl-core lists the report pages for the `docs` build -# as well, and conf.py passes them on for both shapes, so this rule is the one -# place that keeps them out of a `docs` build. Without it, every report page -# would be read and then left out of every toctree -- one orphan warning each. -[[source.variant_sources]] -if = 'var.build_config.target == "reports"' -files = ["generated/**"] - -# Component documentation, hand-written and generated alike. -# -# Gated on membership of the variant's component list, which the generator -# reads out of that variant's parts.cmake. That is the point: the product -# structure is stated once, in the file that already states it. Gating on the -# owning KConfig feature instead would be a second encoding of the same fact, -# free to drift -- and gating the integration suite on `variant == "Disco"`, as -# this did before, was exactly that drift made concrete: it claimed the suite -# for Disco's prod kit too, where parts.cmake does not add it. -# -# doc/components/index.md carries the full 150% toctree. An entry naming a -# document a rule excluded is reported as INFO by both tools, by design. - -[[source.variant_sources]] -if = "'components/light_controller' in var.build_config.components" -files = [ - "components/light_controller/doc/**", - "generated/components/light_controller/reports/**", - "generated/components/light_controller/__source_docs/**", -] - -[[source.variant_sources]] -if = "'components/main_control_knob' in var.build_config.components" -files = [ - "components/main_control_knob/doc/**", - "generated/components/main_control_knob/reports/**", - "generated/components/main_control_knob/__source_docs/**", -] - -[[source.variant_sources]] -if = "'components/power_button' in var.build_config.components" -files = [ - "components/power_button/doc/**", - "generated/components/power_button/reports/**", - "generated/components/power_button/__source_docs/**", -] - -[[source.variant_sources]] -if = "'components/power_signal_processing' in var.build_config.components" -files = [ - "components/power_signal_processing/doc/**", - "generated/components/power_signal_processing/reports/**", - "generated/components/power_signal_processing/__source_docs/**", -] - -[[source.variant_sources]] -if = "'components/brightness_controller' in var.build_config.components" -files = [ - "components/brightness_controller/doc/**", - "generated/components/brightness_controller/reports/**", - "generated/components/brightness_controller/__source_docs/**", -] - -[[source.variant_sources]] -if = "'components/auto_off' in var.build_config.components" -files = [ - "components/auto_off/doc/**", - "generated/components/auto_off/reports/**", - "generated/components/auto_off/__source_docs/**", -] - -[[source.variant_sources]] -if = "'test/spled_integration' in var.build_config.components" -files = [ - "test/spled_integration/doc/**", - "generated/test/spled_integration/reports/**", - "generated/test/spled_integration/__source_docs/**", -] - -[[source.variant_sources]] -if = "'components/examples/hello_gmock' in var.build_config.components" -files = [ - "components/examples/hello_gmock/doc/**", - "generated/components/examples/hello_gmock/reports/**", - "generated/components/examples/hello_gmock/__source_docs/**", -] - -[[source.variant_sources]] -if = "'components/examples/flight_controller' in var.build_config.components" -files = [ - "components/examples/flight_controller/doc/**", - "generated/components/examples/flight_controller/reports/**", - "generated/components/examples/flight_controller/__source_docs/**", -] diff --git a/uv.lock b/uv.lock deleted file mode 100644 index a5c2bece..00000000 --- a/uv.lock +++ /dev/null @@ -1,2528 +0,0 @@ -version = 1 -revision = 3 -requires-python = ">=3.12, <3.14" -resolution-markers = [ - "python_full_version >= '3.13'", - "python_full_version < '3.13'", -] - -[[package]] -name = "accessible-pygments" -version = "0.0.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pygments" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/bc/c1/bbac6a50d02774f91572938964c582fff4270eee73ab822a4aeea4d8b11b/accessible_pygments-0.0.5.tar.gz", hash = "sha256:40918d3e6a2b619ad424cb91e556bd3bd8865443d9f22f1dcdf79e33c8046872", size = 1377899, upload-time = "2024-05-10T11:23:10.216Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/3f/95338030883d8c8b91223b4e21744b04d11b161a3ef117295d8241f50ab4/accessible_pygments-0.0.5-py3-none-any.whl", hash = "sha256:88ae3211e68a1d0b011504b2ffc1691feafce124b845bd072ab6f9f66f34d4b7", size = 1395903, upload-time = "2024-05-10T11:23:08.421Z" }, -] - -[[package]] -name = "alabaster" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a6/f8/d9c74d0daf3f742840fd818d69cfae176fa332022fd44e3469487d5a9420/alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e", size = 24210, upload-time = "2024-07-26T18:15:03.762Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b", size = 13929, upload-time = "2024-07-26T18:15:02.05Z" }, -] - -[[package]] -name = "annotated-doc" -version = "0.0.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/8e/38aa427ed5402449e226975b649c5dc73ccadfefeb95e6aecb8f8ea4b6b6/annotated_doc-0.0.5.tar.gz", hash = "sha256:c7e58ce09192557605d8bbd92836d7e1d520ac9580096042c0bfd197efacf1bb", size = 10758, upload-time = "2026-07-28T13:50:58.129Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl", hash = "sha256:117bac03a25ede5df5440e855b32d556049ca169ead221505badf432fed4b101", size = 5302, upload-time = "2026-07-28T13:50:57.239Z" }, -] - -[[package]] -name = "annotated-types" -version = "0.8.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5f/56/a8120250d128bed162cd73c76d45f6ef9991f3e068f62a8ee060afa3104a/annotated_types-0.8.0.tar.gz", hash = "sha256:13b2beaad985e05e2d6407ee4c4f35590b11f8d693a258a561055cac8f64cab7", size = 15893, upload-time = "2026-07-23T20:16:13.995Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl", hash = "sha256:f072f4d804ea359e4eaf198b1af7a8b0943881a87f31bb764f8bf219bb9419e0", size = 13427, upload-time = "2026-07-23T20:16:12.938Z" }, -] - -[[package]] -name = "arrow" -version = "1.4.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "python-dateutil" }, - { name = "tzdata" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b9/33/032cdc44182491aa708d06a68b62434140d8c50820a087fac7af37703357/arrow-1.4.0.tar.gz", hash = "sha256:ed0cc050e98001b8779e84d461b0098c4ac597e88704a655582b21d116e526d7", size = 152931, upload-time = "2025-10-18T17:46:46.761Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/c9/d7977eaacb9df673210491da99e6a247e93df98c715fc43fd136ce1d3d33/arrow-1.4.0-py3-none-any.whl", hash = "sha256:749f0769958ebdc79c173ff0b0670d59051a535fa26e8eba02953dc19eb43205", size = 68797, upload-time = "2025-10-18T17:46:45.663Z" }, -] - -[[package]] -name = "attrs" -version = "26.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/82a0fe20a541c03148528be8cac2408564a6c9a0cc7e9171802bc1d26985/attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32", size = 952055, upload-time = "2026-03-19T14:22:25.026Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" }, -] - -[[package]] -name = "babel" -version = "2.18.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7d/b2/51899539b6ceeeb420d40ed3cd4b7a40519404f9baf3d4ac99dc413a834b/babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d", size = 9959554, upload-time = "2026-02-01T12:30:56.078Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35", size = 10196845, upload-time = "2026-02-01T12:30:53.445Z" }, -] - -[[package]] -name = "backports-zstd" -version = "1.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/75/f0/9ba1b05811aa5f5434f69768253129460a5744e1814f359efba39a01ce20/backports_zstd-1.7.0.tar.gz", hash = "sha256:1a967189c1822b6e85a2e550fdfc88a3272c17633ea0a4732dac5911a8034f2b", size = 1003722, upload-time = "2026-08-15T17:26:43.96Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/df/23/240495dec973dcfb34816248956ca8d05b32fb75936c226c1cf497b83b83/backports_zstd-1.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5548a857bb0fcc5449cc3687353547396c6b1ecd4bd882f1cd34fa8d29e70ca", size = 439047, upload-time = "2026-08-15T17:25:38.084Z" }, - { url = "https://files.pythonhosted.org/packages/6d/24/5556959c7d03bfee5ff14d7f07dd9bf8de737c69f81d823a32784ab39c34/backports_zstd-1.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bab192b934fdf5a03df4752556d9c8af2d058163fdfbafd4a253cdfe25449a6f", size = 367666, upload-time = "2026-08-15T17:25:39.233Z" }, - { url = "https://files.pythonhosted.org/packages/b2/cb/557db98001c4a7202beed19e8bd42603a2315b80fd5def7e21a0b048ec3b/backports_zstd-1.7.0-cp312-cp312-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:8344260bed9842c415a93d9bfe23ea834e5f27758827d56933d8c0d06db507a2", size = 508475, upload-time = "2026-08-15T17:25:40.367Z" }, - { url = "https://files.pythonhosted.org/packages/40/4b/820acbc2c1d1d945aedca0c0d22546a948630ffb186df523098fbd669a95/backports_zstd-1.7.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c55e55e1e9dee312bc5e186386e6aa5207482a6d2242bd7c14709ded254f87f", size = 478240, upload-time = "2026-08-15T17:25:41.806Z" }, - { url = "https://files.pythonhosted.org/packages/f9/76/77fa9b385e79d4c106ce15d66681978f39a844b0eb5db02682687246b716/backports_zstd-1.7.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cf609af3735c7e697ccd13f6b0c88da57c201b6ea63c6afbfe81d6f9b50e298c", size = 583611, upload-time = "2026-08-15T17:25:43.104Z" }, - { url = "https://files.pythonhosted.org/packages/95/a4/fbb7c73336f3279dad36da94382a59755100b656301ea836ebaa42736581/backports_zstd-1.7.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:676a37971f676830d4f90cee8fdf4e438781596fb2f2d1984ac76c9b3eb39a69", size = 642496, upload-time = "2026-08-15T17:25:44.322Z" }, - { url = "https://files.pythonhosted.org/packages/1e/40/121917bd2671bc3f1507c25503c0554f0b52483edcca4e6210e6d22228df/backports_zstd-1.7.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:470895d0bcddc850766e593d1b26764fb138c2feed149f515a2627ef9587d54c", size = 496195, upload-time = "2026-08-15T17:25:45.503Z" }, - { url = "https://files.pythonhosted.org/packages/de/c7/c6379a0d734bea1c7f14d07c23258108cc92b994654e25cfe3a3e88cd785/backports_zstd-1.7.0-cp312-cp312-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:02f2f6649a342d0901ddb35596ddadb7c3bb1cf6bb54d691e5e0285f1fa0674f", size = 570964, upload-time = "2026-08-15T17:25:46.648Z" }, - { url = "https://files.pythonhosted.org/packages/7a/a4/372c3dd3017c3f93cda0acbc282f8073b70efdc1b56d1fdeebe023660725/backports_zstd-1.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:132ba81fad59d44958b7d10da31545e7128c469cfbc2e268d0eaab96daa64175", size = 484276, upload-time = "2026-08-15T17:25:48.129Z" }, - { url = "https://files.pythonhosted.org/packages/f5/50/83fa7bdd5e1d808203b9143848fdf7e15de399b8119a0d4378b2aea9be78/backports_zstd-1.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a3e1c6ce0b232ee6703ed24ee126e8186107f5a4e56edbd21cd1aa5a8c6bfd12", size = 511963, upload-time = "2026-08-15T17:25:49.666Z" }, - { url = "https://files.pythonhosted.org/packages/56/d2/d4ed32c353148acc18f3b665ab24a677b9c49d3640244424c5d6046400c5/backports_zstd-1.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d7a7cb964eb8d1bb5d039970b16fe54802ea47dc935ae96d9874844a126bf8ff", size = 588025, upload-time = "2026-08-15T17:25:51.288Z" }, - { url = "https://files.pythonhosted.org/packages/ae/5a/df8b5b848e8dfdec6edca55f22067ffbafa081d81aec1313e28155c3fea3/backports_zstd-1.7.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:12a9842a2ec2854cbec7f252ab29d44c2b772788a9bbafded743ca4bf73b115f", size = 568223, upload-time = "2026-08-15T17:25:52.633Z" }, - { url = "https://files.pythonhosted.org/packages/43/8c/f970f15e7fdbf8a251f121c91364fa68bbc2dfab4d5eca058427dec63397/backports_zstd-1.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:138154eea8ced84394991bf0e819dba6b690306a178dd528c28eee724b7d4aec", size = 632937, upload-time = "2026-08-15T17:25:54.511Z" }, - { url = "https://files.pythonhosted.org/packages/6a/d0/e36c18c87a74421954502d123ff7027e0a63a7624dffa99ec0f7474deff9/backports_zstd-1.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:468b636ed365627b364c94be1c35a52858e13b5bc1fa3f068bbc71b1af65f3d7", size = 500735, upload-time = "2026-08-15T17:25:56.064Z" }, - { url = "https://files.pythonhosted.org/packages/1c/57/fc72280334d2aa94238c5882052263bd7796c1fa924044353c30d058e0c3/backports_zstd-1.7.0-cp312-cp312-win32.whl", hash = "sha256:f026fe2e89b7ff01ba6ebec6abaff34c6063919151a32afb68714cf139e17c50", size = 292394, upload-time = "2026-08-15T17:25:57.469Z" }, - { url = "https://files.pythonhosted.org/packages/71/89/6cea747bdeef34cd12482b17e604b832fdb0962987132b99496f1a6c3f82/backports_zstd-1.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:2ea62ba2f1a6e6c9e6dc108921f9ae881969ca72e073162fa488d0de3eb2713f", size = 329876, upload-time = "2026-08-15T17:25:58.798Z" }, - { url = "https://files.pythonhosted.org/packages/64/28/b4a17c07d5a50a45cb04592960d1593cdf3b3728968371f332aa3643b804/backports_zstd-1.7.0-cp312-cp312-win_arm64.whl", hash = "sha256:cefb983345c55ccaa20423a4eb96434730e6d640ffa2db9b60e5bedb0fbef94e", size = 292461, upload-time = "2026-08-15T17:25:59.928Z" }, - { url = "https://files.pythonhosted.org/packages/6f/24/32b3358ae3a4df0ebad85ebbce721818c6d76a836119bee76089d103e951/backports_zstd-1.7.0-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:a3fbcbf819bee2b06b8666b13742098d0f40663ee34e64a12bc360ec0f5e3d89", size = 400913, upload-time = "2026-08-15T17:26:01.089Z" }, - { url = "https://files.pythonhosted.org/packages/af/f3/39ef7dd75eb1e699e25a19212737a73d3c030a0c9fd1d0ed1572b5f8e493/backports_zstd-1.7.0-cp313-cp313-android_24_x86_64.whl", hash = "sha256:efee02f18e04c2e9e6d694c5cf9b7457c4bda3ea96f48b1ee69769e06bb9d89f", size = 454915, upload-time = "2026-08-15T17:26:02.294Z" }, - { url = "https://files.pythonhosted.org/packages/76/e8/8209081e094aa98b2f28bac388619c85b1a44aed813d6b3c54d1da79d19a/backports_zstd-1.7.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:ecc95fa0e91d92951d74468e7789afdf91d9e702f40af2d0fcbf0ded4d0f650a", size = 357992, upload-time = "2026-08-15T17:26:03.552Z" }, - { url = "https://files.pythonhosted.org/packages/b3/65/64025302bae4ba924d613e404c6120bf194b5636786960ece274622a4a3e/backports_zstd-1.7.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:34154d82fc0246738159084d146401073f9ac9cfd755b66bb8853ca06037810c", size = 366686, upload-time = "2026-08-15T17:26:04.812Z" }, - { url = "https://files.pythonhosted.org/packages/4a/b9/c4d24d113d28b774662152c462d38d28109741d6d45c1aea7834371741dc/backports_zstd-1.7.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:44b687b1c0be5cb279693d2682f91ff84c559d679b2ef2fbe501fe4b2db2c4bb", size = 447221, upload-time = "2026-08-15T17:26:05.979Z" }, - { url = "https://files.pythonhosted.org/packages/cb/9f/8db55c7f77aec60879844a879ac026065d8f03aab74080701acc060c4168/backports_zstd-1.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dcdbd368659f46b570114eeea36b75347716523870d71f6bc5d7801862aefd6e", size = 438571, upload-time = "2026-08-15T17:26:07.421Z" }, - { url = "https://files.pythonhosted.org/packages/cd/f8/72930ae4bb7bf6b9d6c7c31bce7b3e5751c062269a4ee718066e25f1973b/backports_zstd-1.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eda97fa535d4651a4ccdeed4ee7dde3978369046abc8a7456a7117d4271f9333", size = 367041, upload-time = "2026-08-15T17:26:08.537Z" }, - { url = "https://files.pythonhosted.org/packages/17/9b/7289dc191b34279d8f176bf5b181c3b26f8e049d14a2c0a2637650f034e5/backports_zstd-1.7.0-cp313-cp313-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:7e3999b5141d7f85171822d06112f70f7f317d162f0120530dd2c7a28dbf8add", size = 507676, upload-time = "2026-08-15T17:26:09.909Z" }, - { url = "https://files.pythonhosted.org/packages/7c/4d/6dd730b79ab96532e23fe851003545b4cc79e50c5b4c79ffcbe1b724eec4/backports_zstd-1.7.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:69367726f4075c2574746f5883b0dc045805c5b02a81fdf8c829c26d33969de3", size = 477744, upload-time = "2026-08-15T17:26:11.038Z" }, - { url = "https://files.pythonhosted.org/packages/e1/53/11687e5019d56ea47893cf2ba59a6b4884a4e2d1496d0e653aed373b973f/backports_zstd-1.7.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:15e97edfd173ade365c01bac7d9d297fa906686015cdbcb5f32a0d410887826b", size = 583215, upload-time = "2026-08-15T17:26:12.379Z" }, - { url = "https://files.pythonhosted.org/packages/aa/c7/5a8c58542469ab31680c403b844770c119a976fd4cf1000fd7d53e7d0f77/backports_zstd-1.7.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:32a94cdcf16b44395cd55086ea38877395ca6bf3362cb507b0eb86db2a45a6a4", size = 644125, upload-time = "2026-08-15T17:26:13.651Z" }, - { url = "https://files.pythonhosted.org/packages/11/35/be5485e65df95b86c4981ad4a577b505cfeec6b700a46a86e2e3175ac718/backports_zstd-1.7.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3f4887a8a1fd1290017fe5a1d29a7d1dc5c57f9477fbd64f119316a7e3ae769", size = 492714, upload-time = "2026-08-15T17:26:14.838Z" }, - { url = "https://files.pythonhosted.org/packages/96/8b/a0603458ca08e4a56f09ae58588ce3c0453425e753df704d9aeaabb66ae5/backports_zstd-1.7.0-cp313-cp313-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e590313ce156f1d8986dff3107e8ed1651d6d106a56b3a95f965ff8d845ba979", size = 567953, upload-time = "2026-08-15T17:26:16.276Z" }, - { url = "https://files.pythonhosted.org/packages/02/87/2296db4c3c578947c35ccd8dcdf7992316d7e1f5f43cc829c062b3ed9319/backports_zstd-1.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:565270b0d6497970fa97a0df59593ae0d225e4176678bbce851d39e5f8aa422b", size = 483564, upload-time = "2026-08-15T17:26:17.493Z" }, - { url = "https://files.pythonhosted.org/packages/c0/d8/f53a79e6bf3cdb7ae08f95220c80bd0d606f3d6c3482995deaf21d024fb9/backports_zstd-1.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:37ef23c6c522fe935726c8fba6344350973c4a23b06d10194d90d0868b09ff7a", size = 511193, upload-time = "2026-08-15T17:26:18.7Z" }, - { url = "https://files.pythonhosted.org/packages/31/ea/d4e2eb159cd5813debd5a34d0644caff5fe7cf2e569bf5b02a82934aeee7/backports_zstd-1.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b3975330159f1efdd1fba76afe1c7b84f66f26e2bf209b32630fb148d647e0d5", size = 587748, upload-time = "2026-08-15T17:26:20.148Z" }, - { url = "https://files.pythonhosted.org/packages/81/d2/b5ec9709660fb1c193508215d9c30e781fac406183faac7c3c36b1c583a9/backports_zstd-1.7.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:b40bc8cd0a86cbbe8263a9c3a2bf2e34897483516c6d799725412a19524c32e3", size = 565808, upload-time = "2026-08-15T17:26:21.349Z" }, - { url = "https://files.pythonhosted.org/packages/bd/13/004735cc4536483cbd973a60346a9dbc7bb977b13c28b55a11da14bb0a1e/backports_zstd-1.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f37e12ef10747f76901b1f20ef70d33221e861de177dba5ba08552242c6fd4bd", size = 634520, upload-time = "2026-08-15T17:26:22.944Z" }, - { url = "https://files.pythonhosted.org/packages/a3/28/05b11f7084d1100491cf7c60962aafd900c3dd01b1fc1ce85914476cdae0/backports_zstd-1.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5992143b2a8b71b4d17afed20cce2df50f8718228e31d6e716493b1fe9201712", size = 497098, upload-time = "2026-08-15T17:26:24.181Z" }, - { url = "https://files.pythonhosted.org/packages/f5/a5/bdc98d039ddbd5815fc1dd71912bbfb9f820a46ec12004ead51c8d60ea50/backports_zstd-1.7.0-cp313-cp313-win32.whl", hash = "sha256:31ae30d216ffae9243dfa607bcb995f94a70de5765bb8fae1e35ea1ad6497959", size = 291974, upload-time = "2026-08-15T17:26:25.512Z" }, - { url = "https://files.pythonhosted.org/packages/13/7d/fb0da7351e8b152d5149127594972922829281c316618df37a7e724f2eb9/backports_zstd-1.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:8086b4a7443bb2863f7ef8edb317b715d5f3ccec6c5512619bd23d57661ba1b7", size = 329550, upload-time = "2026-08-15T17:26:26.683Z" }, - { url = "https://files.pythonhosted.org/packages/37/f9/109ac272d650483fbdfa611c0040253a405f640604fbc90acc8076c6d37f/backports_zstd-1.7.0-cp313-cp313-win_arm64.whl", hash = "sha256:7eaceeec75e1dbdce40b81fb0ed1ffdb7ce492d970db7f8aabd6a95ccd6c3dd3", size = 292174, upload-time = "2026-08-15T17:26:27.819Z" }, -] - -[[package]] -name = "beautifulsoup4" -version = "4.15.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "soupsieve" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/43/65/318323f98dbee45d42dff61d8f047181bc6f2268a9068cfad035a46be5af/beautifulsoup4-4.15.0.tar.gz", hash = "sha256:288e3ca7d54b06f2ac191970bc275c1939cb46d450b255bf6718b04aa37ab4f7", size = 632571, upload-time = "2026-06-07T16:44:20.453Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/88/c6/92fcd42f1ba33e1184263f25bfabf3d27c383410470f169e4b8163bf9c17/beautifulsoup4-4.15.0-py3-none-any.whl", hash = "sha256:d6f88de62e1d4e38ecb1077eb9724cd0eff29d2a08ca16a401e9b9e93f117cf9", size = 109924, upload-time = "2026-06-07T16:44:21.566Z" }, -] - -[[package]] -name = "binaryornot" -version = "0.6.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/86/72/4755b85101f37707c71526a301c1203e413c715a0016ecb592de3d2dcfff/binaryornot-0.6.0.tar.gz", hash = "sha256:cc8d57cfa71d74ff8c28a7726734d53a851d02fad9e3a5581fb807f989f702f0", size = 478718, upload-time = "2026-03-08T16:26:28.804Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cd/0c/31cfaa6b56fe23488ecb993bc9fc526c0d84d89607decdf2a10776426c2e/binaryornot-0.6.0-py3-none-any.whl", hash = "sha256:900adfd5e1b821255ba7e63139b0396b14c88b9286e74e03b6f51e0200331337", size = 14185, upload-time = "2026-03-08T16:26:27.466Z" }, -] - -[[package]] -name = "brotli" -version = "1.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f7/16/c92ca344d646e71a43b8bb353f0a6490d7f6e06210f8554c8f874e454285/brotli-1.2.0.tar.gz", hash = "sha256:e310f77e41941c13340a95976fe66a8a95b01e783d430eeaf7a2f87e0a57dd0a", size = 7388632, upload-time = "2025-11-05T18:39:42.86Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/11/ee/b0a11ab2315c69bb9b45a2aaed022499c9c24a205c3a49c3513b541a7967/brotli-1.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:35d382625778834a7f3061b15423919aa03e4f5da34ac8e02c074e4b75ab4f84", size = 861543, upload-time = "2025-11-05T18:38:24.183Z" }, - { url = "https://files.pythonhosted.org/packages/e1/2f/29c1459513cd35828e25531ebfcbf3e92a5e49f560b1777a9af7203eb46e/brotli-1.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7a61c06b334bd99bc5ae84f1eeb36bfe01400264b3c352f968c6e30a10f9d08b", size = 444288, upload-time = "2025-11-05T18:38:25.139Z" }, - { url = "https://files.pythonhosted.org/packages/3d/6f/feba03130d5fceadfa3a1bb102cb14650798c848b1df2a808356f939bb16/brotli-1.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:acec55bb7c90f1dfc476126f9711a8e81c9af7fb617409a9ee2953115343f08d", size = 1528071, upload-time = "2025-11-05T18:38:26.081Z" }, - { url = "https://files.pythonhosted.org/packages/2b/38/f3abb554eee089bd15471057ba85f47e53a44a462cfce265d9bf7088eb09/brotli-1.2.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:260d3692396e1895c5034f204f0db022c056f9e2ac841593a4cf9426e2a3faca", size = 1626913, upload-time = "2025-11-05T18:38:27.284Z" }, - { url = "https://files.pythonhosted.org/packages/03/a7/03aa61fbc3c5cbf99b44d158665f9b0dd3d8059be16c460208d9e385c837/brotli-1.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:072e7624b1fc4d601036ab3f4f27942ef772887e876beff0301d261210bca97f", size = 1419762, upload-time = "2025-11-05T18:38:28.295Z" }, - { url = "https://files.pythonhosted.org/packages/21/1b/0374a89ee27d152a5069c356c96b93afd1b94eae83f1e004b57eb6ce2f10/brotli-1.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:adedc4a67e15327dfdd04884873c6d5a01d3e3b6f61406f99b1ed4865a2f6d28", size = 1484494, upload-time = "2025-11-05T18:38:29.29Z" }, - { url = "https://files.pythonhosted.org/packages/cf/57/69d4fe84a67aef4f524dcd075c6eee868d7850e85bf01d778a857d8dbe0a/brotli-1.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7a47ce5c2288702e09dc22a44d0ee6152f2c7eda97b3c8482d826a1f3cfc7da7", size = 1593302, upload-time = "2025-11-05T18:38:30.639Z" }, - { url = "https://files.pythonhosted.org/packages/d5/3b/39e13ce78a8e9a621c5df3aeb5fd181fcc8caba8c48a194cd629771f6828/brotli-1.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:af43b8711a8264bb4e7d6d9a6d004c3a2019c04c01127a868709ec29962b6036", size = 1487913, upload-time = "2025-11-05T18:38:31.618Z" }, - { url = "https://files.pythonhosted.org/packages/62/28/4d00cb9bd76a6357a66fcd54b4b6d70288385584063f4b07884c1e7286ac/brotli-1.2.0-cp312-cp312-win32.whl", hash = "sha256:e99befa0b48f3cd293dafeacdd0d191804d105d279e0b387a32054c1180f3161", size = 334362, upload-time = "2025-11-05T18:38:32.939Z" }, - { url = "https://files.pythonhosted.org/packages/1c/4e/bc1dcac9498859d5e353c9b153627a3752868a9d5f05ce8dedd81a2354ab/brotli-1.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:b35c13ce241abdd44cb8ca70683f20c0c079728a36a996297adb5334adfc1c44", size = 369115, upload-time = "2025-11-05T18:38:33.765Z" }, - { url = "https://files.pythonhosted.org/packages/6c/d4/4ad5432ac98c73096159d9ce7ffeb82d151c2ac84adcc6168e476bb54674/brotli-1.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9e5825ba2c9998375530504578fd4d5d1059d09621a02065d1b6bfc41a8e05ab", size = 861523, upload-time = "2025-11-05T18:38:34.67Z" }, - { url = "https://files.pythonhosted.org/packages/91/9f/9cc5bd03ee68a85dc4bc89114f7067c056a3c14b3d95f171918c088bf88d/brotli-1.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0cf8c3b8ba93d496b2fae778039e2f5ecc7cff99df84df337ca31d8f2252896c", size = 444289, upload-time = "2025-11-05T18:38:35.6Z" }, - { url = "https://files.pythonhosted.org/packages/2e/b6/fe84227c56a865d16a6614e2c4722864b380cb14b13f3e6bef441e73a85a/brotli-1.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c8565e3cdc1808b1a34714b553b262c5de5fbda202285782173ec137fd13709f", size = 1528076, upload-time = "2025-11-05T18:38:36.639Z" }, - { url = "https://files.pythonhosted.org/packages/55/de/de4ae0aaca06c790371cf6e7ee93a024f6b4bb0568727da8c3de112e726c/brotli-1.2.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:26e8d3ecb0ee458a9804f47f21b74845cc823fd1bb19f02272be70774f56e2a6", size = 1626880, upload-time = "2025-11-05T18:38:37.623Z" }, - { url = "https://files.pythonhosted.org/packages/5f/16/a1b22cbea436642e071adcaf8d4b350a2ad02f5e0ad0da879a1be16188a0/brotli-1.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67a91c5187e1eec76a61625c77a6c8c785650f5b576ca732bd33ef58b0dff49c", size = 1419737, upload-time = "2025-11-05T18:38:38.729Z" }, - { url = "https://files.pythonhosted.org/packages/46/63/c968a97cbb3bdbf7f974ef5a6ab467a2879b82afbc5ffb65b8acbb744f95/brotli-1.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4ecdb3b6dc36e6d6e14d3a1bdc6c1057c8cbf80db04031d566eb6080ce283a48", size = 1484440, upload-time = "2025-11-05T18:38:39.916Z" }, - { url = "https://files.pythonhosted.org/packages/06/9d/102c67ea5c9fc171f423e8399e585dabea29b5bc79b05572891e70013cdd/brotli-1.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3e1b35d56856f3ed326b140d3c6d9db91740f22e14b06e840fe4bb1923439a18", size = 1593313, upload-time = "2025-11-05T18:38:41.24Z" }, - { url = "https://files.pythonhosted.org/packages/9e/4a/9526d14fa6b87bc827ba1755a8440e214ff90de03095cacd78a64abe2b7d/brotli-1.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:54a50a9dad16b32136b2241ddea9e4df159b41247b2ce6aac0b3276a66a8f1e5", size = 1487945, upload-time = "2025-11-05T18:38:42.277Z" }, - { url = "https://files.pythonhosted.org/packages/5b/e8/3fe1ffed70cbef83c5236166acaed7bb9c766509b157854c80e2f766b38c/brotli-1.2.0-cp313-cp313-win32.whl", hash = "sha256:1b1d6a4efedd53671c793be6dd760fcf2107da3a52331ad9ea429edf0902f27a", size = 334368, upload-time = "2025-11-05T18:38:43.345Z" }, - { url = "https://files.pythonhosted.org/packages/ff/91/e739587be970a113b37b821eae8097aac5a48e5f0eca438c22e4c7dd8648/brotli-1.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:b63daa43d82f0cdabf98dee215b375b4058cce72871fd07934f179885aad16e8", size = 369116, upload-time = "2025-11-05T18:38:44.609Z" }, -] - -[[package]] -name = "brotlicffi" -version = "1.2.0.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cffi" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/71/97/7845739a36828ffe751a1c6b240692f552fd7ecf65026c51326c0a4aa369/brotlicffi-1.2.0.2.tar.gz", hash = "sha256:5e0fbd13644cf1f6015e75fa5e0ad8fdce1048d9c9ff90b0ce826174b249ee35", size = 478755, upload-time = "2026-08-21T17:29:18.415Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2e/71/c27f24b8334f65f2492601c7764338f156cb904d2ffe0061e6004a76d9cc/brotlicffi-1.2.0.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:d5a8ffa154f16660ab818d78045b55fa6f9970f1ca4c38998766e99c672071cb", size = 438885, upload-time = "2026-08-21T17:29:04.113Z" }, - { url = "https://files.pythonhosted.org/packages/ef/22/d8fd1a4d09b7ab563b89380395e09151d2ef1344be31594df6a6987d4028/brotlicffi-1.2.0.2-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec6b1af7b7a8ce788354f2c603651ada0fba166ec31ab879e2eec462a3e6dbf4", size = 1534365, upload-time = "2026-08-21T17:29:05.878Z" }, - { url = "https://files.pythonhosted.org/packages/06/78/076419ed6c2c6aa3eaac6fd6b076502b4be89d50625fcdc513cd4aeca718/brotlicffi-1.2.0.2-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22916101de0e7ff535f2edf54b52a85591853b8ae9a98737643defdd3c063a3a", size = 1536851, upload-time = "2026-08-21T17:29:07.599Z" }, - { url = "https://files.pythonhosted.org/packages/35/dd/31ae9945cbd605339fb51c9a609f7dbb182cd361adeabc1d470142357206/brotlicffi-1.2.0.2-cp39-abi3-win32.whl", hash = "sha256:df1d34c4ad9adbf7f63a6b42f7d0e4dfd259c88141b85145b57abecc1abc3b24", size = 342379, upload-time = "2026-08-21T17:29:09.05Z" }, - { url = "https://files.pythonhosted.org/packages/95/ae/afd54e744df93b51cc29f6a19beccf9998b25743d7177697390de10479d1/brotlicffi-1.2.0.2-cp39-abi3-win_amd64.whl", hash = "sha256:489ca4da3ee65926d72bf01584b61088a9da6bdd1bb01b2040901e1beaffa8f0", size = 379761, upload-time = "2026-08-21T17:29:10.687Z" }, -] - -[[package]] -name = "certifi" -version = "2026.7.22" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a3/c2/24167ea9858356b47a87a50d39908bfdb72ceeefe0041586e704e5376b3a/certifi-2026.7.22.tar.gz", hash = "sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55", size = 138112, upload-time = "2026-07-22T03:35:12.644Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl", hash = "sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775", size = 136983, upload-time = "2026-07-22T03:35:11.276Z" }, -] - -[[package]] -name = "cffi" -version = "2.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pycparser", marker = "implementation_name != 'PyPy'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9e/ef/008a1939e372c06329a3fce4279c02f328488f3526744906eeec3da7ad5f/cffi-2.1.1.tar.gz", hash = "sha256:dd31f52ea1086513bb9df30f8fcee9b8918323ae067a3d5b78bc826a000712be", size = 530807, upload-time = "2026-08-03T21:21:18.939Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/10/69/43965eccfdead3b9220015fd1320e117be8c6ed01a62ffab76eeb752f5d5/cffi-2.1.1-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:c8c69575568085ba0b1b10c0249d779a214aea6f6522e949a0fc9fb0fcb449d0", size = 184821, upload-time = "2026-08-03T21:19:44.887Z" }, - { url = "https://files.pythonhosted.org/packages/54/7d/16e5a096677b5e313ca80cd5e5170efa3ea44624a82bb111925522da64b1/cffi-2.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f81b3b8f3d4e343550fa4baa0e479bba9f2d29ce9c2e9b51d1ce1718d7442fcf", size = 184719, upload-time = "2026-08-03T21:19:46.129Z" }, - { url = "https://files.pythonhosted.org/packages/56/e6/8941622732edec876dd17d0453dce07317ae96db34f2ec1436c9d3785986/cffi-2.1.1-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:811bd1e21d32de12efca32393a0ab3f5133b54fce9bd44b8bd77ab07da14bf6a", size = 214799, upload-time = "2026-08-03T21:19:47.218Z" }, - { url = "https://files.pythonhosted.org/packages/44/de/f98430906df1545ffde0d543dd124a7a439bc2cd32b36b9c53f805df7333/cffi-2.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:68e62fe11f30d5ca8289242866f0a5291402d8529ca2178ab8afc5c9694ae890", size = 222389, upload-time = "2026-08-03T21:19:48.331Z" }, - { url = "https://files.pythonhosted.org/packages/6a/5b/717f1526b9957b34456313c31645c5b82b8fb5c3fe9e4752999be7128bfc/cffi-2.1.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:4a7c934f7360e8cd64fe9efadcbd10c7c6364f531e432b9a4bf5ccbc9e0e8b50", size = 210249, upload-time = "2026-08-03T21:19:49.543Z" }, - { url = "https://files.pythonhosted.org/packages/64/b3/f8aa4f3e34986c7e4ec45072d1b1b9dd295b6b18007b45518d79726dd725/cffi-2.1.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:3143d81e29e1e20a9ce10901ec369012947876596f75a222235965f2b7ae832e", size = 208775, upload-time = "2026-08-03T21:19:50.918Z" }, - { url = "https://files.pythonhosted.org/packages/b1/db/dceb9dd5b231e1da801793f8acc9f3c52a7e1afe40bb1aae37e02b0faad5/cffi-2.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c1453022f490d2459a11819d83ad1d586e9ff65a12ac3e705ffebd46d3685dcf", size = 221822, upload-time = "2026-08-03T21:19:52.054Z" }, - { url = "https://files.pythonhosted.org/packages/a0/d2/6cd24ae3be000a634109c247d1475d62e5616d0dc78c82770942ec384248/cffi-2.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:208f941bb9d18e768138677f0a6d2ce01f590df56043dda1df1535ac57c88517", size = 225232, upload-time = "2026-08-03T21:19:53.109Z" }, - { url = "https://files.pythonhosted.org/packages/cb/52/3fa190537004dd7f0ab860a6dc7c0175b8667f68d1e618a46f5498d30250/cffi-2.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:210019b6c7cf07f081b4c54635c8cf744377001350e29cc0f81c4377b4797735", size = 223597, upload-time = "2026-08-03T21:19:54.515Z" }, - { url = "https://files.pythonhosted.org/packages/80/fb/0bb75b7039588c074b37ae99f40d9bfddf990ecb2fbc346ebccd2e56b9be/cffi-2.1.1-cp312-cp312-win32.whl", hash = "sha256:046bfc24911b37851ee1b51aab8bffe713d89c68c6a057b09484ce9fd5f69b4e", size = 175292, upload-time = "2026-08-03T21:19:55.566Z" }, - { url = "https://files.pythonhosted.org/packages/d9/79/615cc094e2fb508cade7de88d3b4f6c4ec2bab695c97bce9153dc65aadf5/cffi-2.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:f53e442b08449d42821fa4a4fba000095af9f62742a500f978a9f557ec44339a", size = 185919, upload-time = "2026-08-03T21:19:56.89Z" }, - { url = "https://files.pythonhosted.org/packages/70/c6/d0ea84713fe46b243a436a18fcd47d639732747e21635c8a27191b06dc30/cffi-2.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:7bde5e4cc5c10140859842b9d383af292b22639a4dffb725314baf45968cef80", size = 180093, upload-time = "2026-08-03T21:19:58.155Z" }, - { url = "https://files.pythonhosted.org/packages/9d/f4/035513d4117049066b4779dc3b7c0c0fdad175fa13731c9f4003f1cd1478/cffi-2.1.1-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:b5bdfd1c873d4e093aabc0ca84c4ca6dbc4f752afb5c86f146d9742580c9da2e", size = 194248, upload-time = "2026-08-03T21:19:59.399Z" }, - { url = "https://files.pythonhosted.org/packages/76/af/2aeb4dbb5fc41a04161ae9ff1518de7cec08e164f44a8ce6a4cf7fd2cd1d/cffi-2.1.1-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:31348097ff5bbe827ccc41795d4dd099d9f0625e7def00ee653c137a490c2a6c", size = 196908, upload-time = "2026-08-03T21:20:00.746Z" }, - { url = "https://files.pythonhosted.org/packages/a7/46/2e5fdde8555706dd98139a910ca11be02809f3f605ce956f655d0214e100/cffi-2.1.1-cp313-cp313-macosx_10_15_x86_64.whl", hash = "sha256:9d2055050ea716bd38b7f7f1579c275386646b4894c155a3e2f3cd62ed41b7c6", size = 184805, upload-time = "2026-08-03T21:20:02.02Z" }, - { url = "https://files.pythonhosted.org/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:19ee6127ee34de7d83ce3d371ebc5ed91addbdcc39f9ab15ce4eb35a4e534971", size = 184764, upload-time = "2026-08-03T21:20:03.141Z" }, - { url = "https://files.pythonhosted.org/packages/43/1f/1c3d90d91811c8f86ced9ed637956c54bfe5b79ca98fe976d7f8c8979f6b/cffi-2.1.1-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:6a8dddef476fab96d066d578fc88526767b836ab5ab21754e1d5bf3879c31c7c", size = 214722, upload-time = "2026-08-03T21:20:04.377Z" }, - { url = "https://files.pythonhosted.org/packages/37/6f/3b5ce4c3b2192d250f04908f2bfd91ef34552ec8f7716a5d4abdb8d67bb2/cffi-2.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f16c709686a78c727bbbf059f92b0bf41c6fc60deec706d2dc19f529175a6125", size = 222369, upload-time = "2026-08-03T21:20:05.544Z" }, - { url = "https://files.pythonhosted.org/packages/02/10/4b3c75dde3d9663c9e02ba05c2668b954f671d4bbe346413ca8c696b295a/cffi-2.1.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:fcd22650c908d7b7da162bbfaab594a1227a15d1643a98c68b122ac642fa2264", size = 210175, upload-time = "2026-08-03T21:20:06.75Z" }, - { url = "https://files.pythonhosted.org/packages/df/62/14f74b9543e605d17701dc797b815958b8bb70b7624ce1b832ddad48ed6c/cffi-2.1.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:aa9511c62d14da7aacc9b4bf51f3f697a621e83b2d6919008243c3aad168eea3", size = 208670, upload-time = "2026-08-03T21:20:08.04Z" }, - { url = "https://files.pythonhosted.org/packages/95/95/86342356ff5953b3fb06f7ef7c5bee212d45e770abc7218d451b9148313c/cffi-2.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a931079504ecc49efed7744c476a5c343a92fabf66dec2db95edb1b2fdc770e2", size = 221824, upload-time = "2026-08-03T21:20:09.274Z" }, - { url = "https://files.pythonhosted.org/packages/eb/ff/7b3429ff53aafe931ed8a5fc69f481bbef7ba6de87ddcbb63d08f483f613/cffi-2.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a2d7755bef5a12ed488f4ef1f1b69ee9191d7396083b755a5d2295f6edb4768b", size = 225148, upload-time = "2026-08-03T21:20:10.7Z" }, - { url = "https://files.pythonhosted.org/packages/34/34/a95870b9221e09cf4f2ce3178b1a210abdfe63a1bd357da940418d7b8d15/cffi-2.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e0bcb7e0f677f543555d2adff3bf19c05f66cdb4796e5ff602442ab2fe3c4ef7", size = 223564, upload-time = "2026-08-03T21:20:12.165Z" }, - { url = "https://files.pythonhosted.org/packages/70/ea/839b50531021a647fb5e929f72cf97bc1ff702b5472166164b5b6e76b851/cffi-2.1.1-cp313-cp313-win32.whl", hash = "sha256:334644fbac4eff73d985a17a91226df55d0f394160c4cfb880e084c8f7161cac", size = 175263, upload-time = "2026-08-03T21:20:13.559Z" }, - { url = "https://files.pythonhosted.org/packages/60/a6/8b149b2c3f2e11aaa1618ef64500b45f50f22c57a977a4dff1aff1f91042/cffi-2.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:1aa5645c30469b09530c4ebca77ebf8f17618293c58f8549cb1a543a50236e7d", size = 185688, upload-time = "2026-08-03T21:20:14.69Z" }, - { url = "https://files.pythonhosted.org/packages/01/9a/11f687cb39d6a3504060d5242f04f48c735afb4d3d533958a20594890cb2/cffi-2.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:63bbfd5ded17c4840ac07cd8f1c21ba9d9708141f840b324f422f41b207e3973", size = 180078, upload-time = "2026-08-03T21:20:15.917Z" }, -] - -[[package]] -name = "charset-normalizer" -version = "3.5.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e5/3f/143b048436775b0f76ac3eec145c019e8173ccc2885c8f20319b996d5e83/charset_normalizer-3.5.1.tar.gz", hash = "sha256:6117b84ea48435e5356dc737f5121485c30920ba43375fa7b434fd753df0eac3", size = 171764, upload-time = "2026-08-15T08:20:44.807Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/30/27/78873dc8b6a56357517b74b6bb9568b80450e7bb4f6ef7e3fa9d22aa0bd7/charset_normalizer-3.5.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:5b6d1386bf0096d26d3a863dc0a487a5b4eb9aa93cf5ba69683d29dde6b9d60f", size = 344456, upload-time = "2026-08-15T08:17:10.072Z" }, - { url = "https://files.pythonhosted.org/packages/9a/4c/be49ada26b1f0232d57aa89bbebf997a5cc2332a5616b6eca26ff680044d/charset_normalizer-3.5.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4582c27e8c889d64811987b5967fbd3ae0c823fe1fd933b543d55ac20bb475fa", size = 238530, upload-time = "2026-08-15T08:17:11.563Z" }, - { url = "https://files.pythonhosted.org/packages/76/84/6f1290fa07ae6978d3960caa3eb1b8019bf9284ab7c2297b00c099ef4250/charset_normalizer-3.5.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:1d1c7a53a6c2103925cdd6d7229f8c567379f211c869793df679f2e9f738c369", size = 230200, upload-time = "2026-08-15T08:17:12.919Z" }, - { url = "https://files.pythonhosted.org/packages/e7/a0/47b18adeed31c8f16ba9700f32c1b18594cfa09f47eb672a488c273c22bf/charset_normalizer-3.5.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e6621fb2a4988d6e53eedc455e5903e2679f3967b8acb3d639f1b63c14a2e893", size = 262222, upload-time = "2026-08-15T08:17:14.571Z" }, - { url = "https://files.pythonhosted.org/packages/38/fe/341861ac118dae06f3ec0eb487488af52128f2ef2faf0b11003944d22259/charset_normalizer-3.5.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7c0c10730342b0c9b35dd1d619beb8214e520bd96a1f870f452680b238aab3e0", size = 258951, upload-time = "2026-08-15T08:17:16.158Z" }, - { url = "https://files.pythonhosted.org/packages/6f/89/bb5108dc6c3651dca963f2b0a3ba19bbcb370c94e1b6d3e0e844a58e6dca/charset_normalizer-3.5.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b9af956078716df40d985fb0dfeb2c2120c5ca92ba4ff4b388acfd01cdc14d08", size = 248801, upload-time = "2026-08-15T08:17:17.683Z" }, - { url = "https://files.pythonhosted.org/packages/b1/ba/ef83ae3aca816393decfa3530976f38a79812d707b80b580ac33b83f9877/charset_normalizer-3.5.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f9f8405c2c758532c74fed975dbee57be1f31a6e865c031870c79a6ed3212ada", size = 244070, upload-time = "2026-08-15T08:17:19.191Z" }, - { url = "https://files.pythonhosted.org/packages/f6/0b/c5292a2462d69b7378ea89793bbb5b2b6fcf6f7dd6d1667f9619094ad553/charset_normalizer-3.5.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:96fef3e886d6a9874b14f27fc193fbdc69d5d8035783d86aa4e1cea594e695f9", size = 240110, upload-time = "2026-08-15T08:17:20.547Z" }, - { url = "https://files.pythonhosted.org/packages/46/22/111e5be3b740d5c2a5bfcedb3d237b6591e5c2e82ae9d6ffcb121fe0909c/charset_normalizer-3.5.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5d8531a6569d025f68e2321e7638fb7978f23db58e5f69f56913837aae03816e", size = 232836, upload-time = "2026-08-15T08:17:21.895Z" }, - { url = "https://files.pythonhosted.org/packages/f9/d2/d2aad6fe0dbb44b194bf3becb60f5a0ac48446ade999a47fe7bb41eb09a7/charset_normalizer-3.5.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:aae2ee51122d3ae968a3837d97dc24a0aeebb0dea23694422cd172bd30017cd6", size = 262712, upload-time = "2026-08-15T08:17:23.727Z" }, - { url = "https://files.pythonhosted.org/packages/35/5a/337e4663a5eae6de99db940ee8066d4145caafb61327db62deda15313cce/charset_normalizer-3.5.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:7235dc28fc6dd9d832ac7c7bce95367dedb85929f17368a0c2bee1e080b9acbf", size = 242977, upload-time = "2026-08-15T08:17:25.157Z" }, - { url = "https://files.pythonhosted.org/packages/ca/85/f82f8a92e31c7519410e2e1afdc630f28ec47490ce2c09a11c1a43cbb459/charset_normalizer-3.5.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4abdc5f9ad448c1ecbfae2974b820535d6bc6e7eef63babbab3d81cf46968c71", size = 260207, upload-time = "2026-08-15T08:17:26.602Z" }, - { url = "https://files.pythonhosted.org/packages/b7/52/643d11ffd60e9ac2fd1fb87e167a19285b9eefeff4a40e63c87cbfbeab36/charset_normalizer-3.5.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ba501e667c17d8411f98e67a022d9604ef179aff0e459b7e292c796837c13573", size = 250562, upload-time = "2026-08-15T08:17:27.971Z" }, - { url = "https://files.pythonhosted.org/packages/62/16/46556278c2168d12df9da7fede5dc6fc70e60301b26a82bbeec238c9cfe3/charset_normalizer-3.5.1-cp312-cp312-win32.whl", hash = "sha256:cfa1c0cc3a8f9f53f1243a5a99ac36fd003880199383b37672e86ddda9cb07e2", size = 178507, upload-time = "2026-08-15T08:17:29.277Z" }, - { url = "https://files.pythonhosted.org/packages/9d/7a/4c6c298171e6b3e745633180ff59350fc0ca0db1ffd28df1e369e0579f71/charset_normalizer-3.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:3617ac3cfd8b9888f145ad89dd6e692285834b0201c6074a5eeaad3fd4d668c2", size = 200551, upload-time = "2026-08-15T08:17:30.668Z" }, - { url = "https://files.pythonhosted.org/packages/cd/d7/eb95a042f0dd22e304b0b6472b154f3546a1a039a9ee89ccb2a7f61591fc/charset_normalizer-3.5.1-cp312-cp312-win_arm64.whl", hash = "sha256:88e85ab89cb822c1e635f51d6d32e488f94e002e70e2f492bdb8b945543f345a", size = 180700, upload-time = "2026-08-15T08:17:32.028Z" }, - { url = "https://files.pythonhosted.org/packages/bc/61/2cb6ad133dbbb449fa2d37ccae973232f4827e799af258d15e589a3d1e9e/charset_normalizer-3.5.1-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:4f298bdadb8f0b9e5672877f647d1be9373ef5320c9e2f049795e26cad28b6a9", size = 211584, upload-time = "2026-08-15T08:17:33.597Z" }, - { url = "https://files.pythonhosted.org/packages/18/57/a305c968be1ca13f3dd1b32f445877e97addf55d80b65c7cb35fac82b777/charset_normalizer-3.5.1-cp313-cp313-android_24_x86_64.whl", hash = "sha256:88ca277405c2d3b71c4e1c2ee0e7966e807bcba86a69d11e19ba199d18ae4491", size = 223359, upload-time = "2026-08-15T08:17:35.022Z" }, - { url = "https://files.pythonhosted.org/packages/09/0a/d3646670292ce8d8f8cc11ac067d44885e697a5591f57a9221128da5e7b3/charset_normalizer-3.5.1-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:9362dd90aa7dab48c0054a21187791ccf05473f7dba5d92b8033ae62164675e7", size = 194464, upload-time = "2026-08-15T08:17:36.452Z" }, - { url = "https://files.pythonhosted.org/packages/de/93/d51ec556e01042fed6f993ea859311bc7917b466684182fbbceb6ca24762/charset_normalizer-3.5.1-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:977cdbd483a9cff38179bea4fd754289a6f2195c7abd414aba85410b3e66cc5e", size = 197676, upload-time = "2026-08-15T08:17:37.819Z" }, - { url = "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e90251c0c7bdd54a100a0dce3c07b7e637278c93af29dbf78ebb89a58c4bac7d", size = 340473, upload-time = "2026-08-15T08:17:39.303Z" }, - { url = "https://files.pythonhosted.org/packages/31/e7/1d994be1b93d41e9502b8b0460eaa88a1dd8df335df415db87d6c3e91ab2/charset_normalizer-3.5.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94d78ecec2605a8d0398b0f365d5f12a63248438516f5dac536a5eff7337df4a", size = 240156, upload-time = "2026-08-15T08:17:40.66Z" }, - { url = "https://files.pythonhosted.org/packages/09/53/27923ce5cc6cbccb832037b27dca98882d9c53e9b69e866bbbef4aae7fc8/charset_normalizer-3.5.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d59b75732e9b6f27388e10c14b0259cc5f2e48c78627d185e6a177b58ad3cffe", size = 228246, upload-time = "2026-08-15T08:17:42.003Z" }, - { url = "https://files.pythonhosted.org/packages/ce/48/5a97e84d63af1d55c07439cb80e56d99a8efb4295700eb4e18c0d1615d2c/charset_normalizer-3.5.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0d929fc574b4d6fd9e7c0f5c2ede8716a41911923aa7fa5fce38e0818aa4a1ac", size = 263660, upload-time = "2026-08-15T08:17:43.627Z" }, - { url = "https://files.pythonhosted.org/packages/7a/c2/071575791dcc88316c0a9a65ce38897a82e4cfe4a325f0f7fe1b1ac47bcf/charset_normalizer-3.5.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:394fea06235c8543390050ed5f529187074b029fb027213f6c46ac11ab5d950e", size = 260354, upload-time = "2026-08-15T08:17:45.094Z" }, - { url = "https://files.pythonhosted.org/packages/fb/af/63240b0c0248c075c2535a1f1bd992821d8251b9f173abc13329661d09e4/charset_normalizer-3.5.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62b55f6722735a6c472f88361cde6640608773d9443cebdbb51abf436a1fcdd3", size = 250638, upload-time = "2026-08-15T08:17:46.496Z" }, - { url = "https://files.pythonhosted.org/packages/4d/66/70dfad64f15be09c15ccfee81330a7e515895dbe296dd23114e9a231268a/charset_normalizer-3.5.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fa48b1b63d639f9483e0633e092f5851e2348c352f1f9bb6c8182f87884ef876", size = 244583, upload-time = "2026-08-15T08:17:47.963Z" }, - { url = "https://files.pythonhosted.org/packages/c0/24/ef36367d38b9ddd4bccbf72888c342e8de1f5ae506fa0b2dcf970e2732a1/charset_normalizer-3.5.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c71fb0d56c920c269cd3e2e3fe7c610e3f1fdb21a6ce60efa6430ff63676cea6", size = 242038, upload-time = "2026-08-15T08:17:49.481Z" }, - { url = "https://files.pythonhosted.org/packages/db/ab/55e683ba0fff2e43adafc10daa3001eac90fdaa419a97227d5a7067eedde/charset_normalizer-3.5.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:485a0d363cafefcd2538a73c7c838daa2035f09b2c9f9b5e3133f80c6aeb84c2", size = 233677, upload-time = "2026-08-15T08:17:50.845Z" }, - { url = "https://files.pythonhosted.org/packages/bd/67/0f40eaf8d1b6e7cf15e82382a2965efaca787fc1c2794b7021d37aaf5036/charset_normalizer-3.5.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c0ea61a470e070686aa30892fed79e297d2c8d0ab46b8bcdf027d38c51da591", size = 264491, upload-time = "2026-08-15T08:17:52.61Z" }, - { url = "https://files.pythonhosted.org/packages/5c/64/12b4c2a11ee8df4fcc518c78b0d93e3a92bd3d5253d1617ce74ff0e8c7ef/charset_normalizer-3.5.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:90b7481fb62fbe172c558bc6fd1c4c98d82004a54a7551f20e11ac9bf0b8708c", size = 245196, upload-time = "2026-08-15T08:17:54.023Z" }, - { url = "https://files.pythonhosted.org/packages/37/2e/651d910af6d0fba325eee1cda37ec5443462ed25360e666c144166eb6091/charset_normalizer-3.5.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:35fe081843b35aad20ffeccec3eeffbe637b15d14f3fb22cc1b59cd8ec17e93c", size = 261660, upload-time = "2026-08-15T08:17:55.491Z" }, - { url = "https://files.pythonhosted.org/packages/90/c6/b09e05e6db7f64338e0dc067c79577b1138da86c1e38369096851d96be88/charset_normalizer-3.5.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fd0350afdc3aabd5576f60ea109228bd5538139713c7b094c5cd27c73a98bc6f", size = 252618, upload-time = "2026-08-15T08:17:57.025Z" }, - { url = "https://files.pythonhosted.org/packages/76/4e/362d4f9fdcdf5556fb2aa3ce7d4a58ebce03ed1ff03aa1d9aca8d02f13f3/charset_normalizer-3.5.1-cp313-cp313-pyemscripten_2025_0_wasm32.whl", hash = "sha256:9d9a0dc7cbe9bec24c3f767c9122c41fe5a1bc43f47cd099d00d393e09769de4", size = 140362, upload-time = "2026-08-15T08:17:58.425Z" }, - { url = "https://files.pythonhosted.org/packages/b4/d4/703be739b26acce318bd29eb3b25b7209e1b1f527f9eae3d1f1f01fdde2b/charset_normalizer-3.5.1-cp313-cp313-win32.whl", hash = "sha256:d63600d620ad0064c3a748b950ac5ea38a80190e5498532efefa4b7b3f1da1f3", size = 177755, upload-time = "2026-08-15T08:18:00.037Z" }, - { url = "https://files.pythonhosted.org/packages/8a/33/56d97ade41c8db611e727168c52ae46c9224c362ec28d4b65d7e9869e8da/charset_normalizer-3.5.1-cp313-cp313-win_amd64.whl", hash = "sha256:aea996a6aba25260827c9ea511d1addfde2da9eb686ac961838509086188b7e6", size = 199295, upload-time = "2026-08-15T08:18:01.506Z" }, - { url = "https://files.pythonhosted.org/packages/5b/75/5b20dd1e6573a01a08158fe104104fa2c8abf941745596954185726cd46c/charset_normalizer-3.5.1-cp313-cp313-win_arm64.whl", hash = "sha256:fd0a274c0e5f9a21565cd9d3dd749b61f96b7aa1e20a93aa1ba4029518f2e5c0", size = 179856, upload-time = "2026-08-15T08:18:02.929Z" }, - { url = "https://files.pythonhosted.org/packages/5b/97/fb4e82231aba271ffd775a1b4993b0defc4e3059f286ae41d9433409fe85/charset_normalizer-3.5.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:41876ee62a3dddf48ff1121ad8f0798032aa03f2fd35f21f34a4cab14f18d8d2", size = 331467, upload-time = "2026-08-15T08:19:50.959Z" }, - { url = "https://files.pythonhosted.org/packages/9f/2f/fe3f187327aac18e2d54e9d2b08e15d27bf9b642d9e51c219f130fc34d1a/charset_normalizer-3.5.1-cp37-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a6dac12ff6b846103483683f60c5f8fee205121adc58ffd87e90a90a3af69e99", size = 253057, upload-time = "2026-08-15T08:19:52.654Z" }, - { url = "https://files.pythonhosted.org/packages/d7/c7/9e48cee5c161fe24da823b61bf381921d77cb994a0a4de148e95018c1984/charset_normalizer-3.5.1-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cee5dd7c6fb5dd52a0fe2a740f9bc6e3593f5f8b1788bde49de02086f30182b2", size = 240930, upload-time = "2026-08-15T08:19:54.163Z" }, - { url = "https://files.pythonhosted.org/packages/49/e0/716601f3cc69be7b198951150c75ead1ece33c3c8036ff6ffa46029659a0/charset_normalizer-3.5.1-cp37-abi3-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:343fb4f2821043bd87095f7b08a1a181febc8e36ac64212143bbfd0a0e1bc235", size = 230822, upload-time = "2026-08-15T08:19:55.807Z" }, - { url = "https://files.pythonhosted.org/packages/d3/05/71bfc5caa0abcc45aea1f6a4d50ac68e59605ddc7666fe8494f4cd229665/charset_normalizer-3.5.1-cp37-abi3-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ae4a097991662cd4fff0ddc74e0fe7874f82e00042fa0ea00855645ed0c79598", size = 260037, upload-time = "2026-08-15T08:19:57.312Z" }, - { url = "https://files.pythonhosted.org/packages/c3/92/de7e32ed05341e7a9c4c877c318418197b7f2d66a3b68d561bf2ac57ca3e/charset_normalizer-3.5.1-cp37-abi3-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4b599739b93b2cbeded49645ae3c8d1405c29ddfbceac1545c87a3f9580a9e96", size = 255097, upload-time = "2026-08-15T08:19:59.056Z" }, - { url = "https://files.pythonhosted.org/packages/f5/7b/ade0a122600319dfa0b1000ab0f9731c94a817904cf3c5de408c73a4ede7/charset_normalizer-3.5.1-cp37-abi3-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b39b69b347e5e47a3b5b8cfc005c68c1ba347474e3960236c4944a8ecd174962", size = 250166, upload-time = "2026-08-15T08:20:00.612Z" }, - { url = "https://files.pythonhosted.org/packages/75/9c/019fbb9f4834491a160951349b1a3714439376f66e5f7cf18b4f18f0c7aa/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:a2028475ba855475b8b4d3cfeb4994269c967aea8b9892dfba907f4263a863a3", size = 241821, upload-time = "2026-08-15T08:20:02.321Z" }, - { url = "https://files.pythonhosted.org/packages/2b/b8/11d4840bfc99330cc7fbcc2681ee5a044553a6e77655508d8f9b2bff7b34/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:36047af20e17097c3bb9476c2b7655f2f7aa51322c0ba58c07695bedf755a950", size = 232529, upload-time = "2026-08-15T08:20:04.008Z" }, - { url = "https://files.pythonhosted.org/packages/18/96/2b3a21492d9f65171ac75d872f5018260013d00bfa0ff70ec9f179148cbd/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_ppc64le.whl", hash = "sha256:4c4fb141a727957c93edfe5c32a26ceb6b5f6461d67146e2d39f51e16170bea8", size = 260348, upload-time = "2026-08-15T08:20:05.877Z" }, - { url = "https://files.pythonhosted.org/packages/d6/aa/a69a2028e8bd052476c245460ab19d7de595de084dd968f2d75cd50c3e25/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_riscv64.whl", hash = "sha256:2f293479cce755c75f1697e87c409b7ae4c555c7dfecb6e988ad13abba943031", size = 247234, upload-time = "2026-08-15T08:20:07.487Z" }, - { url = "https://files.pythonhosted.org/packages/35/8a/3d130aeabcaf3d2466af76b7b141c08d9e89c9016ab4b7cdd0f7dc2d1c62/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_s390x.whl", hash = "sha256:3588e376b3ea2eea84976f67273d679f229e24c66dce7b82ae45aef04ff6e072", size = 256917, upload-time = "2026-08-15T08:20:09.142Z" }, - { url = "https://files.pythonhosted.org/packages/80/c2/a7379b840292d0c1ab9fbd17d1f3967aa81794dc95bc74be8999d7fedcf7/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e199fb99720074809a7720f1c0b4d919eea8b87e88713e0f8f602f7bef543d9d", size = 254846, upload-time = "2026-08-15T08:20:10.727Z" }, - { url = "https://files.pythonhosted.org/packages/01/65/d43b714731bb2f40d4053dfa00ecfc1c5a301f8e3316c5db3a09af59fe94/charset_normalizer-3.5.1-cp37-abi3-win32.whl", hash = "sha256:dd732602a7009217f658d5863d12d79d373a4de0eebc111094bcdd3bb8e0a6cc", size = 174216, upload-time = "2026-08-15T08:20:12.334Z" }, - { url = "https://files.pythonhosted.org/packages/35/4f/b911ed898b26a09789eba9c9200c999aff6c61b4bafaf4838e56d1a1e1a3/charset_normalizer-3.5.1-cp37-abi3-win_amd64.whl", hash = "sha256:70055ff39b97c99e7ae40ea3e393fb62aa2e44dbd9b29f8d14f42fb0025c3959", size = 199764, upload-time = "2026-08-15T08:20:13.908Z" }, - { url = "https://files.pythonhosted.org/packages/f0/a7/920baf467bfd9bf689f3b318340f37aee4572a71f162bd8db51da55ba4fa/charset_normalizer-3.5.1-cp37-abi3-win_arm64.whl", hash = "sha256:87e4f41d375c0b9be2fb5251aee4b8a689169e134535aed81bf085c3b647451e", size = 287318, upload-time = "2026-08-15T08:20:15.551Z" }, - { url = "https://files.pythonhosted.org/packages/cc/61/d01fc49b8dea277640b55a9e15960dbca9fdc8c9fde18e572d39c59f4019/charset_normalizer-3.5.1-py3-none-any.whl", hash = "sha256:6df0ec430f9a831772c23ca5a224cba36517a58a84bb32c32bb59a9fa67c47f6", size = 68658, upload-time = "2026-08-15T08:20:43.306Z" }, -] - -[[package]] -name = "clanguru" -version = "0.21.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jinja2" }, - { name = "libclang" }, - { name = "mashumaro" }, - { name = "openpyxl" }, - { name = "py-app-dev" }, - { name = "pyyaml" }, - { name = "typer" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/8e/83/e4cf6f23ff4d2251d74a08480e20b164a7e074cecfab5fea5f3952c51427/clanguru-0.21.0.tar.gz", hash = "sha256:a13d9275aef37b6a87e4cd9c131c5fe7a31afeaeaff619b83cb8dbea667c448d", size = 42313, upload-time = "2026-09-09T18:48:35.508Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/53/a0/aaa4944711d5098a52cc60c9352f86a1c918456ca6452f4a8aa7c9521967/clanguru-0.21.0-py3-none-any.whl", hash = "sha256:6c9de23ad211be5275a2bd943216a8c0d2f1f9c63131de94eef6c9d23dc2e2a5", size = 43892, upload-time = "2026-09-09T18:48:34.045Z" }, -] - -[[package]] -name = "click" -version = "8.1.8" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593, upload-time = "2024-12-21T18:38:44.339Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188, upload-time = "2024-12-21T18:38:41.666Z" }, -] - -[[package]] -name = "click-option-group" -version = "0.5.9" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ef/ff/d291d66595b30b83d1cb9e314b2c9be7cfc7327d4a0d40a15da2416ea97b/click_option_group-0.5.9.tar.gz", hash = "sha256:f94ed2bc4cf69052e0f29592bd1e771a1789bd7bfc482dd0bc482134aff95823", size = 22222, upload-time = "2025-10-09T09:38:01.474Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/75/45/54bb2d8d4138964a94bef6e9afe48b0be4705ba66ac442ae7d8a8dc4ffef/click_option_group-0.5.9-py3-none-any.whl", hash = "sha256:ad2599248bd373e2e19bec5407967c3eec1d0d4fc4a5e77b08a0481e75991080", size = 11553, upload-time = "2025-10-09T09:38:00.066Z" }, -] - -[[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 = "colorlog" -version = "6.12.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/8c/55/ba79756cb90c8d69d599d57785398ac87bba7b19c80e87f4e8a562197c93/colorlog-6.12.0.tar.gz", hash = "sha256:2a7924c1dadf18b22a0eb8b06d1c7b01d5341707ec1641eb6fcc4fde0c3e8e5f", size = 18151, upload-time = "2026-07-23T13:40:40.71Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d4/19/0b6647bf5e331521e55d2b63bfbdc210bd9cd605189273f03614a05f702d/colorlog-6.12.0-py3-none-any.whl", hash = "sha256:30d392604e9110045a2c2aeefc27d7a017abbab63f3a8aee594eac0801df784e", size = 12239, upload-time = "2026-07-23T13:40:39.562Z" }, -] - -[[package]] -name = "comment-parser" -version = "1.2.4" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.13'", -] -dependencies = [ - { name = "python-magic", version = "0.4.24", source = { registry = "https://pypi.org/simple" } }, -] -sdist = { url = "https://files.pythonhosted.org/packages/76/cd/6e4c79d4a25e3b6542d1a3728b3e2b2c4650e3f8c3cde950aaecc6f64764/comment_parser-1.2.4.tar.gz", hash = "sha256:4e03c421c07d146f5a4d248423820347f3589f60d17acea55f7fb5683faffa22", size = 8350, upload-time = "2022-01-26T04:50:40.828Z" } - -[[package]] -name = "comment-parser" -version = "1.2.5" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.13'", -] -dependencies = [ - { name = "python-magic", version = "0.4.27", source = { registry = "https://pypi.org/simple" } }, -] -sdist = { url = "https://files.pythonhosted.org/packages/37/6a/354d8e640b5f90996ac07c002189a552226a0ddaad85efd14863166aaa14/comment_parser-1.2.5.tar.gz", hash = "sha256:5606b769228cafce03d538e361472896581b386f3bc44bd62f4b61ff45ff05ec", size = 8852, upload-time = "2024-12-25T05:08:14.618Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/53/12ceba92ce55851a3d34123b2774a32689f745ce4c0c9bebca1a2a07e266/comment_parser-1.2.5-py3-none-any.whl", hash = "sha256:fb3dee8f351ebd1cfc22d3f19dabf93a4f7d4c9ea13b2092242de086a4449d9e", size = 13222, upload-time = "2026-03-16T03:30:00.77Z" }, -] - -[[package]] -name = "contourpy" -version = "1.3.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174, upload-time = "2025-07-26T12:03:12.549Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/be/45/adfee365d9ea3d853550b2e735f9d66366701c65db7855cd07621732ccfc/contourpy-1.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b08a32ea2f8e42cf1d4be3169a98dd4be32bafe4f22b6c4cb4ba810fa9e5d2cb", size = 293419, upload-time = "2025-07-26T12:01:21.16Z" }, - { url = "https://files.pythonhosted.org/packages/53/3e/405b59cfa13021a56bba395a6b3aca8cec012b45bf177b0eaf7a202cde2c/contourpy-1.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:556dba8fb6f5d8742f2923fe9457dbdd51e1049c4a43fd3986a0b14a1d815fc6", size = 273979, upload-time = "2025-07-26T12:01:22.448Z" }, - { url = "https://files.pythonhosted.org/packages/d4/1c/a12359b9b2ca3a845e8f7f9ac08bdf776114eb931392fcad91743e2ea17b/contourpy-1.3.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92d9abc807cf7d0e047b95ca5d957cf4792fcd04e920ca70d48add15c1a90ea7", size = 332653, upload-time = "2025-07-26T12:01:24.155Z" }, - { url = "https://files.pythonhosted.org/packages/63/12/897aeebfb475b7748ea67b61e045accdfcf0d971f8a588b67108ed7f5512/contourpy-1.3.3-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2e8faa0ed68cb29af51edd8e24798bb661eac3bd9f65420c1887b6ca89987c8", size = 379536, upload-time = "2025-07-26T12:01:25.91Z" }, - { url = "https://files.pythonhosted.org/packages/43/8a/a8c584b82deb248930ce069e71576fc09bd7174bbd35183b7943fb1064fd/contourpy-1.3.3-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:626d60935cf668e70a5ce6ff184fd713e9683fb458898e4249b63be9e28286ea", size = 384397, upload-time = "2025-07-26T12:01:27.152Z" }, - { url = "https://files.pythonhosted.org/packages/cc/8f/ec6289987824b29529d0dfda0d74a07cec60e54b9c92f3c9da4c0ac732de/contourpy-1.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d00e655fcef08aba35ec9610536bfe90267d7ab5ba944f7032549c55a146da1", size = 362601, upload-time = "2025-07-26T12:01:28.808Z" }, - { url = "https://files.pythonhosted.org/packages/05/0a/a3fe3be3ee2dceb3e615ebb4df97ae6f3828aa915d3e10549ce016302bd1/contourpy-1.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:451e71b5a7d597379ef572de31eeb909a87246974d960049a9848c3bc6c41bf7", size = 1331288, upload-time = "2025-07-26T12:01:31.198Z" }, - { url = "https://files.pythonhosted.org/packages/33/1d/acad9bd4e97f13f3e2b18a3977fe1b4a37ecf3d38d815333980c6c72e963/contourpy-1.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:459c1f020cd59fcfe6650180678a9993932d80d44ccde1fa1868977438f0b411", size = 1403386, upload-time = "2025-07-26T12:01:33.947Z" }, - { url = "https://files.pythonhosted.org/packages/cf/8f/5847f44a7fddf859704217a99a23a4f6417b10e5ab1256a179264561540e/contourpy-1.3.3-cp312-cp312-win32.whl", hash = "sha256:023b44101dfe49d7d53932be418477dba359649246075c996866106da069af69", size = 185018, upload-time = "2025-07-26T12:01:35.64Z" }, - { url = "https://files.pythonhosted.org/packages/19/e8/6026ed58a64563186a9ee3f29f41261fd1828f527dd93d33b60feca63352/contourpy-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:8153b8bfc11e1e4d75bcb0bff1db232f9e10b274e0929de9d608027e0d34ff8b", size = 226567, upload-time = "2025-07-26T12:01:36.804Z" }, - { url = "https://files.pythonhosted.org/packages/d1/e2/f05240d2c39a1ed228d8328a78b6f44cd695f7ef47beb3e684cf93604f86/contourpy-1.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:07ce5ed73ecdc4a03ffe3e1b3e3c1166db35ae7584be76f65dbbe28a7791b0cc", size = 193655, upload-time = "2025-07-26T12:01:37.999Z" }, - { url = "https://files.pythonhosted.org/packages/68/35/0167aad910bbdb9599272bd96d01a9ec6852f36b9455cf2ca67bd4cc2d23/contourpy-1.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:177fb367556747a686509d6fef71d221a4b198a3905fe824430e5ea0fda54eb5", size = 293257, upload-time = "2025-07-26T12:01:39.367Z" }, - { url = "https://files.pythonhosted.org/packages/96/e4/7adcd9c8362745b2210728f209bfbcf7d91ba868a2c5f40d8b58f54c509b/contourpy-1.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d002b6f00d73d69333dac9d0b8d5e84d9724ff9ef044fd63c5986e62b7c9e1b1", size = 274034, upload-time = "2025-07-26T12:01:40.645Z" }, - { url = "https://files.pythonhosted.org/packages/73/23/90e31ceeed1de63058a02cb04b12f2de4b40e3bef5e082a7c18d9c8ae281/contourpy-1.3.3-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:348ac1f5d4f1d66d3322420f01d42e43122f43616e0f194fc1c9f5d830c5b286", size = 334672, upload-time = "2025-07-26T12:01:41.942Z" }, - { url = "https://files.pythonhosted.org/packages/ed/93/b43d8acbe67392e659e1d984700e79eb67e2acb2bd7f62012b583a7f1b55/contourpy-1.3.3-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:655456777ff65c2c548b7c454af9c6f33f16c8884f11083244b5819cc214f1b5", size = 381234, upload-time = "2025-07-26T12:01:43.499Z" }, - { url = "https://files.pythonhosted.org/packages/46/3b/bec82a3ea06f66711520f75a40c8fc0b113b2a75edb36aa633eb11c4f50f/contourpy-1.3.3-cp313-cp313-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:644a6853d15b2512d67881586bd03f462c7ab755db95f16f14d7e238f2852c67", size = 385169, upload-time = "2025-07-26T12:01:45.219Z" }, - { url = "https://files.pythonhosted.org/packages/4b/32/e0f13a1c5b0f8572d0ec6ae2f6c677b7991fafd95da523159c19eff0696a/contourpy-1.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4debd64f124ca62069f313a9cb86656ff087786016d76927ae2cf37846b006c9", size = 362859, upload-time = "2025-07-26T12:01:46.519Z" }, - { url = "https://files.pythonhosted.org/packages/33/71/e2a7945b7de4e58af42d708a219f3b2f4cff7386e6b6ab0a0fa0033c49a9/contourpy-1.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a15459b0f4615b00bbd1e91f1b9e19b7e63aea7483d03d804186f278c0af2659", size = 1332062, upload-time = "2025-07-26T12:01:48.964Z" }, - { url = "https://files.pythonhosted.org/packages/12/fc/4e87ac754220ccc0e807284f88e943d6d43b43843614f0a8afa469801db0/contourpy-1.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca0fdcd73925568ca027e0b17ab07aad764be4706d0a925b89227e447d9737b7", size = 1403932, upload-time = "2025-07-26T12:01:51.979Z" }, - { url = "https://files.pythonhosted.org/packages/a6/2e/adc197a37443f934594112222ac1aa7dc9a98faf9c3842884df9a9d8751d/contourpy-1.3.3-cp313-cp313-win32.whl", hash = "sha256:b20c7c9a3bf701366556e1b1984ed2d0cedf999903c51311417cf5f591d8c78d", size = 185024, upload-time = "2025-07-26T12:01:53.245Z" }, - { url = "https://files.pythonhosted.org/packages/18/0b/0098c214843213759692cc638fce7de5c289200a830e5035d1791d7a2338/contourpy-1.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:1cadd8b8969f060ba45ed7c1b714fe69185812ab43bd6b86a9123fe8f99c3263", size = 226578, upload-time = "2025-07-26T12:01:54.422Z" }, - { url = "https://files.pythonhosted.org/packages/8a/9a/2f6024a0c5995243cd63afdeb3651c984f0d2bc727fd98066d40e141ad73/contourpy-1.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:fd914713266421b7536de2bfa8181aa8c699432b6763a0ea64195ebe28bff6a9", size = 193524, upload-time = "2025-07-26T12:01:55.73Z" }, - { url = "https://files.pythonhosted.org/packages/c0/b3/f8a1a86bd3298513f500e5b1f5fd92b69896449f6cab6a146a5d52715479/contourpy-1.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:88df9880d507169449d434c293467418b9f6cbe82edd19284aa0409e7fdb933d", size = 306730, upload-time = "2025-07-26T12:01:57.051Z" }, - { url = "https://files.pythonhosted.org/packages/3f/11/4780db94ae62fc0c2053909b65dc3246bd7cecfc4f8a20d957ad43aa4ad8/contourpy-1.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d06bb1f751ba5d417047db62bca3c8fde202b8c11fb50742ab3ab962c81e8216", size = 287897, upload-time = "2025-07-26T12:01:58.663Z" }, - { url = "https://files.pythonhosted.org/packages/ae/15/e59f5f3ffdd6f3d4daa3e47114c53daabcb18574a26c21f03dc9e4e42ff0/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e4e6b05a45525357e382909a4c1600444e2a45b4795163d3b22669285591c1ae", size = 326751, upload-time = "2025-07-26T12:02:00.343Z" }, - { url = "https://files.pythonhosted.org/packages/0f/81/03b45cfad088e4770b1dcf72ea78d3802d04200009fb364d18a493857210/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ab3074b48c4e2cf1a960e6bbeb7f04566bf36b1861d5c9d4d8ac04b82e38ba20", size = 375486, upload-time = "2025-07-26T12:02:02.128Z" }, - { url = "https://files.pythonhosted.org/packages/0c/ba/49923366492ffbdd4486e970d421b289a670ae8cf539c1ea9a09822b371a/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c3d53c796f8647d6deb1abe867daeb66dcc8a97e8455efa729516b997b8ed99", size = 388106, upload-time = "2025-07-26T12:02:03.615Z" }, - { url = "https://files.pythonhosted.org/packages/9f/52/5b00ea89525f8f143651f9f03a0df371d3cbd2fccd21ca9b768c7a6500c2/contourpy-1.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50ed930df7289ff2a8d7afeb9603f8289e5704755c7e5c3bbd929c90c817164b", size = 352548, upload-time = "2025-07-26T12:02:05.165Z" }, - { url = "https://files.pythonhosted.org/packages/32/1d/a209ec1a3a3452d490f6b14dd92e72280c99ae3d1e73da74f8277d4ee08f/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4feffb6537d64b84877da813a5c30f1422ea5739566abf0bd18065ac040e120a", size = 1322297, upload-time = "2025-07-26T12:02:07.379Z" }, - { url = "https://files.pythonhosted.org/packages/bc/9e/46f0e8ebdd884ca0e8877e46a3f4e633f6c9c8c4f3f6e72be3fe075994aa/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2b7e9480ffe2b0cd2e787e4df64270e3a0440d9db8dc823312e2c940c167df7e", size = 1391023, upload-time = "2025-07-26T12:02:10.171Z" }, - { url = "https://files.pythonhosted.org/packages/b9/70/f308384a3ae9cd2209e0849f33c913f658d3326900d0ff5d378d6a1422d2/contourpy-1.3.3-cp313-cp313t-win32.whl", hash = "sha256:283edd842a01e3dcd435b1c5116798d661378d83d36d337b8dde1d16a5fc9ba3", size = 196157, upload-time = "2025-07-26T12:02:11.488Z" }, - { url = "https://files.pythonhosted.org/packages/b2/dd/880f890a6663b84d9e34a6f88cded89d78f0091e0045a284427cb6b18521/contourpy-1.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:87acf5963fc2b34825e5b6b048f40e3635dd547f590b04d2ab317c2619ef7ae8", size = 240570, upload-time = "2025-07-26T12:02:12.754Z" }, - { url = "https://files.pythonhosted.org/packages/80/99/2adc7d8ffead633234817ef8e9a87115c8a11927a94478f6bb3d3f4d4f7d/contourpy-1.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:3c30273eb2a55024ff31ba7d052dde990d7d8e5450f4bbb6e913558b3d6c2301", size = 199713, upload-time = "2025-07-26T12:02:14.4Z" }, -] - -[[package]] -name = "cookiecutter" -version = "2.7.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "arrow" }, - { name = "binaryornot" }, - { name = "click" }, - { name = "jinja2" }, - { name = "python-slugify" }, - { name = "pyyaml" }, - { name = "requests" }, - { name = "rich" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/92/03/f4c96d8fd4f5e8af0210bf896eb63927f35d3014a8e8f3bf9d2c43ad3332/cookiecutter-2.7.1.tar.gz", hash = "sha256:ca7bb7bc8c6ff441fbf53921b5537668000e38d56e28d763a1b73975c66c6138", size = 142854, upload-time = "2026-03-04T04:06:02.786Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/14/a9/8c855c14b401dc67d20739345295af5afce5e930a69600ab20f6cfa50b5c/cookiecutter-2.7.1-py3-none-any.whl", hash = "sha256:cee50defc1eaa7ad0071ee9b9893b746c1b3201b66bf4d3686d0f127c8ed6cf9", size = 41317, upload-time = "2026-03-04T04:06:01.221Z" }, -] - -[[package]] -name = "cycler" -version = "0.12.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, -] - -[[package]] -name = "defusedxml" -version = "0.7.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520, upload-time = "2021-03-08T10:59:26.269Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload-time = "2021-03-08T10:59:24.45Z" }, -] - -[[package]] -name = "deprecated" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "wrapt" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/49/85/12f0a49a7c4ffb70572b6c2ef13c90c88fd190debda93b23f026b25f9634/deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223", size = 2932523, upload-time = "2025-10-30T08:19:02.757Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f", size = 11298, upload-time = "2025-10-30T08:19:00.758Z" }, -] - -[[package]] -name = "docopt" -version = "0.6.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491", size = 25901, upload-time = "2014-06-16T11:18:57.406Z" } - -[[package]] -name = "docutils" -version = "0.21.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444, upload-time = "2024-04-23T18:57:18.24Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408, upload-time = "2024-04-23T18:57:14.835Z" }, -] - -[[package]] -name = "dotty-dict" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6a/ab/88d67f02024700b48cd8232579ad1316aa9df2272c63049c27cc094229d6/dotty_dict-1.3.1.tar.gz", hash = "sha256:4b016e03b8ae265539757a53eba24b9bfda506fb94fbce0bee843c6f05541a15", size = 7699, upload-time = "2022-07-09T18:50:57.727Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1a/91/e0d457ee03ec33d79ee2cd8d212debb1bc21dfb99728ae35efdb5832dc22/dotty_dict-1.3.1-py3-none-any.whl", hash = "sha256:5022d234d9922f13aa711b4950372a06a6d64cb6d6db9ba43d0ba133ebfce31f", size = 7014, upload-time = "2022-07-09T18:50:55.058Z" }, -] - -[[package]] -name = "et-xmlfile" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d3/38/af70d7ab1ae9d4da450eeec1fa3918940a5fafb9055e934af8d6eb0c2313/et_xmlfile-2.0.0.tar.gz", hash = "sha256:dab3f4764309081ce75662649be815c4c9081e88f0837825f90fd28317d4da54", size = 17234, upload-time = "2024-10-25T17:25:40.039Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/8b/5fe2cc11fee489817272089c4203e679c63b570a5aaeb18d852ae3cbba6a/et_xmlfile-2.0.0-py3-none-any.whl", hash = "sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa", size = 18059, upload-time = "2024-10-25T17:25:39.051Z" }, -] - -[[package]] -name = "fonttools" -version = "4.65.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/77/51/d63c7e52163ac14393a35bd14bd7c0da95f8f74be5d7cc988092f9965129/fonttools-4.65.0.tar.gz", hash = "sha256:762ba5431358d0dbd4a01982484a1d494fb267e91f974cdcf20b80eab8560f6f", size = 3674467, upload-time = "2026-09-10T15:35:54.955Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/58/db/242fa4fce7f632c5f7ab15585343393b25792510c0c32bd218ad24d59f1c/fonttools-4.65.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e844a45c9e5ced6536f184cf1a65b5d65e8f7e711993b413e10500a8223622e5", size = 3097120, upload-time = "2026-09-10T15:33:46Z" }, - { url = "https://files.pythonhosted.org/packages/a0/b6/42fa4d373416675f74446421cf0b2badb82a4245c60745f05f424f75c649/fonttools-4.65.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b30e953de049bf43fc0a63c7d0c44d205c923e4bbf24716aae1518c0e65f977c", size = 2584658, upload-time = "2026-09-10T15:33:48.473Z" }, - { url = "https://files.pythonhosted.org/packages/75/6f/d589b9d62280a846c77a2c383d852c6dcb79ae8aa02bf0fa46c8577af145/fonttools-4.65.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:09c34bdeed8915bfb53bee0c8ed2254dbd8ec69c0014b7f3702f347c049bf358", size = 5425737, upload-time = "2026-09-10T15:33:51.473Z" }, - { url = "https://files.pythonhosted.org/packages/b5/09/de2c0c20a42c18e565a2617932beb08c06697bbdd0d3f62b108262e11583/fonttools-4.65.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:05595385ae99f4b9626cebb973bf171b8fe38a8f40708e6e42abba0ed7537778", size = 5402463, upload-time = "2026-09-10T15:33:54.907Z" }, - { url = "https://files.pythonhosted.org/packages/79/2e/bc0f5c9dce21821454bb5812d3b23410bca33c8bbd5468386d0327aa0cff/fonttools-4.65.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d95b34dd68fbfc0e4a1740c421597656117f979ed8dc85de66e08f9f9981806e", size = 5362168, upload-time = "2026-09-10T15:33:57.481Z" }, - { url = "https://files.pythonhosted.org/packages/1f/0d/2116763ade7e71e0e5d421babe1785d745be9b3d605bf914792ce1c97f79/fonttools-4.65.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:924d06e6130429168318db71c40174a765ad016fc4b56ca811287e3d7373b3a6", size = 5524117, upload-time = "2026-09-10T15:34:00.021Z" }, - { url = "https://files.pythonhosted.org/packages/e2/5e/f9600553b9f645e3068553831685ff1dab6259536a23b38d2e048de38f17/fonttools-4.65.0-cp312-cp312-win32.whl", hash = "sha256:04f73dd01005752a6e75cf4a8dc6b70dc724d1d4bc34cc89522153f4a2f07680", size = 2432089, upload-time = "2026-09-10T15:34:02.803Z" }, - { url = "https://files.pythonhosted.org/packages/3a/02/e436a6a1863b9862bab9f82d6da33055dd7aa3738017edd902a163525dc2/fonttools-4.65.0-cp312-cp312-win_amd64.whl", hash = "sha256:3b5d9ba89edf778b376e669b879ae33a198bf45cf5a23c3f6514f935cf9d0d9d", size = 2483475, upload-time = "2026-09-10T15:34:05.09Z" }, - { url = "https://files.pythonhosted.org/packages/c4/5c/343a4225e83eb06f82c1d8bf41fc5e5f71eab2f62bc7ca215c764722c0a9/fonttools-4.65.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8b7bb52817a24731d2e4f4df0e71fdde05e6c806c8f8f1517b015d142fdacfa5", size = 3094663, upload-time = "2026-09-10T15:34:07.235Z" }, - { url = "https://files.pythonhosted.org/packages/9b/c9/49b2401be932741d9218181c08948c96db32eab21ecaaf79283b752e13e7/fonttools-4.65.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e2c21772fcf70325189707b19f346812690bb1b0bd7e207e6ac205244806b303", size = 2584521, upload-time = "2026-09-10T15:34:09.648Z" }, - { url = "https://files.pythonhosted.org/packages/51/c9/48b07e6c5cf44fa56f758a04c3772a66c0e9ba82bbe22077e4076746a62b/fonttools-4.65.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:64c9b26816415b5e3d899e9077109d327b22140fe3c4066644d8cdbad5bb1569", size = 5395399, upload-time = "2026-09-10T15:34:12.38Z" }, - { url = "https://files.pythonhosted.org/packages/fa/2d/5cc5a10c8ed56079d6c2e9e3e5920622529a2ae045c9f47a6055ccb1a319/fonttools-4.65.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6dd6243f60e2d6160c2966e1e14020dc261ffd741b69a2e4ca8bfd051592e4b7", size = 5376659, upload-time = "2026-09-10T15:34:15.239Z" }, - { url = "https://files.pythonhosted.org/packages/ab/6f/ccf33739d936bb3afa1655a225be7ee5d63d6d3c8b7d0e570bc5a2a7b899/fonttools-4.65.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:834962fd7cf21c58e81ac50a59e6ed2306f9df5e3dd481dad1cd7d2c4c60b773", size = 5336795, upload-time = "2026-09-10T15:34:17.817Z" }, - { url = "https://files.pythonhosted.org/packages/7e/c1/ffd17483f2094f0f4118974295b514b5b82afd4f6e3c80c23f01684e97a6/fonttools-4.65.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:580eb68ff7bd6954a7a76afddd864bfc66eaaf5f5c20dd6ead9186d0055a4ffe", size = 5496530, upload-time = "2026-09-10T15:34:20.241Z" }, - { url = "https://files.pythonhosted.org/packages/b1/19/9aca7712d0676ba5f8d1530ce20478a9bb09cccd0153d56693337379cdcf/fonttools-4.65.0-cp313-cp313-win32.whl", hash = "sha256:7a18b2ffd44249fe84289253197aa65ad4f2de554c0d381f18b1f5939bc6bc60", size = 2430392, upload-time = "2026-09-10T15:34:22.906Z" }, - { url = "https://files.pythonhosted.org/packages/1f/6f/f015dea0f4354e0798751b657cea2dee482914737f88bf1a078349ce92cf/fonttools-4.65.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ae1846b0f192fd485d26a455af19b8f5cf05aff08f9836f533913d8fcea133c", size = 2481620, upload-time = "2026-09-10T15:34:25.816Z" }, - { url = "https://files.pythonhosted.org/packages/e6/35/f894ceb867118c0261d0f69a9bd516b045a3754238f76c88a49513ac7a83/fonttools-4.65.0-py3-none-any.whl", hash = "sha256:3060b8c1fc2329fa20265b7c138614143ea7c1624e26c5c180c76aeb74deae6f", size = 1196441, upload-time = "2026-09-10T15:35:52.347Z" }, -] - -[[package]] -name = "gcovr" -version = "8.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorlog" }, - { name = "jinja2" }, - { name = "lxml" }, - { name = "pygments" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/07/37/b4a87dff166dc0a5002e9d03fcb6ca8eeff048247b011b67f047e31122c9/gcovr-8.6.tar.gz", hash = "sha256:b2e7042abca9321cadbab8a06eb34d19f801b831557b28cdc30a029313de8b9e", size = 199997, upload-time = "2026-01-13T20:04:30.019Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/92/be/f722c843e7875c7cf92cf0e0c1604cddda55a70278c768c6327a78fdba79/gcovr-8.6-py3-none-any.whl", hash = "sha256:dbf9d87c38042752ad6f530aa8210427e22b526611bb7b7bfed0e81977d1f1ef", size = 254618, upload-time = "2026-01-13T20:04:28.15Z" }, -] - -[[package]] -name = "gitdb" -version = "4.0.12" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "smmap" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", size = 394684, upload-time = "2025-01-02T07:20:46.413Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf", size = 62794, upload-time = "2025-01-02T07:20:43.624Z" }, -] - -[[package]] -name = "gitpython" -version = "3.1.62" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "gitdb" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e0/db/3ca813cbacb23ab6fe46ff38a9b5ef8e73e970c8051f2ce903aacafe0446/gitpython-3.1.62.tar.gz", hash = "sha256:1791de66309bc0c7cfca40bf8d2e3de7ca091cbf94e6051be1ad0722c61062af", size = 231728, upload-time = "2026-09-07T02:57:21.155Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d6/0b/29d7965215f8ef830a7ca1f42997fe13e5693d85e9edb18f938d063ef5f2/gitpython-3.1.62-py3-none-any.whl", hash = "sha256:7002251225e10e29d2e1f49e6532613fe5d5d9f0b6f1f02997a52b38fe56899e", size = 222753, upload-time = "2026-09-07T02:57:19.762Z" }, -] - -[[package]] -name = "giturlparse" -version = "0.15.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8c/8a/b70b84cc78f9059d627f09560c81a11e8f046570d220a24e169489cad6c9/giturlparse-0.15.0.tar.gz", hash = "sha256:9af3f1fd5c4a0cac94ddb283593635005646393ee0debbe330d1bdff8866bf2c", size = 16138, upload-time = "2026-06-16T07:28:56.021Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/96/147a2771ab655b9353781fb2f95c94eaf1d8576dccc991c1a61d0d355067/giturlparse-0.15.0-py2.py3-none-any.whl", hash = "sha256:76d2e6983b037356ab99b30683e533ac3db96409b68e2163a20fc3aff6446f10", size = 16683, upload-time = "2026-06-16T07:28:55.184Z" }, -] - -[[package]] -name = "hammocking" -version = "1.0.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jinja2" }, - { name = "libclang" }, - { name = "py-app-dev" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fd/0e/b0c0ee876af8ad404c3c1e277d24da9bc9c82e747a93ea31283afe8a5825/hammocking-1.0.2.tar.gz", hash = "sha256:309a3fff0a1c4461390128c82abe7881599f018ba6be828b1cbc51860fe60f47", size = 406743, upload-time = "2026-04-28T20:55:58.345Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/96/86/70140c041f2e4210054e81bf26afca6dffe4527f8a7d915aa5da1769bf62/hammocking-1.0.2-py3-none-any.whl", hash = "sha256:7fa0124b268b8941794a83427a0aa9d3001c75a9f3b458ab03316d07febec7a9", size = 12563, upload-time = "2026-04-28T20:55:57.319Z" }, -] - -[[package]] -name = "idna" -version = "3.20" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f5/08/8eea9d4b8302028f3abb2c0813953f7aec26d33b7a8960ed760e65ff29fa/idna-3.20.tar.gz", hash = "sha256:a7db850025b95ded1eae8a46181a1a6c56c92c96f0e2b005d9ff8dc0210cab44", size = 216463, upload-time = "2026-09-17T14:11:04.752Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl", hash = "sha256:ab7ae7122974553370f0bdb919e1a960b2cd1bc1ef0276416d896db81c14582c", size = 69583, upload-time = "2026-09-17T14:11:03.168Z" }, -] - -[[package]] -name = "ignore-python" -version = "0.4.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7b/79/39bfb3743a176742c9075be3b7b12b4ec7100bb4cae13448b1839fb0d9df/ignore_python-0.4.1.tar.gz", hash = "sha256:dbd8a009d554b86c600f7b5cb180a126813ebf485c08d7ae05bcf9754fc25073", size = 12234, upload-time = "2026-07-01T11:59:59.307Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/96/0e/6f4e47c3c730066dc1ddd4d25eda3896d5e24ce51819693db3de87a30496/ignore_python-0.4.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7fa78c104e2cf751ca00491f6b8108153d40e07ea6731a5d0039ddbaf8a7ebb", size = 886147, upload-time = "2026-07-01T11:58:15.993Z" }, - { url = "https://files.pythonhosted.org/packages/1e/2d/6f552951f000cd10773b754042b16c5d8550022d5648234edcf80d3a0326/ignore_python-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:88381ad01c24506933cb8d5cdf94417435f20cdf078ffca5bd06b1325c7fe5cb", size = 840284, upload-time = "2026-07-01T11:58:17.219Z" }, - { url = "https://files.pythonhosted.org/packages/e3/0b/d9a27ace2a7cbcc652c8431488933a1e9e54a6704ca536f4cb73436af840/ignore_python-0.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e87d887140602de486130da3f6deee5b03b82302488a92e388dda1f29bfeb30", size = 924643, upload-time = "2026-07-01T11:58:18.298Z" }, - { url = "https://files.pythonhosted.org/packages/3d/55/6d70979897a10e8b453a559cd3a3a1d170e475f20231f183fc945f13da71/ignore_python-0.4.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fe1511740bed936c5a82ceb7a570d6ebb4291dd13b37f8607a0e4072f72bd3e4", size = 894406, upload-time = "2026-07-01T11:58:19.589Z" }, - { url = "https://files.pythonhosted.org/packages/b3/1d/111e67c9be54c9fda510643dfe840cbd4e8e82c8c4677c8c37fb51c86e01/ignore_python-0.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:96f3caf5db26f44fec5ce20d837f6e9bd391f5dd8559e8e08fe9d45d74927cde", size = 1177927, upload-time = "2026-07-01T11:58:20.873Z" }, - { url = "https://files.pythonhosted.org/packages/a1/1d/1ec7398522d437dcf5808f3d0c170100dbaff2cfb89886a2d837b87dd4f3/ignore_python-0.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7cf900d9e3ef608eee780a5146846bf9cac4ecfcdfb2a99ae59b2c08baf25c59", size = 953287, upload-time = "2026-07-01T11:58:22.158Z" }, - { url = "https://files.pythonhosted.org/packages/30/5f/ccf9faa05129b10571528867a565cf42cbc2dd58387bed5c297c8dff017f/ignore_python-0.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3718a8a2c17c7953812c473e035b97c697cd2fbd3c1d165450c37fe31f946d91", size = 966483, upload-time = "2026-07-01T11:58:23.508Z" }, - { url = "https://files.pythonhosted.org/packages/ca/f0/6fa4ce058b27017455ac6d2efb8e29bc729041b900af0ad4684f80453a23/ignore_python-0.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:90f7e52145073cf6d8a658e4e259345743a1483d078fc4b09431b9df336635e8", size = 1004278, upload-time = "2026-07-01T11:58:24.633Z" }, - { url = "https://files.pythonhosted.org/packages/46/ce/5fea86be6ebf40c4783974ddf942ffa3bdec390d7ae666d93ddfe151dc23/ignore_python-0.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0a62eb1130a62333e7d0e2d97fe7107004c6e1495cc934e1c57f979640204ce0", size = 1102070, upload-time = "2026-07-01T11:58:25.85Z" }, - { url = "https://files.pythonhosted.org/packages/e5/99/06c6c35902b15e1040bce8c0bc1804a08a1eef583b4acd84380e22ce011b/ignore_python-0.4.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:4dd65cec2aed8883fd8e82d522f00bf177e30412770b3ddac7599182b02c3f4c", size = 1167818, upload-time = "2026-07-01T11:58:27.008Z" }, - { url = "https://files.pythonhosted.org/packages/df/05/f5ad9dc01f18a879a6f47bbae05a40558c2ebf009a65733edeafc55318fc/ignore_python-0.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9dbbb14d4ec825f4279dc499bc6793884e0bc2dc29086a1bda6335bdc438835f", size = 1179445, upload-time = "2026-07-01T11:58:28.29Z" }, - { url = "https://files.pythonhosted.org/packages/ee/61/67e45639e141443830d7dfe8bfac014ba0ad215e04ece6540aa8c1cbeaa9/ignore_python-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:68a0c6754f237e5618a76343d236deee3372f9bc593842d1228a13fb870b1408", size = 1176735, upload-time = "2026-07-01T11:58:29.839Z" }, - { url = "https://files.pythonhosted.org/packages/1d/48/2fa7ebd1e52818379d6686d6242263c8ee3c0210d357c61c4de4a8efeab0/ignore_python-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:c174dc85629eabeed5b2a2a05d6480f70cb6c366e520ba6d1bbe7f540473408f", size = 749842, upload-time = "2026-07-01T11:58:31.047Z" }, - { url = "https://files.pythonhosted.org/packages/eb/51/6b2241f3f07aed3497e8f733c40dd5435fa58c6b0a860fd71bfd37d5bd8f/ignore_python-0.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:1dafbf90809a5ecd18851a0bd115cb5823d14df9bd84839a8bb14aa83db59721", size = 689895, upload-time = "2026-07-01T11:58:32.25Z" }, - { url = "https://files.pythonhosted.org/packages/ce/02/f351359f18ee87f770cb7126056baa3fe825d58563e2f3c0c0f46f97a442/ignore_python-0.4.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:fe7a1d6774a48df4e63761217fb14f83f7ee664dfd5aa7c43c68e52478fa47e8", size = 885345, upload-time = "2026-07-01T11:58:33.295Z" }, - { url = "https://files.pythonhosted.org/packages/64/44/9433f5dfafa68f98e6f24a2f5b3765d5d3fa0270ab3b1ba21530d49be14f/ignore_python-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dbb867ecec784c3cc3491c8c42e55f1a4dcb4016e3855179a5125e1ec206dba5", size = 839369, upload-time = "2026-07-01T11:58:34.42Z" }, - { url = "https://files.pythonhosted.org/packages/ba/2e/bfa075c5b065a44a39c1e890ecb4031e97e73711129e23087ee58f32418f/ignore_python-0.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0dce0d63c67f33bbd0c2fd86db24607c1c92c24329b637b0ad0ecacd0e1c5f3a", size = 924307, upload-time = "2026-07-01T11:58:35.556Z" }, - { url = "https://files.pythonhosted.org/packages/13/f6/78505e82c84aee247f0fe53ceef3ccbe7de57b9826d307c80465dd357312/ignore_python-0.4.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:64093ddd989a262e0d8175ce6d62ac25bb578009d39db8f09b485ea4dbb298f3", size = 894260, upload-time = "2026-07-01T11:58:36.702Z" }, - { url = "https://files.pythonhosted.org/packages/bb/c3/89383366e9050b5030b30b860f2de190d092c390ba244d46a61252044963/ignore_python-0.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:88eb3af05b964ef8d5741a0c2fac3528734a9bcce6f63b8abb4a7121abfa1041", size = 1177366, upload-time = "2026-07-01T11:58:37.912Z" }, - { url = "https://files.pythonhosted.org/packages/25/33/df3b3146da1f9f4e36e4bea9e47cc51771b34b6676344c90876c2316a734/ignore_python-0.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:064092cf100d573543cd4f5c03abb69476a0bf2987a1f6ba756c8d524e86898a", size = 953720, upload-time = "2026-07-01T11:58:39.104Z" }, - { url = "https://files.pythonhosted.org/packages/9d/63/2b6cc85a92820926cdab55452f758bac2b60d6c2c15d1f122297950eae67/ignore_python-0.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19b6cbede28ba33116b3c88695375c40a5ebf658ad4afe28a1d54727edf44161", size = 965884, upload-time = "2026-07-01T11:58:40.347Z" }, - { url = "https://files.pythonhosted.org/packages/98/de/b0e11d32d74802f02377c6980b18b9d64498e36dc26d55304fd8e0387a7a/ignore_python-0.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:76068ce9bc1b53e9cdaf18eaf73a5f658accf326217f748ffdcb4723284fa7e8", size = 1003545, upload-time = "2026-07-01T11:58:41.544Z" }, - { url = "https://files.pythonhosted.org/packages/20/32/c2826b3c34c15b1324a303e1ba0b6fe5bfcac1e3f0a9f471df7728c724e1/ignore_python-0.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0891e2ac657b51a19fcedebe04c5dc0a432abd4650184086c7a88ce1e824b2f1", size = 1101743, upload-time = "2026-07-01T11:58:42.704Z" }, - { url = "https://files.pythonhosted.org/packages/40/8d/c4aa2bc153497ce125f7966f79a8637f00809b44f9a185d9538f5b69c1bf/ignore_python-0.4.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a303ebb4a89d58239e232076eee586e0b9020139044ba776066433d5fbafb925", size = 1167333, upload-time = "2026-07-01T11:58:44.412Z" }, - { url = "https://files.pythonhosted.org/packages/fc/70/022b0163e0e3f2fa596efa3fb245a43b1973a8de7a4ed3f97cccbf0f35df/ignore_python-0.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4fe4684917607a29b15f476b8623f19b31c3a831c17e15d20c4d02800e6527b2", size = 1178935, upload-time = "2026-07-01T11:58:45.783Z" }, - { url = "https://files.pythonhosted.org/packages/34/07/25484608155c064046da3b1411aab56c0d8983036e41ab6e39dc97a4a589/ignore_python-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:58987f4ae122212ac4e0971812c9293138d1326c609f1d94a691aff69f0b4137", size = 1175839, upload-time = "2026-07-01T11:58:47.028Z" }, - { url = "https://files.pythonhosted.org/packages/cf/64/2c075a6a0141bbce26dfc8b913e9bba5da7a428472cc395411391dbd16c3/ignore_python-0.4.1-cp313-cp313-win32.whl", hash = "sha256:0d42e50dd0ccefa515c42704d7fb5571b4ccebe91d33eba6261fad4b99b480d9", size = 657403, upload-time = "2026-07-01T11:58:48.403Z" }, - { url = "https://files.pythonhosted.org/packages/15/d6/21edb0a8145de5d371b8fa80aaea32d6d3bfc4e96e9de261288f9ac2d5af/ignore_python-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:a5487ddfccf518973e18ee2f43cd2b52505c55eb3e9fefc056774a10e30376cb", size = 749016, upload-time = "2026-07-01T11:58:49.515Z" }, - { url = "https://files.pythonhosted.org/packages/7b/a4/84e8e55c99fa0d9c924b09b0c0e1d20ef0d8edfc7562262195a1e78ac731/ignore_python-0.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:aee1c6043cd1b8d00983c7dec209d668eb1f0cc702d7eda886581b90cd5c274a", size = 689126, upload-time = "2026-07-01T11:58:50.606Z" }, -] - -[[package]] -name = "imagesize" -version = "2.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fb/5e/513ff06670c84e7b9887c1fdf61b2d42b4f574a831f2f1d2222023049d8a/imagesize-2.0.1.tar.gz", hash = "sha256:b2ba6a4dea487a7ebcd53248d3476aca449d30db12a2dde5e0c5ca9624fd77e5", size = 1883774, upload-time = "2026-08-24T12:35:19.13Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/01/f9/575c8d760eae1fc99651b7cc5efd96ad5379ca4d6b53750b0fb4fe983f34/imagesize-2.0.1-py3-none-any.whl", hash = "sha256:ea0c9a0384df69ed86a943a15cde37d0360b82491b3910dc2215e202e62b5b02", size = 14794, upload-time = "2026-08-24T12:35:12.548Z" }, -] - -[[package]] -name = "importlib-resources" -version = "6.5.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cf/8c/f834fbf984f691b4f7ff60f50b514cc3de5cc08abfc3295564dd89c5e2e7/importlib_resources-6.5.2.tar.gz", hash = "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c", size = 44693, upload-time = "2025-01-03T18:51:56.698Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/ed/1f1afb2e9e7f38a545d628f864d562a5ae64fe6f7a10e28ffb9b185b4e89/importlib_resources-6.5.2-py3-none-any.whl", hash = "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec", size = 37461, upload-time = "2025-01-03T18:51:54.306Z" }, -] - -[[package]] -name = "inflate64" -version = "1.0.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3e/f3/41bb2901543abe7aad0b0b0284ae5854bb75f848cf406bf8a046bf525f67/inflate64-1.0.4.tar.gz", hash = "sha256:b398c686960c029777afc0ed281a86f66adb956cfc3fbf6667cc6453f7b407ce", size = 902542, upload-time = "2025-11-28T10:55:52.641Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/33/5cfa7468960de1be0833e7e41adf5b7804a0aef2fb46f3679df3876bf3ab/inflate64-1.0.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:c8009e4a4918ee6c8cbc49e58fe159464895064cfdf0565fed3f49ca81e45272", size = 58619, upload-time = "2025-11-28T10:54:48.315Z" }, - { url = "https://files.pythonhosted.org/packages/cd/0a/583c7c2832da36e986c5758d0afb6f5944599e55c5b798b066a9ef63e581/inflate64-1.0.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0d173a7a0e865bb7d19685c5b1ad2994712b8361b24136d7e94abeff58505647", size = 35865, upload-time = "2025-11-28T10:54:49.389Z" }, - { url = "https://files.pythonhosted.org/packages/72/4b/9c6acfbe900e5c8698132244c68036b0455bd2169f46e356c83dc0366f11/inflate64-1.0.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8bad992f2d034f5f7e36208e54502d1b0829ce772c898e5dc59109833420148a", size = 36019, upload-time = "2025-11-28T10:54:50.813Z" }, - { url = "https://files.pythonhosted.org/packages/7f/66/c0c3d3b4b863aab2c2ce631d219a8eb3b95b78acd5f40d3212f071e693db/inflate64-1.0.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6bfcf806912ced77a21394f7363805ecacd626b79f93cba87d505a48e88ede78", size = 98765, upload-time = "2025-11-28T10:54:52.273Z" }, - { url = "https://files.pythonhosted.org/packages/37/00/1a2351a85d36b26c5b2b8cfbb37ad86084c98f592dd7590f8577d8b33993/inflate64-1.0.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62d1aac3aba094ae42e27ce7581b414c90f218248be0953b6aeb11a127225e5d", size = 100594, upload-time = "2025-11-28T10:54:53.684Z" }, - { url = "https://files.pythonhosted.org/packages/f7/3e/5d18ff5b86aaaf54117e1bb6ce15cb17163f56035f9c480e609d35f258ab/inflate64-1.0.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8065166f355122484f004225b379d403346bdae69ec624786a9334f025580675", size = 96745, upload-time = "2025-11-28T10:54:55.277Z" }, - { url = "https://files.pythonhosted.org/packages/84/ff/306d5d6aca1e04e596d2a504a59ff9a900623a6ec852f38aab99f384562d/inflate64-1.0.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:94a95f32087d223d2e119ff5c7c264109e8d4cb7e421e7a688a899a6fe021b38", size = 99795, upload-time = "2025-11-28T10:54:56.485Z" }, - { url = "https://files.pythonhosted.org/packages/cf/ec/d4caa4bf3c9e520c15e900fee5a00fc523953843e14aa378ca1abfb2b4ea/inflate64-1.0.4-cp312-cp312-win32.whl", hash = "sha256:ad4fa490bb7dc2a4640a3adaa2d5950f4a465ba034bbcf184c2103646e58ad97", size = 32956, upload-time = "2025-11-28T10:54:57.642Z" }, - { url = "https://files.pythonhosted.org/packages/33/c4/c0de4e9bdf12e449360b710e9ab5b5248804610f382b538773cbd07b72bb/inflate64-1.0.4-cp312-cp312-win_amd64.whl", hash = "sha256:2c6befdf83d088a6e0d10d0873a9d4bfde2ce00ad7a52c8189cf303306f98030", size = 35577, upload-time = "2025-11-28T10:54:59.14Z" }, - { url = "https://files.pythonhosted.org/packages/80/07/03a5ef74ad3869b3c5af3b09216321f5a1a5a45265f7bd6d5abc669c7622/inflate64-1.0.4-cp312-cp312-win_arm64.whl", hash = "sha256:2b263c619469f90a75f29c421c53d31b208ad494a078235a8f6db2bc96583fdc", size = 33465, upload-time = "2025-11-28T10:55:00.568Z" }, - { url = "https://files.pythonhosted.org/packages/c2/55/b7de7ae318a4f233f892c4f7c8b7e0e8643abe3fdcc53ed35020a9fe3f47/inflate64-1.0.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c3f37540d0e64884a935fd62a7d17e40ab69f05ec63e815483b6513675d01bef", size = 58633, upload-time = "2025-11-28T10:55:01.931Z" }, - { url = "https://files.pythonhosted.org/packages/b8/5f/6f89c8524503fd7a9ca2bd91fe60d7291b3f684e9d41edb38ef49e10fc3d/inflate64-1.0.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4d24112180c95d12f279cade9a1e21f8be7f4790c4109c293292edf87d061992", size = 35864, upload-time = "2025-11-28T10:55:03.075Z" }, - { url = "https://files.pythonhosted.org/packages/7d/14/9eadd59244b38cf85ccd0ca43d1296c50b3a33aa37be4fb68a1928efa58c/inflate64-1.0.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5c098dab17821f466fc6e6a3d78fc6e0295bb51458015f03416b1d58d6a8df4f", size = 36019, upload-time = "2025-11-28T10:55:04.126Z" }, - { url = "https://files.pythonhosted.org/packages/ca/04/399e82d8f5003dd92c8a0c5c1a9a8ce0919114710a496cbe88848bff3a72/inflate64-1.0.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a984b9287ff0fb596eb058d66a9e94530556afd2b7c054b44f2e0aeeff894e8f", size = 98973, upload-time = "2025-11-28T10:55:05.229Z" }, - { url = "https://files.pythonhosted.org/packages/c0/c5/038dc2593bbc4272d87eac8c9f75692267d47f834ced888f6d81995df606/inflate64-1.0.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f62a13d0327631778fa2a47c308ae2b07b2659b7bb8564783259ac65949f8c0c", size = 100777, upload-time = "2025-11-28T10:55:06.41Z" }, - { url = "https://files.pythonhosted.org/packages/74/4a/f6d3031dd3578510894a41bfe1ac149228970ce1629a43f20e0c5abbe8d1/inflate64-1.0.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:513201336fb3b0b7e2aee5dbbbe30a9f1b23291738b5ceb80076fc285f2ec2f1", size = 96967, upload-time = "2025-11-28T10:55:07.594Z" }, - { url = "https://files.pythonhosted.org/packages/26/ef/7ab3bde4e176609ae0e607a8a9bb38d201885275664a6d574299f5bf7850/inflate64-1.0.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:84ce3a97272ba745fce52b38363855c7201968f6402a794bbade774e64c657b9", size = 99997, upload-time = "2025-11-28T10:55:08.85Z" }, - { url = "https://files.pythonhosted.org/packages/39/59/8256b3e802e203c8645e0b32b25e6bd94508ad572593f0cdf8234db3879a/inflate64-1.0.4-cp313-cp313-win32.whl", hash = "sha256:332051a9d7e50579b90a3f555d68f53414b06f636c9ffe82e97c0baae3c8fbcc", size = 32958, upload-time = "2025-11-28T10:55:10.343Z" }, - { url = "https://files.pythonhosted.org/packages/e7/4f/5784ee1eb8260f2310e24ef2883f1f494f9332bcfde4ed14ee780372149e/inflate64-1.0.4-cp313-cp313-win_amd64.whl", hash = "sha256:3983f53b590ff7d0ba243f664ce852aca882482f30f7a8eab33e10d769336d0c", size = 35578, upload-time = "2025-11-28T10:55:11.389Z" }, - { url = "https://files.pythonhosted.org/packages/39/e8/8d927770ce25dc9764c8104207a80653d65471d0a6a8f9ead350016e4586/inflate64-1.0.4-cp313-cp313-win_arm64.whl", hash = "sha256:118d8286f085e99a14341c76ef9fbffd56619ccc80318a9a204aea3dbfa71470", size = 33465, upload-time = "2025-11-28T10:55:12.824Z" }, -] - -[[package]] -name = "iniconfig" -version = "2.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, -] - -[[package]] -name = "jinja2" -version = "3.1.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, -] - -[[package]] -name = "jsonschema" -version = "4.26.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "attrs" }, - { name = "jsonschema-specifications" }, - { name = "referencing" }, - { name = "rpds-py" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583, upload-time = "2026-01-07T13:41:07.246Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce", size = 90630, upload-time = "2026-01-07T13:41:05.306Z" }, -] - -[[package]] -name = "jsonschema-rs" -version = "0.52.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e6/48/771a96c524eafadcd2366271c13bd6e5b79af9032821f11e22846d36da3f/jsonschema_rs-0.52.1.tar.gz", hash = "sha256:25ec1da52bc1c11c012e17a01b97e24d33a15d1d76c705fd5a7c276d1bbe7677", size = 2631333, upload-time = "2026-08-30T09:52:05.865Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/13/37/92f23a0e53b6448faaae98ea4896f549c104cea8c07b8d213a22b2fb84dd/jsonschema_rs-0.52.1-cp310-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:cf728999f2cf4fb4fba8abf8d5a110565f716f4a460f13157de59e836c03706d", size = 10119218, upload-time = "2026-08-30T09:51:25.959Z" }, - { url = "https://files.pythonhosted.org/packages/71/3e/52261a693a148d8746db1ff67591e9e9f4b56b155be3d48840f7e5cbab58/jsonschema_rs-0.52.1-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:d32934b6a3032e968e59bb172addb8e752d7fdbff742834390f87549889c86db", size = 5277560, upload-time = "2026-08-30T09:51:28.055Z" }, - { url = "https://files.pythonhosted.org/packages/82/07/94db20d60141955d1987b73bcae8fdd3db6cfdf7ef4ad68fb9b399cd436d/jsonschema_rs-0.52.1-cp310-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5eb2562cca5effc43134c4f8d2ba0c2b04b97c7cfcb6ac27997f0a5b2aab662f", size = 5179470, upload-time = "2026-08-30T09:51:29.328Z" }, - { url = "https://files.pythonhosted.org/packages/5f/5d/cd7ab77544d6a8fad152c0ec1c332de1506da1c753475357fbfbf5ed91a2/jsonschema_rs-0.52.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:150845b65c701d5db2a397c97beb98356123548b29c70095ec9a851a611cc736", size = 5418427, upload-time = "2026-08-30T09:51:30.682Z" }, - { url = "https://files.pythonhosted.org/packages/ac/30/8b3d95e7be67daa93996a1444ca2238bdfcb58debf8bccf6469b5f183dc8/jsonschema_rs-0.52.1-cp310-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:895e7ec4c6e7ff564786f86e197c95d15017a42177523319bd45ede20e4c4417", size = 4999697, upload-time = "2026-08-30T09:51:31.998Z" }, - { url = "https://files.pythonhosted.org/packages/c7/24/001bb2ee8ca4ba19a7e31daad391de8e10f554a4f8c8396f83775eb585fa/jsonschema_rs-0.52.1-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4b05b745f05859ca8b2d056e22a3fae036e922a61805680cbe77cac31141be2e", size = 5185040, upload-time = "2026-08-30T09:51:33.943Z" }, - { url = "https://files.pythonhosted.org/packages/f8/84/50cd77eb2d1763625e8b394d5da6ffebcb148f71f4350b7bf3872ba25996/jsonschema_rs-0.52.1-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f709d4666f7fc728829503ff653c8a578634ab1ed54e9f11097da89dd18baf75", size = 5658962, upload-time = "2026-08-30T09:51:35.305Z" }, - { url = "https://files.pythonhosted.org/packages/02/5d/a588c8fc4d3f9fc06e222d35003c9c60a28bbcc492c49f273e19fa205ef8/jsonschema_rs-0.52.1-cp310-abi3-win32.whl", hash = "sha256:9131e083499ea49157e559dff813215f3ed116ed3a2996b108fed2faf1b80c0a", size = 4613745, upload-time = "2026-08-30T09:51:36.776Z" }, - { url = "https://files.pythonhosted.org/packages/1d/64/6b08a726984c8a3eb648cc516efa5bf20d218f6c26b912ffc126746c8147/jsonschema_rs-0.52.1-cp310-abi3-win_amd64.whl", hash = "sha256:3c9152a9aaec6a656b89fa203ccc26de54065e26cf6785378d54b6390ad403f2", size = 5340066, upload-time = "2026-08-30T09:51:38.183Z" }, -] - -[[package]] -name = "jsonschema-specifications" -version = "2025.9.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "referencing" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, -] - -[[package]] -name = "junitparser" -version = "5.0.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6c/c9/edeb58b0565b74ba0ffedf822d63aa40368bb4ff2da49751768eea696f5a/junitparser-5.0.3.tar.gz", hash = "sha256:f824ec1b7afbf2fd3b6813b87967b02fcda750e135d27be17cae497147419a04", size = 12120, upload-time = "2026-09-01T06:13:00.32Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/36/dbb6f74621890e5daa831c5f474b81e8b773298adf5ea835c03215a9359c/junitparser-5.0.3-py3-none-any.whl", hash = "sha256:553535b8cd1672a9c8bd2c7326ae1ae69279267fbc562106b5aa44d3c5f769af", size = 15000, upload-time = "2026-09-01T06:12:58.01Z" }, -] - -[[package]] -name = "kconfiglib" -version = "14.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/59/29/d557718c84ef1a8f275faa4caf8e353778121beefbe9fadfa0055ca99aae/kconfiglib-14.1.0.tar.gz", hash = "sha256:bed2cc2216f538eca4255a83a4588d8823563cdd50114f86cf1a2674e602c93c", size = 162613, upload-time = "2020-01-31T06:40:50.563Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/f1/d98a89231e779b079b977590efcc31249d959c8f1d4b5858cad69695ff9c/kconfiglib-14.1.0-py2.py3-none-any.whl", hash = "sha256:edcd35a20e7e138a9a9e96149027f805f785e818d2eae400b6fa8b0c8845114a", size = 145875, upload-time = "2020-01-31T06:40:47.252Z" }, -] - -[[package]] -name = "kiwisolver" -version = "1.5.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ba/07/bd78e6a8fae171ea041ef5bba3ed21a003522fa088834b069b1909981f30/kiwisolver-1.5.1.tar.gz", hash = "sha256:f1303ef2eec81262a4b708c3e858afe58d7c75ad91c1c05266eda7673369859a", size = 104395, upload-time = "2026-08-28T10:28:27.153Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/9b/65b302742389c6f96f2956bef5decf26011309feb2fc5d79613af18adea4/kiwisolver-1.5.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:63fb7294b768f444eb4b068965f2662f28c2fd4161e23bd60fcf3ff27b74c046", size = 123876, upload-time = "2026-08-28T10:25:27.44Z" }, - { url = "https://files.pythonhosted.org/packages/71/74/c21f339956f6f691b2ed7e31d5f3ae767304df6c460192739fc830853051/kiwisolver-1.5.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0ebdef3eae5336568147c39a55be6a2036ffde53faa9ca2d978989ae7c2da12c", size = 66487, upload-time = "2026-08-28T10:25:28.728Z" }, - { url = "https://files.pythonhosted.org/packages/84/e5/bdb34e21523e01dceda064d63713f3bdec91388af24fba1eca7ea5e85864/kiwisolver-1.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1798e83840c3f627246104c4d8a9639c60fa068adf9ce92b61791781fa8a68c1", size = 64660, upload-time = "2026-08-28T10:25:30.071Z" }, - { url = "https://files.pythonhosted.org/packages/fc/f4/dadfec469313c7f428efa7e84b4aba9732f813c13ea7131a24b7b008ef57/kiwisolver-1.5.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:34633ecf50d16187ab8e5528b7a2530f2feb4e23f300db4672538b51cfc5cd38", size = 1477929, upload-time = "2026-08-28T10:25:31.495Z" }, - { url = "https://files.pythonhosted.org/packages/6f/35/09c58daac34e6f6ea5c6dee0094b422118e5a7c265586008a95fd135ac5f/kiwisolver-1.5.1-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d27c2123977cb9269c30a49ba45f03a4323017ef693e19db4ec9dbe1299a3002", size = 1278499, upload-time = "2026-08-28T10:25:33.375Z" }, - { url = "https://files.pythonhosted.org/packages/19/32/739765e24fbad29d13f83e546ea4abc215a78cea9d677ca09025b027724d/kiwisolver-1.5.1-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6a797a1cefc8b9c93170db580337e1fe3d011ad18b1299943231279406342048", size = 1296677, upload-time = "2026-08-28T10:25:35.059Z" }, - { url = "https://files.pythonhosted.org/packages/df/32/03304d1010e2cc45e5b3b52cef7e43fed3a2a5cd6c87a89b4a88e1d85b5d/kiwisolver-1.5.1-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2551cf9917af48ee7c4b29cc82320489508cf96fd26a51f6fc124de661cd44c7", size = 1346037, upload-time = "2026-08-28T10:25:36.705Z" }, - { url = "https://files.pythonhosted.org/packages/3e/57/4c49377bfd274450dd72ecaa13eaac32ea804a03363e4d1db0c5aa999ceb/kiwisolver-1.5.1-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:38f6e0deb4d0a4615efe0c4efc5990b06ae450ab50a0b321c0b078b6d238c083", size = 988248, upload-time = "2026-08-28T10:25:38.299Z" }, - { url = "https://files.pythonhosted.org/packages/cb/c3/38df144a08b6c5d75ca4504e5cc3141bb3bfef64c04f4ef48204f42711b6/kiwisolver-1.5.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bfd1de989b3330420e29de39352f5c049905c9e3ee67233a50d550e3d652c148", size = 2228722, upload-time = "2026-08-28T10:25:40.038Z" }, - { url = "https://files.pythonhosted.org/packages/e7/11/3221838a89cd64d9b386353e000cd8a296069a20fbe3584507fdfd5bebae/kiwisolver-1.5.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1209042a623ddfda5497e4066c7b77651dde8e1d3a9dd97599dc7e97f3b9b78c", size = 2325216, upload-time = "2026-08-28T10:25:41.699Z" }, - { url = "https://files.pythonhosted.org/packages/83/d4/075c219230697bb5db910d37262b9bacf880f92b4811a02ab81ed073a253/kiwisolver-1.5.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:26e8268480be5061d509e29669d59103c067a26377a56491630ece11762e3858", size = 1977689, upload-time = "2026-08-28T10:25:43.559Z" }, - { url = "https://files.pythonhosted.org/packages/bb/08/1d219c3c2dd960983d0d4da623d916e9de6385df2b0bab3d1af0e9b8fccc/kiwisolver-1.5.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:d79308fa689fac89cbcfbd4dbfc80b5f95c54c5a7fd4d194be221f9d33d026e6", size = 2491443, upload-time = "2026-08-28T10:25:45.242Z" }, - { url = "https://files.pythonhosted.org/packages/ba/d3/024208ec1079d273f1047468d1bdffbf38bb75b7b268090fd3a0301b9d9a/kiwisolver-1.5.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b03af77d77e50edba2030fd5f7c352ff209314b09030a3cba7c14edf9a09a444", size = 2295200, upload-time = "2026-08-28T10:25:46.984Z" }, - { url = "https://files.pythonhosted.org/packages/6e/7c/7b210498f9f92e1cd7855f260fa69ef056881087b199ee20c208f0e4189a/kiwisolver-1.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:06a6917674de9e0fe3f66f5430787f59a9f2ddb64af9b714eaec547e29ef5c19", size = 70748, upload-time = "2026-08-28T10:25:48.444Z" }, - { url = "https://files.pythonhosted.org/packages/94/61/ef0daa157c8bb23672f7423e0d14c39db1dc6ef8ed47e6bc54c9c1bef3bf/kiwisolver-1.5.1-cp312-cp312-win_arm64.whl", hash = "sha256:ad8b9671348d7c8716715652ae11f85ed0eb99e265a2df2ca490577d69860b2c", size = 68324, upload-time = "2026-08-28T10:25:49.81Z" }, - { url = "https://files.pythonhosted.org/packages/08/c1/88018321d976f53c421e379c43bc6993e70ce0c8a3ec5edc4bfe102257f6/kiwisolver-1.5.1-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:b6ae6a0328f0bc035741820fdeecdcd67bf4694eee03972e843663107122f450", size = 62272, upload-time = "2026-08-28T10:25:51.02Z" }, - { url = "https://files.pythonhosted.org/packages/85/d2/712bc17ea4f1d216034928069d612defbc6c95a471c55a7203a39faecb1a/kiwisolver-1.5.1-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:886fc26012f0e8b5f69d1cfe6d711f6b11f194621539bf8e6bb1c25c5dc82724", size = 64481, upload-time = "2026-08-28T10:25:52.22Z" }, - { url = "https://files.pythonhosted.org/packages/1b/e6/6c5380d676f43b6d918033962ea5e72360ca69e5a404154bc496b598ffdb/kiwisolver-1.5.1-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:aefe930d113798330e9462f7874542977869c0613cba3262e2de3a8d5dee8f3a", size = 66260, upload-time = "2026-08-28T10:25:53.387Z" }, - { url = "https://files.pythonhosted.org/packages/92/6a/7087f5822cc8bb272679641404b1966a42504dac9ee74e2b33840475a0aa/kiwisolver-1.5.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5ca5aebae78a0bc13c1943af4af615d4966c5b650b05d5aa83b50e427196fee", size = 123876, upload-time = "2026-08-28T10:25:54.644Z" }, - { url = "https://files.pythonhosted.org/packages/5c/4b/9f385087ca09ee5ab9c09c6832561a7d2f7c78d3e5661d511e669f70e439/kiwisolver-1.5.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1ed0f5e49d0ceff8b72190824d9e59c062fbbc02c231b853112c78474b3f5ec2", size = 66487, upload-time = "2026-08-28T10:25:55.899Z" }, - { url = "https://files.pythonhosted.org/packages/47/8b/40d33ffd2f378094ed462e9a9a0907e59d4de9845e65a59561272da350d4/kiwisolver-1.5.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:77a4c8187a5948d7f8795adb765a3c7b553d07d86d88e43038fc32fc1fb9a3f3", size = 64673, upload-time = "2026-08-28T10:25:57.048Z" }, - { url = "https://files.pythonhosted.org/packages/ab/43/86aacc027959108b4c66eeae8b73cedb057dfa6eb3a335d05ad65197081c/kiwisolver-1.5.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:74ad5c3dad54a4641b4c28cd15ded70899d04459c6c7aeacafea716be97cce6d", size = 1477992, upload-time = "2026-08-28T10:25:58.479Z" }, - { url = "https://files.pythonhosted.org/packages/ed/40/b1d0369048c79733a32c8abb0f2718532e6630641368e33a81384246e844/kiwisolver-1.5.1-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:21e46b23a2da695c364124817bc01d970effd5483147f8d66a6a7167e3f6b851", size = 1278821, upload-time = "2026-08-28T10:26:00.121Z" }, - { url = "https://files.pythonhosted.org/packages/61/a1/fa71c1792272ff9461432715ae60ffb7e11a4d7ac3bf68961b9cab6c60cf/kiwisolver-1.5.1-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:75d9b1cf8258462dbdc1eeda718c96ea7f079324c09067f6daabfcf37712b7fe", size = 1296805, upload-time = "2026-08-28T10:26:01.868Z" }, - { url = "https://files.pythonhosted.org/packages/a3/49/3f0bd94af8e06ecc47eb834b195a06f05d48711ceb2352c56d6835160f0e/kiwisolver-1.5.1-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8fca690b00c4c48f6c2a547b0160ed511357093a4e4c9b47e0fadf3128066d89", size = 1346109, upload-time = "2026-08-28T10:26:03.59Z" }, - { url = "https://files.pythonhosted.org/packages/a4/44/3afe6ef9cf06d61220953a8963e94eca978491be1d9547cb01d82a1efa08/kiwisolver-1.5.1-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:876bbfd276473d3daffe30e8c975df4ed9429967b41a6cb362dbb5155b6f13ad", size = 988252, upload-time = "2026-08-28T10:26:05.306Z" }, - { url = "https://files.pythonhosted.org/packages/e4/30/a12bd7a7285a211e1747c3eec77b8c614dbfcc1dad942f7611a1a6921ae5/kiwisolver-1.5.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f942903fde7363d1d879057ec5de01310efda2597161784d752fa9953a01a71a", size = 2228846, upload-time = "2026-08-28T10:26:07.312Z" }, - { url = "https://files.pythonhosted.org/packages/a1/6b/233e2958abf0dab7b18d07e52f286e02e519d7651bfbbe97af9347564109/kiwisolver-1.5.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c90d3022d8a94778939cda8638c6c8da8fa757b8958dad7ec868ce29c87681b8", size = 2325583, upload-time = "2026-08-28T10:26:09.093Z" }, - { url = "https://files.pythonhosted.org/packages/42/8e/7673060a27b01405b580058510adef34687069d229800239f5e44682d4d0/kiwisolver-1.5.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:8a34616dc2521cc8dc1d7d081734da63539f021ac0450ce950908340c6e7aa2f", size = 1978221, upload-time = "2026-08-28T10:26:11.127Z" }, - { url = "https://files.pythonhosted.org/packages/3f/7b/1b882fc1a8b4a0bb8084e7d1d85004116d08c92c0705d31f2928dec607f2/kiwisolver-1.5.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:8bf4df63592c2a66b4f8edc5df2544998c288aa02f96ce0acd880cd1de8c8127", size = 2491819, upload-time = "2026-08-28T10:26:13.348Z" }, - { url = "https://files.pythonhosted.org/packages/39/9c/426deb49e62c5f69464b64bbeca064d3b758a7506b8913d986ef34f4619c/kiwisolver-1.5.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d09037ca068d784ebc4aec290ef952ca27ac15dd9c0b5801a88c6e1096b83e6b", size = 2295520, upload-time = "2026-08-28T10:26:15.042Z" }, - { url = "https://files.pythonhosted.org/packages/f5/22/deabbb3ad6d918d74b7831b2d8ae7151b09d21c87974e5ee8a456f58c94c/kiwisolver-1.5.1-cp313-cp313-win_amd64.whl", hash = "sha256:dc23390afe9f4ef9ac3bcc72a03a56eebbde03f4c571a32cb38f859cff9a6524", size = 70758, upload-time = "2026-08-28T10:26:16.504Z" }, - { url = "https://files.pythonhosted.org/packages/b9/71/02fa5c2fd92068bb8952847e70ee6c5cb280e7febe11653d17812acc53dd/kiwisolver-1.5.1-cp313-cp313-win_arm64.whl", hash = "sha256:186884a58486651e3c217b6acea0a53eaa9498fdd472057c46f2f0fb5c25aad5", size = 68329, upload-time = "2026-08-28T10:26:17.658Z" }, - { url = "https://files.pythonhosted.org/packages/a9/c4/1407df7512a5b36cc79840e01710dc575733c461b13ab866cae77eaf87f3/kiwisolver-1.5.1-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:482676e5bd48d70ac99d9fc78863469845421e01184fa83f1f9366dc49f7e974", size = 134002, upload-time = "2026-08-28T10:28:08.881Z" }, - { url = "https://files.pythonhosted.org/packages/16/45/c37a21ad5c0ab581a93c55ad544721aaa1f0ae94edb29c6a678a23d013e6/kiwisolver-1.5.1-graalpy312-graalpy250_312_native-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:072bdb15a3c19a5b5dbc8f8fb1f4e1884bf4f3507eeb4cc6334401274d37a5c0", size = 194292, upload-time = "2026-08-28T10:28:11.06Z" }, - { url = "https://files.pythonhosted.org/packages/a6/c1/69f00d627949580e43d57af0aa465df46868d7c29801c137a55374101294/kiwisolver-1.5.1-graalpy312-graalpy250_312_native-win_amd64.whl", hash = "sha256:a5a00665d1a0e26763a7338d7e911d4598fbc1d50dd0d6b7919b7dc6c5d6569f", size = 73362, upload-time = "2026-08-28T10:28:12.449Z" }, -] - -[[package]] -name = "libclang" -version = "18.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6e/5c/ca35e19a4f142adffa27e3d652196b7362fa612243e2b916845d801454fc/libclang-18.1.1.tar.gz", hash = "sha256:a1214966d08d73d971287fc3ead8dfaf82eb07fb197680d8b3859dbbbbf78250", size = 39612, upload-time = "2024-03-17T16:04:37.434Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/49/f5e3e7e1419872b69f6f5e82ba56e33955a74bd537d8a1f5f1eff2f3668a/libclang-18.1.1-1-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:0b2e143f0fac830156feb56f9231ff8338c20aecfe72b4ffe96f19e5a1dbb69a", size = 25836045, upload-time = "2024-06-30T17:40:31.646Z" }, - { url = "https://files.pythonhosted.org/packages/e2/e5/fc61bbded91a8830ccce94c5294ecd6e88e496cc85f6704bf350c0634b70/libclang-18.1.1-py2.py3-none-macosx_10_9_x86_64.whl", hash = "sha256:6f14c3f194704e5d09769108f03185fce7acaf1d1ae4bbb2f30a72c2400cb7c5", size = 26502641, upload-time = "2024-03-18T15:52:26.722Z" }, - { url = "https://files.pythonhosted.org/packages/db/ed/1df62b44db2583375f6a8a5e2ca5432bbdc3edb477942b9b7c848c720055/libclang-18.1.1-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:83ce5045d101b669ac38e6da8e58765f12da2d3aafb3b9b98d88b286a60964d8", size = 26420207, upload-time = "2024-03-17T15:00:26.63Z" }, - { url = "https://files.pythonhosted.org/packages/1d/fc/716c1e62e512ef1c160e7984a73a5fc7df45166f2ff3f254e71c58076f7c/libclang-18.1.1-py2.py3-none-manylinux2010_x86_64.whl", hash = "sha256:c533091d8a3bbf7460a00cb6c1a71da93bffe148f172c7d03b1c31fbf8aa2a0b", size = 24515943, upload-time = "2024-03-17T16:03:45.942Z" }, - { url = "https://files.pythonhosted.org/packages/3c/3d/f0ac1150280d8d20d059608cf2d5ff61b7c3b7f7bcf9c0f425ab92df769a/libclang-18.1.1-py2.py3-none-manylinux2014_aarch64.whl", hash = "sha256:54dda940a4a0491a9d1532bf071ea3ef26e6dbaf03b5000ed94dd7174e8f9592", size = 23784972, upload-time = "2024-03-17T16:12:47.677Z" }, - { url = "https://files.pythonhosted.org/packages/fe/2f/d920822c2b1ce9326a4c78c0c2b4aa3fde610c7ee9f631b600acb5376c26/libclang-18.1.1-py2.py3-none-manylinux2014_armv7l.whl", hash = "sha256:cf4a99b05376513717ab5d82a0db832c56ccea4fd61a69dbb7bccf2dfb207dbe", size = 20259606, upload-time = "2024-03-17T16:17:42.437Z" }, - { url = "https://files.pythonhosted.org/packages/2d/c2/de1db8c6d413597076a4259cea409b83459b2db997c003578affdd32bf66/libclang-18.1.1-py2.py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:69f8eb8f65c279e765ffd28aaa7e9e364c776c17618af8bff22a8df58677ff4f", size = 24921494, upload-time = "2024-03-17T16:14:20.132Z" }, - { url = "https://files.pythonhosted.org/packages/0b/2d/3f480b1e1d31eb3d6de5e3ef641954e5c67430d5ac93b7fa7e07589576c7/libclang-18.1.1-py2.py3-none-win_amd64.whl", hash = "sha256:4dd2d3b82fab35e2bf9ca717d7b63ac990a3519c7e312f19fa8e86dcc712f7fb", size = 26415083, upload-time = "2024-03-17T16:42:21.703Z" }, - { url = "https://files.pythonhosted.org/packages/71/cf/e01dc4cc79779cd82d77888a88ae2fa424d93b445ad4f6c02bfc18335b70/libclang-18.1.1-py2.py3-none-win_arm64.whl", hash = "sha256:3f0e1f49f04d3cd198985fea0511576b0aee16f9ff0e0f0cad7f9c57ec3c20e8", size = 22361112, upload-time = "2024-03-17T16:42:59.565Z" }, -] - -[[package]] -name = "loguru" -version = "0.7.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "win32-setctime", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3a/05/a1dae3dffd1116099471c643b8924f5aa6524411dc6c63fdae648c4f1aca/loguru-0.7.3.tar.gz", hash = "sha256:19480589e77d47b8d85b2c827ad95d49bf31b0dcde16593892eb51dd18706eb6", size = 63559, upload-time = "2024-12-06T11:20:56.608Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl", hash = "sha256:31a33c10c8e1e10422bfd431aeb5d351c7cf7fa671e3c4df004162264b28220c", size = 61595, upload-time = "2024-12-06T11:20:54.538Z" }, -] - -[[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/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" }, -] - -[[package]] -name = "markdown-it-py" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mdurl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" }, -] - -[[package]] -name = "markupsafe" -version = "3.0.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, - { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, - { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, - { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, - { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, - { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, - { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, - { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, - { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, - { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, - { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, - { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, - { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, - { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, - { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, - { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, - { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, - { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, - { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, - { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, - { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, - { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, - { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, - { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, - { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, - { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, - { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, - { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, - { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, - { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, - { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, - { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, - { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, -] - -[[package]] -name = "mashumaro" -version = "3.22" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d1/e3/a06dcd2e6df094c5e294721926f1f76da30f50823e2ac233a9198e804891/mashumaro-3.22.tar.gz", hash = "sha256:64538cc365204402a060ebde683a86505b5a4344acf6870d79021e9fbfe57360", size = 197845, upload-time = "2026-05-26T14:39:21.859Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/1c/92fd926c2e7763535454683250dbdd8d10aa2f2c62f58d6abbcce4d8b3fc/mashumaro-3.22-py3-none-any.whl", hash = "sha256:17dc4d7294c33ef380a8b929dda0608577aa2141988c00a0c4932310108fe71d", size = 95916, upload-time = "2026-05-26T14:39:20.233Z" }, -] - -[[package]] -name = "matplotlib" -version = "3.11.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "contourpy" }, - { name = "cycler" }, - { name = "fonttools" }, - { name = "kiwisolver" }, - { name = "numpy" }, - { name = "packaging" }, - { name = "pillow" }, - { name = "pyparsing" }, - { name = "python-dateutil" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e7/c8/9aa712a0afb882649424dd8de8ad9aa6235e796e84c6052e8f6dc1598d0d/matplotlib-3.11.2.tar.gz", hash = "sha256:cec596316640f2b394b8f0daa0ea61a8eae82d017b620b9f202befb972a59ea4", size = 32660610, upload-time = "2026-09-11T19:05:31.214Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/ce/1bfcc4873b121597791ad74032943b123218c0613af0b97e8dd05e916fb1/matplotlib-3.11.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ef752769cd962f39ea0b6ffc82d1ea43a0012c5a6157c7a075212fa509cfcff2", size = 9476466, upload-time = "2026-09-11T19:03:19.45Z" }, - { url = "https://files.pythonhosted.org/packages/a6/c4/7f5f3601ee69baf072c0c7d3ce60c03e0618621c5a56c34a62a460e29d11/matplotlib-3.11.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ef31985c4dedb5f1424e1aec6849a47dd37689cb7fa3c20b1b82187f26806261", size = 9305583, upload-time = "2026-09-11T19:03:22.39Z" }, - { url = "https://files.pythonhosted.org/packages/b8/90/2b3fd67ee273163faeda6d514be70b5596eaa0fd77b60ffc294ad0b34f5f/matplotlib-3.11.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:df4f7784aca81a94f254c0a2767d592ee25f407e488f5fa7203e51093fb6ca27", size = 9860353, upload-time = "2026-09-11T19:03:25.049Z" }, - { url = "https://files.pythonhosted.org/packages/f4/84/32549e7a462dc311aed2ab62e5d2538028840b5c53a8be0195c789937c3d/matplotlib-3.11.2-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b9a7ad579856284135e401ecc918c5f8a017ee30539298862a109f51b971710", size = 10670348, upload-time = "2026-09-11T19:03:28.108Z" }, - { url = "https://files.pythonhosted.org/packages/84/39/02e21b74f7439bd643d717ea846006d46e309e6d29b632b57751265311d6/matplotlib-3.11.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3aa4b8516fd26659e4363abbf317c703d9116496c5db2e9d0609a2866dd39dd2", size = 10810580, upload-time = "2026-09-11T19:03:31.402Z" }, - { url = "https://files.pythonhosted.org/packages/04/93/0d239bde12b308262265c2d98909b2f0ecad2b5deeae96241642e822e9c7/matplotlib-3.11.2-cp312-cp312-win_amd64.whl", hash = "sha256:c5c1c68ee401fc98271263410f0e5ce88285abacf7627132914e8adf3d70ff43", size = 9349409, upload-time = "2026-09-11T19:03:34.195Z" }, - { url = "https://files.pythonhosted.org/packages/49/a8/06baf901c02246c8a222b655cc4540ef9c15e1549a04e07927f9cde716c3/matplotlib-3.11.2-cp312-cp312-win_arm64.whl", hash = "sha256:643ff850d8e0f5b8319337f87ed3cb59506afb3df3cc48de777d85871233be7b", size = 9028084, upload-time = "2026-09-11T19:03:37.032Z" }, - { url = "https://files.pythonhosted.org/packages/bf/ce/fc58855a3d17f6cb8a87b6f9ccd100f65432a3a7ffed57309cbf14c78987/matplotlib-3.11.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7d43ff8cebb50840648cb6429b2228621dbd709010f3117b3740abb20abf21c0", size = 9476987, upload-time = "2026-09-11T19:03:40.17Z" }, - { url = "https://files.pythonhosted.org/packages/a9/29/2a47b700545aca050e0ed73c89ba21e08407e11f5f42a567421b220de6c1/matplotlib-3.11.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2a8285cea8ef4d92aa041d1c33788bcae82248503300f93f1ca2136b9049452f", size = 9306050, upload-time = "2026-09-11T19:03:43.103Z" }, - { url = "https://files.pythonhosted.org/packages/a9/df/e7c10292f348cf55178a5b3c0092a38ea68891a3945f199ae8b7b8ac9dc1/matplotlib-3.11.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1944895967f87c84c9b4bad29a707b31f5b36df4a3a2339ea1f8ea3ce5105539", size = 9861060, upload-time = "2026-09-11T19:03:46.044Z" }, - { url = "https://files.pythonhosted.org/packages/e4/b9/b978de6d43d47f1d4d8e653fac32c16d8d2e5f46bbbb822e26d7cb1adece/matplotlib-3.11.2-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:af2661f6ac6bbd1d081996f54fdd9385715c625ace8cec0869055c0cfbf38981", size = 10670885, upload-time = "2026-09-11T19:03:48.942Z" }, - { url = "https://files.pythonhosted.org/packages/a3/80/d72f61bb2631ac15d17fada1f17e0f99fecba69d8376d34f17cf93b7eddd/matplotlib-3.11.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7e5a90f8a707ebb6004a713b1cff091a40cc5df4c7c1cb165e5a505ebc11c292", size = 10811222, upload-time = "2026-09-11T19:03:51.665Z" }, - { url = "https://files.pythonhosted.org/packages/94/2e/6d1d33f242c705b5c6c6fb3f0fc141add51cb1abb62912e59de0835d28c4/matplotlib-3.11.2-cp313-cp313-win_amd64.whl", hash = "sha256:bc067c462a86f0e57bf52fc6e058d90171a5420007dac00c46e90153050c69a7", size = 9349539, upload-time = "2026-09-11T19:03:54.534Z" }, - { url = "https://files.pythonhosted.org/packages/bb/bb/c0aa86a7f4c0e62f1c3c0711e361f6f23f87eb9018732a5e11994bd1b7ec/matplotlib-3.11.2-cp313-cp313-win_arm64.whl", hash = "sha256:3e8576f7c47e02fd4f21f44171302d2d1d58d4471d46da3d71fe8899d19539d9", size = 9028295, upload-time = "2026-09-11T19:03:57.261Z" }, -] - -[[package]] -name = "mdit-py-plugins" -version = "0.6.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/59/fc/f8d0863f8862f25602c0404d75568e89fb6b4109804645e5cdfb1be5cf56/mdit_py_plugins-0.6.1.tar.gz", hash = "sha256:a2bca0f039f39dbd35fb74ae1b5f998608c437463371f0ff7f49a19a17a114d0", size = 56114, upload-time = "2026-05-13T09:03:38.91Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a5/69/6da5581c6a7fede7dc261bf4e67d6adca4196f176b43288b55b3db395b6e/mdit_py_plugins-0.6.1-py3-none-any.whl", hash = "sha256:214c82fb2ac524472ab6a5bcab1de80f73b50443e187f401bfd77efbc7c6481d", size = 66663, upload-time = "2026-05-13T09:03:37.76Z" }, -] - -[[package]] -name = "mdurl" -version = "0.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, -] - -[[package]] -name = "minijinja" -version = "2.24.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d0/18/2dbb84297175b77b5eb497e07e66e71c71b8073bdbe3d3cb1d3309823d66/minijinja-2.24.0.tar.gz", hash = "sha256:8e9dc11bd5c7a20869c42d6c7c0caa5cd437c62a00a042f65df20036f0def93c", size = 299288, upload-time = "2026-08-31T19:28:46.351Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/16/9170db3a85bf7fed14c5281e13927d310385e5fd945518dda80e2ec0a631/minijinja-2.24.0-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:f286106f9d2ffd73702a470cc4d9262b1588eb48916fc84b98d19df4e3064bd4", size = 2174596, upload-time = "2026-08-31T19:28:25.642Z" }, - { url = "https://files.pythonhosted.org/packages/82/ec/9a1e7513d7e18ff11907eb6ae92f060f2abd85e0df029625816b8f469eb4/minijinja-2.24.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9e252fa4c59cff1794dfffb5349da6a4885de97aaaf2fbc6983becc1eb973e9", size = 1140515, upload-time = "2026-08-31T19:28:27.648Z" }, - { url = "https://files.pythonhosted.org/packages/66/0c/835223a549b924b1bf9a7a2e6723783342a05896c90cf49a10bbef72a253/minijinja-2.24.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:94964dca64c80b2a85b598037ab07f01a794d238c66d5556d01c4f400b630fd0", size = 1115064, upload-time = "2026-08-31T19:28:29.634Z" }, - { url = "https://files.pythonhosted.org/packages/ad/ed/14056592c0008a0945e96966c5e2b215579d6f3487032d7ba2d8ad2e9c12/minijinja-2.24.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5a4dbd73f2c02ab6d0ab0b62b68a7d2557e5d45723d3b4e423b7c3877f31cad", size = 1178991, upload-time = "2026-08-31T19:28:31.538Z" }, - { url = "https://files.pythonhosted.org/packages/4b/6b/71ca5f679c03a67af5d551b32e306c6bb87aa7157767c3a7a678323d748f/minijinja-2.24.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43d633999cb06509ba3de9a0e5798f97d5ba5bc0d337f9d8f8ea02f349050cbd", size = 1312790, upload-time = "2026-08-31T19:28:33.473Z" }, - { url = "https://files.pythonhosted.org/packages/56/13/3c7c6f34c41eece458f4f416dbab229024502173de780ee978ef38a4c605/minijinja-2.24.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:90cc9e1196d98e56fdc87b69a5949bc76ecbbc512c7654081483c5acabf8ca8f", size = 1308284, upload-time = "2026-08-31T19:28:36.272Z" }, - { url = "https://files.pythonhosted.org/packages/2e/c9/bbcf76a1bd02a503c2d05f996d6271358c77bab68893689d3bd14514fdab/minijinja-2.24.0-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:194364c0a060606e96ae635cd997c7e014b4ef026d12c02fe9f8912749622481", size = 1381830, upload-time = "2026-08-31T19:28:37.994Z" }, - { url = "https://files.pythonhosted.org/packages/20/91/980d6b2572a0985ec033c1b93bb8eea6be87f920a7cab2097ef740894c61/minijinja-2.24.0-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:6c2106a399eaff009ebf308ccebed397787ff4442159de9598543298f3eee522", size = 1463332, upload-time = "2026-08-31T19:28:39.749Z" }, - { url = "https://files.pythonhosted.org/packages/92/98/75d6a76499fd40f839a0a1a8fc46aa43cf6c47ea9680d4174289fd6fec3a/minijinja-2.24.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5e0cdc27520d2163ec8a2078e4ff20c3afff4fb89eb05d21679c3facd30369ab", size = 1388664, upload-time = "2026-08-31T19:28:41.421Z" }, - { url = "https://files.pythonhosted.org/packages/7d/f1/e8d82609d7aad5791d52fdec4c642fab46974094cef9102110efa6fc2713/minijinja-2.24.0-cp38-abi3-win32.whl", hash = "sha256:b68aa1bd72da3a6175afa721090592f19e637b7a02408f796298d342b709d06b", size = 1058094, upload-time = "2026-08-31T19:28:43.157Z" }, - { url = "https://files.pythonhosted.org/packages/5b/e5/d86c8c706b3820fc6f58baa0f7d322e78885843ddba7e9cba77985a3fbc7/minijinja-2.24.0-cp38-abi3-win_amd64.whl", hash = "sha256:541959f4529017e437b8822cdaabaaab9d4090c140138dec40dbd739b3b0f778", size = 1118117, upload-time = "2026-08-31T19:28:44.843Z" }, -] - -[[package]] -name = "mlx-traceability" -version = "11.8.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "docutils" }, - { name = "matplotlib" }, - { name = "natsort" }, - { name = "python-decouple" }, - { name = "requests" }, - { name = "sphinx" }, - { name = "sphinxcontrib-jquery" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/cb/ea/110e5ef3b5656b1ebf7e74cee598e3270713a7e72db734b5a4d1f6b89c51/mlx_traceability-11.8.3.tar.gz", hash = "sha256:2ef56e6f2d4d1d32592f746b9d5bd194abe7610fd55ae55258d223bac108b5ab", size = 70594, upload-time = "2026-02-24T14:07:44.631Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/70/2dd58eefbfbeb578a33045aed7541bd15308f215925e9aecbe9b84a447a7/mlx_traceability-11.8.3-py3-none-any.whl", hash = "sha256:49507b2301e18b037037b7e893dc7a457cccf81e8fca656e482b6320933568e2", size = 81101, upload-time = "2026-02-24T14:07:43.359Z" }, -] - -[[package]] -name = "multivolumefile" -version = "0.2.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/50/f0/a7786212b5a4cb9ba05ae84a2bbd11d1d0279523aea0424b6d981d652a14/multivolumefile-0.2.3.tar.gz", hash = "sha256:a0648d0aafbc96e59198d5c17e9acad7eb531abea51035d08ce8060dcad709d6", size = 77984, upload-time = "2021-04-29T12:18:39.882Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/22/31/ec5f46fd4c83185b806aa9c736e228cb780f13990a9cf4da0beb70025fcc/multivolumefile-0.2.3-py3-none-any.whl", hash = "sha256:237f4353b60af1703087cf7725755a1f6fcaeeea48421e1896940cd1c920d678", size = 17037, upload-time = "2021-04-29T12:18:38.886Z" }, -] - -[[package]] -name = "myst-parser" -version = "4.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "docutils" }, - { name = "jinja2" }, - { name = "markdown-it-py" }, - { name = "mdit-py-plugins" }, - { name = "pyyaml" }, - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/66/a5/9626ba4f73555b3735ad86247a8077d4603aa8628537687c839ab08bfe44/myst_parser-4.0.1.tar.gz", hash = "sha256:5cfea715e4f3574138aecbf7d54132296bfd72bb614d31168f48c477a830a7c4", size = 93985, upload-time = "2025-02-12T10:53:03.833Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/df/76d0321c3797b54b60fef9ec3bd6f4cfd124b9e422182156a1dd418722cf/myst_parser-4.0.1-py3-none-any.whl", hash = "sha256:9134e88959ec3b5780aedf8a99680ea242869d012e8821db3126d427edc9c95d", size = 84579, upload-time = "2025-02-12T10:53:02.078Z" }, -] - -[[package]] -name = "natsort" -version = "8.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e2/a9/a0c57aee75f77794adaf35322f8b6404cbd0f89ad45c87197a937764b7d0/natsort-8.4.0.tar.gz", hash = "sha256:45312c4a0e5507593da193dedd04abb1469253b601ecaf63445ad80f0a1ea581", size = 76575, upload-time = "2023-06-20T04:17:19.925Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/82/7a9d0550484a62c6da82858ee9419f3dd1ccc9aa1c26a1e43da3ecd20b0d/natsort-8.4.0-py3-none-any.whl", hash = "sha256:4732914fb471f56b5cce04d7bae6f164a592c7712e1c85f9ef585e197299521c", size = 38268, upload-time = "2023-06-20T04:17:17.522Z" }, -] - -[[package]] -name = "numpy" -version = "2.4.6" -source = { registry = "https://pypi.org/simple" } -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/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" }, -] - -[[package]] -name = "object-deps-report" -version = "0.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "clanguru" }, - { name = "py-app-dev" }, - { name = "typer" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1f/de/cf9b2fc0a535aa3cacc3bd21bd5d93da96edd4f0211f34d201ad6236097d/object_deps_report-0.0.1.tar.gz", hash = "sha256:e97d349a385081503fd6254ed55c833e7f5677ecf923b5a53e0a69710a4c083e", size = 7457, upload-time = "2026-08-03T12:17:30.967Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a5/c6/fe5277fd033af3bd5d37c40a179703f440c0d33132aaf464fc5370d68c03/object_deps_report-0.0.1-py3-none-any.whl", hash = "sha256:45c559bd01432e54e8121c6eb227ab755e4b046af71e3ee8077ae3412f00bbe2", size = 9480, upload-time = "2026-08-03T12:17:29.871Z" }, -] - -[[package]] -name = "openpyxl" -version = "3.1.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "et-xmlfile" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3d/f9/88d94a75de065ea32619465d2f77b29a0469500e99012523b91cc4141cd1/openpyxl-3.1.5.tar.gz", hash = "sha256:cf0e3cf56142039133628b5acffe8ef0c12bc902d2aadd3e0fe5878dc08d1050", size = 186464, upload-time = "2024-06-28T14:03:44.161Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c0/da/977ded879c29cbd04de313843e76868e6e13408a94ed6b987245dc7c8506/openpyxl-3.1.5-py2.py3-none-any.whl", hash = "sha256:5282c12b107bffeef825f4617dc029afaf41d0ea60823bbb665ef3079dc79de2", size = 250910, upload-time = "2024-06-28T14:03:41.161Z" }, -] - -[[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 = "pillow" -version = "12.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1c/3d/bb7fca845737cf9d7dbde16ed1843984665ff2e0a518f5db43e77ec540b9/pillow-12.3.0.tar.gz", hash = "sha256:3b8182a766685eaa002637e28b4ec8d6b18819a0c71f579bf0dbaa5830297cce", size = 47025035, upload-time = "2026-07-01T11:56:38.965Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/37/bf/fb3ebff8ddcb76aac5a01389251bbbb9519922a9b520d8247c1ca864a25d/pillow-12.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ba09209fbe443b4acccebe845d8a138b89a8f4fbaeedd44953490b5315d5e965", size = 5345969, upload-time = "2026-07-01T11:54:06.397Z" }, - { url = "https://files.pythonhosted.org/packages/d8/66/9a386a92561f402389a4fc70c18838bf6d35eb5eb5c6850b4b2dc64f5048/pillow-12.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffd0c5368496f41b0944be820fcb7a838aa6e623d250b01acf2643939c3f99d7", size = 4780323, upload-time = "2026-07-01T11:54:09.351Z" }, - { url = "https://files.pythonhosted.org/packages/25/27/ac8f99618ffd3dde21db0f4d4b1d2ab00c0880595bfd17df103f7f39fd0c/pillow-12.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9c7f76c0673154f044e9d78c8655fb4213f6ca31a836df48b40fe5d187717b9", size = 6266838, upload-time = "2026-07-01T11:54:11.71Z" }, - { url = "https://files.pythonhosted.org/packages/84/21/a35af28dcc61f37ed850a2d64c65c701321dfbf25085e469d5559360cbbf/pillow-12.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:78cb2c6865a35ab8ff8b75fd122f6033b92a62c82801110e48ddd6c936a45d91", size = 6940830, upload-time = "2026-07-01T11:54:13.732Z" }, - { url = "https://files.pythonhosted.org/packages/eb/51/8b08617af3ad95e33ce6d7dd2c99ed6c8298f7fb131636303956be022e25/pillow-12.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e491916b378fba47242221bb9ead245211b70d504f495d105d17b14a24b4907c", size = 6344383, upload-time = "2026-07-01T11:54:15.756Z" }, - { url = "https://files.pythonhosted.org/packages/1d/72/cf78ac9780bb93c28328f408973845a309d4d145041665f734572ced1b52/pillow-12.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0dd2064cbc55aaec028ef5fbb60fa47bb6c3e7918e07ff17935284b227a9d2df", size = 7052934, upload-time = "2026-07-01T11:54:17.721Z" }, - { url = "https://files.pythonhosted.org/packages/20/20/25e0f4dc178a6bc0696793720055519a0de89e7661dae886992decbd2f81/pillow-12.3.0-cp312-cp312-win32.whl", hash = "sha256:dbce0b29841537a2fa4a214c2bbf14de3587c9680caa9b4e217568472490b28f", size = 6472684, upload-time = "2026-07-01T11:54:19.839Z" }, - { url = "https://files.pythonhosted.org/packages/45/89/da2f7971a317f83d807fdd4065c0af40208e59e692cc43d315a71a0e96d1/pillow-12.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a2b55dd6b2a4c4b7d87ffa56bdb33fdc5fdb9a462173861a7bc097f17d91cb09", size = 7227137, upload-time = "2026-07-01T11:54:22.025Z" }, - { url = "https://files.pythonhosted.org/packages/de/47/4845a0a6c0dbf1db8456bd9fc791f13c5ced7ced20606d08a0aacfd25b49/pillow-12.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:331b624368d4f1d069149002f25f44bc61c8919ce8ddb3c45bdad8f6e2d89510", size = 2568267, upload-time = "2026-07-01T11:54:24.051Z" }, - { url = "https://files.pythonhosted.org/packages/9d/ac/31fb64e1e7efb5a4b50cd3d92049ba89ac6e4d8d3bb6a74e15048ca3353e/pillow-12.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:21900ce7ba264168cd50defae43cd75d25c833ad4ad6e73ffc5596d12e25ac89", size = 4161684, upload-time = "2026-07-01T11:54:25.934Z" }, - { url = "https://files.pythonhosted.org/packages/87/b4/9805e23d2b4d77842b468513841fda254ee42f0289d25088340e4ff46e2d/pillow-12.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:4e8c2a84d977f50b9daed6eeaf3baef67d00d5d74d932288f02cb94518ee3ace", size = 4255487, upload-time = "2026-07-01T11:54:27.935Z" }, - { url = "https://files.pythonhosted.org/packages/df/39/ecf519435a200c693fe053a6ee4d835b41cf963a4dfc2551c4e637cb2a71/pillow-12.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:ae26d61dfa7a47befdc7572b521024e8745f3d809bd95ca9505a7bba9ef849ec", size = 3696433, upload-time = "2026-07-01T11:54:29.813Z" }, - { url = "https://files.pythonhosted.org/packages/42/92/2fc3ffad878ae8dd5469ec1bc8eb83b71f48e13efdf68f02709003982a32/pillow-12.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7a743ff716f746fc19a9557f60dab1600d4613255f8a7aeb3cdde4db7eb15a66", size = 5345889, upload-time = "2026-07-01T11:54:31.97Z" }, - { url = "https://files.pythonhosted.org/packages/10/76/8803c13605b763d33d156c4678fc77f8443389c0c51c8aef707bb02015f4/pillow-12.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d69141514cc30b774ceea5e3ed3a6635c8d8a96edf664689b890f4089111fb35", size = 4780109, upload-time = "2026-07-01T11:54:34.026Z" }, - { url = "https://files.pythonhosted.org/packages/1f/01/e18aff37cb0b4aac47ac90f016d347a49aca667ef97f190b06ac2aabc928/pillow-12.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f7401aebd7f581d7f83a439d87d474999317ee099218e5ad25d125290990ba65", size = 6263736, upload-time = "2026-07-01T11:54:36.131Z" }, - { url = "https://files.pythonhosted.org/packages/f7/62/de5bdd77d935331f4f802edc11e4d82950f642caad6cb2f949837b8560e2/pillow-12.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0847a763afefb695bc912d7c131e7e0632d4edc1d8698f58ddabec8e46b8b6d3", size = 6937129, upload-time = "2026-07-01T11:54:38.216Z" }, - { url = "https://files.pythonhosted.org/packages/70/4d/105627a13300c5e0df1d174230b32fd1273062c96f7745fd552b945d1e1d/pillow-12.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:571b9fcb07b97ef3a492028fb3d2dc0993ca23a06138b0315286566d29ef718a", size = 6339562, upload-time = "2026-07-01T11:54:40.354Z" }, - { url = "https://files.pythonhosted.org/packages/6b/1d/f13de01a553988ab895ba1c722e06cf3144d4f57656fd5b81b6d881f1179/pillow-12.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:756c768d0c9c2955feb7a56c37ea24aea2e369f8d36a88da270b6a9f19e62b5e", size = 7049439, upload-time = "2026-07-01T11:54:42.489Z" }, - { url = "https://files.pythonhosted.org/packages/c9/f9/066794cca041b969964f779ee5fa66a9498bbf34248ac39c5d7954e4198f/pillow-12.3.0-cp313-cp313-win32.whl", hash = "sha256:a876864214e136f0eb367788dbd7df045f4806801518e2cfe9e13229cfe06d8f", size = 6473287, upload-time = "2026-07-01T11:54:44.9Z" }, - { url = "https://files.pythonhosted.org/packages/a6/9b/7a58e61d62be561da3a356fe2384d4059a6345fc130e23ef1c36a5b81d24/pillow-12.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:1cca606cd25738df4ed873d5ad46bbdb3d83b5cbca291f6b4ff13a4df6b0bbe8", size = 7239691, upload-time = "2026-07-01T11:54:47.141Z" }, - { url = "https://files.pythonhosted.org/packages/aa/b0/c4ed4f0ef8f8fa5ee8351537db6650bb8189f7e118842978dd6589065692/pillow-12.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:b629de27fda84b42cde7edef0d85f13b958b47f6e9bbcbba9b673c562a89bd8b", size = 2568185, upload-time = "2026-07-01T11:54:49.137Z" }, -] - -[[package]] -name = "pip" -version = "26.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ae/15/4500e320e6b101ec3b719ae85b697d9940b6cda672bc555bd6016fc60c6f/pip-26.2.1.tar.gz", hash = "sha256:f6ad667e89a1fe78046c8f13232b247200f5258d7828f3f7883d660878e0813f", size = 1848877, upload-time = "2026-08-04T22:51:14.148Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f3/6e/1736e5b4ae2b778ef2f81c47d797de9f891d4d8acb047a24ca37a60294dd/pip-26.2.1-py3-none-any.whl", hash = "sha256:71138adf1f4ca900cdb7d289c21b7494329f2332b6d85f0e1c42108c0384ed3e", size = 1816632, upload-time = "2026-08-04T22:51:12.472Z" }, -] - -[[package]] -name = "pip-system-certs" -version = "5.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pip" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7d/6a/563b05a4f6c9ddc205c98bb413e74221368efb98b8fb9cca96b578b8930c/pip_system_certs-5.3.tar.gz", hash = "sha256:19c8bf9957bcce7d69c4dbc2d0b2ef13de1984d53f50a59012e6dbbad0af67c6", size = 6395, upload-time = "2025-10-16T06:14:55.217Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9f/57/752b63c609affae8f26ae0f1d1103d6ea7e707ad45943f62f7422936071d/pip_system_certs-5.3-py3-none-any.whl", hash = "sha256:3fbb5de62e374a99b688b1ad06e64ee5c4aeb633ef23e3a677d32e3e84fd863c", size = 6896, upload-time = "2025-10-16T06:14:54.072Z" }, -] - -[[package]] -name = "pluggy" -version = "1.6.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, -] - -[[package]] -name = "poks" -version = "0.11.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "gitpython" }, - { name = "mashumaro" }, - { name = "pip-system-certs" }, - { name = "py-app-dev" }, - { name = "py7zr" }, - { name = "requests" }, - { name = "typer" }, - { name = "zstandard" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a4/20/56ebe9b8b7607e775a5c8a1977ecb4555346a95f27212d329a642e1ce550/poks-0.11.1.tar.gz", hash = "sha256:1248c470d6bc7a97ea375e7afb774d3956c7c3ec51f6d11d6bfd7f3debd904af", size = 25655, upload-time = "2026-03-22T14:56:57.159Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/91/e8/9677a57ef26c79dad2056c79758170c085fc5387be5920387bc6420b1f4d/poks-0.11.1-py3-none-any.whl", hash = "sha256:d3ede0a3d449ba456510be03d91c554f96ff8cd55e08b5494e2d2942ab54070e", size = 27790, upload-time = "2026-03-22T14:56:56.022Z" }, -] - -[[package]] -name = "psutil" -version = "7.2.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/aa/c6/d1ddf4abb55e93cebc4f2ed8b5d6dbad109ecb8d63748dd2b20ab5e57ebe/psutil-7.2.2.tar.gz", hash = "sha256:0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372", size = 493740, upload-time = "2026-01-28T18:14:54.428Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/51/08/510cbdb69c25a96f4ae523f733cdc963ae654904e8db864c07585ef99875/psutil-7.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2edccc433cbfa046b980b0df0171cd25bcaeb3a68fe9022db0979e7aa74a826b", size = 130595, upload-time = "2026-01-28T18:14:57.293Z" }, - { url = "https://files.pythonhosted.org/packages/d6/f5/97baea3fe7a5a9af7436301f85490905379b1c6f2dd51fe3ecf24b4c5fbf/psutil-7.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e78c8603dcd9a04c7364f1a3e670cea95d51ee865e4efb3556a3a63adef958ea", size = 131082, upload-time = "2026-01-28T18:14:59.732Z" }, - { url = "https://files.pythonhosted.org/packages/37/d6/246513fbf9fa174af531f28412297dd05241d97a75911ac8febefa1a53c6/psutil-7.2.2-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1a571f2330c966c62aeda00dd24620425d4b0cc86881c89861fbc04549e5dc63", size = 181476, upload-time = "2026-01-28T18:15:01.884Z" }, - { url = "https://files.pythonhosted.org/packages/b8/b5/9182c9af3836cca61696dabe4fd1304e17bc56cb62f17439e1154f225dd3/psutil-7.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:917e891983ca3c1887b4ef36447b1e0873e70c933afc831c6b6da078ba474312", size = 184062, upload-time = "2026-01-28T18:15:04.436Z" }, - { url = "https://files.pythonhosted.org/packages/16/ba/0756dca669f5a9300d0cbcbfae9a4c30e446dfc7440ffe43ded5724bfd93/psutil-7.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:ab486563df44c17f5173621c7b198955bd6b613fb87c71c161f827d3fb149a9b", size = 139893, upload-time = "2026-01-28T18:15:06.378Z" }, - { url = "https://files.pythonhosted.org/packages/1c/61/8fa0e26f33623b49949346de05ec1ddaad02ed8ba64af45f40a147dbfa97/psutil-7.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:ae0aefdd8796a7737eccea863f80f81e468a1e4cf14d926bd9b6f5f2d5f90ca9", size = 135589, upload-time = "2026-01-28T18:15:08.03Z" }, - { url = "https://files.pythonhosted.org/packages/e7/36/5ee6e05c9bd427237b11b3937ad82bb8ad2752d72c6969314590dd0c2f6e/psutil-7.2.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ed0cace939114f62738d808fdcecd4c869222507e266e574799e9c0faa17d486", size = 129090, upload-time = "2026-01-28T18:15:22.168Z" }, - { url = "https://files.pythonhosted.org/packages/80/c4/f5af4c1ca8c1eeb2e92ccca14ce8effdeec651d5ab6053c589b074eda6e1/psutil-7.2.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:1a7b04c10f32cc88ab39cbf606e117fd74721c831c98a27dc04578deb0c16979", size = 129859, upload-time = "2026-01-28T18:15:23.795Z" }, - { url = "https://files.pythonhosted.org/packages/b5/70/5d8df3b09e25bce090399cf48e452d25c935ab72dad19406c77f4e828045/psutil-7.2.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:076a2d2f923fd4821644f5ba89f059523da90dc9014e85f8e45a5774ca5bc6f9", size = 155560, upload-time = "2026-01-28T18:15:25.976Z" }, - { url = "https://files.pythonhosted.org/packages/63/65/37648c0c158dc222aba51c089eb3bdfa238e621674dc42d48706e639204f/psutil-7.2.2-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0726cecd84f9474419d67252add4ac0cd9811b04d61123054b9fb6f57df6e9e", size = 156997, upload-time = "2026-01-28T18:15:27.794Z" }, - { url = "https://files.pythonhosted.org/packages/8e/13/125093eadae863ce03c6ffdbae9929430d116a246ef69866dad94da3bfbc/psutil-7.2.2-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fd04ef36b4a6d599bbdb225dd1d3f51e00105f6d48a28f006da7f9822f2606d8", size = 148972, upload-time = "2026-01-28T18:15:29.342Z" }, - { url = "https://files.pythonhosted.org/packages/04/78/0acd37ca84ce3ddffaa92ef0f571e073faa6d8ff1f0559ab1272188ea2be/psutil-7.2.2-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b58fabe35e80b264a4e3bb23e6b96f9e45a3df7fb7eed419ac0e5947c61e47cc", size = 148266, upload-time = "2026-01-28T18:15:31.597Z" }, - { url = "https://files.pythonhosted.org/packages/b4/90/e2159492b5426be0c1fef7acba807a03511f97c5f86b3caeda6ad92351a7/psutil-7.2.2-cp37-abi3-win_amd64.whl", hash = "sha256:eb7e81434c8d223ec4a219b5fc1c47d0417b12be7ea866e24fb5ad6e84b3d988", size = 137737, upload-time = "2026-01-28T18:15:33.849Z" }, - { url = "https://files.pythonhosted.org/packages/8c/c7/7bb2e321574b10df20cbde462a94e2b71d05f9bbda251ef27d104668306a/psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee", size = 134617, upload-time = "2026-01-28T18:15:36.514Z" }, -] - -[[package]] -name = "py-app-dev" -version = "2.23.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "loguru" }, - { name = "mashumaro" }, - { name = "psutil" }, - { name = "pyyaml" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5c/e6/8a14ebf396ebb644d75ad402a25692f0b36cbfdbae00842cca03936bb00e/py_app_dev-2.23.0.tar.gz", hash = "sha256:51864d8875f9b61944e567e301301645c4c77cdeacd182e1474618d69ac327b0", size = 24611, upload-time = "2026-09-15T08:36:59.355Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/be/22/17b7ca1df048647373e9381db30878631bfd4e64ace03f96d019da74368a/py_app_dev-2.23.0-py3-none-any.whl", hash = "sha256:e8a8c589818ea75b6d5a3076ab1f2cc90b9c40696f4879290c5a8c8e181ee775", size = 28595, upload-time = "2026-09-15T08:36:57.974Z" }, -] - -[[package]] -name = "py7zr" -version = "1.1.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "backports-zstd" }, - { name = "brotli", marker = "platform_python_implementation == 'CPython'" }, - { name = "brotlicffi", marker = "platform_python_implementation == 'PyPy'" }, - { name = "inflate64" }, - { name = "multivolumefile" }, - { name = "psutil", marker = "sys_platform != 'cygwin'" }, - { name = "pybcj" }, - { name = "pycryptodomex" }, - { name = "pyppmd" }, - { name = "texttable" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/59/3f/ac248f25f3901d3d6cf80ac99d5bac6fd1e5e6543c1812c79b02b6074c60/py7zr-1.1.3.tar.gz", hash = "sha256:8d51894abb38355bf14881088bb97f01fe4cb5b14ebe22f66d6297668c7e1a74", size = 71695, upload-time = "2026-06-19T09:28:29.339Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/88/40/dc7f804abd0ea167ea8d4d9b3f5455321aaf671d040fcef647e9e952e714/py7zr-1.1.3-py3-none-any.whl", hash = "sha256:17934a35089e026dec6c72ee275d9b841e646881ef822d618e805c3006661d9a", size = 72242, upload-time = "2026-06-19T09:28:27.512Z" }, -] - -[[package]] -name = "pybcj" -version = "1.0.8" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/14/c9/e2de4f98c21f2ff9e58047395b6a8e17701a0f2977f0e63f80948f61647f/pybcj-1.0.8.tar.gz", hash = "sha256:6818270692912d47e81ccd777b7d0ed2ad3a19ef7aaead3735b38048c80bf368", size = 31763, upload-time = "2026-07-16T22:47:24.705Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/09/32/63b96b702fc4848834ce552302fbdccad92f67886eaf3fbbed530569f4a1/pybcj-1.0.8-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:748af4545040da68dfae8cdf9f902ac7c29f209aaf6450a970abe0302d1b0f58", size = 32798, upload-time = "2026-07-16T22:46:40.083Z" }, - { url = "https://files.pythonhosted.org/packages/a2/21/0b501901021499e41afe7d0148c94ee26dcf045d3e1389bf1b42a61d11a6/pybcj-1.0.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:190e21c3bdb6b28c63999889668a3f80f5d7eb13b957f2dfda53c9ddeb3d946a", size = 24673, upload-time = "2026-07-16T22:46:41.288Z" }, - { url = "https://files.pythonhosted.org/packages/b3/97/c05d5800d742f5162bd06ef790dfcf73128431328f16abe7a0e2109d8ca5/pybcj-1.0.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:384b25dfe66868329a3872c6eae668033e009e4e86754eba3a70b656c9eb4208", size = 24958, upload-time = "2026-07-16T22:46:42.469Z" }, - { url = "https://files.pythonhosted.org/packages/05/0f/9db13432a6f8878f90c108a68fda46e832eea53585cb5dee8bdbc9472467/pybcj-1.0.8-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b480efcd66cfb4533ede6c3d67224ff477c8dd661613826edff9c95921a562d6", size = 53297, upload-time = "2026-07-16T22:46:43.93Z" }, - { url = "https://files.pythonhosted.org/packages/76/59/5629811698e6cfaea6cf159cf86fa471904ceb60448dc8b80233bba2e392/pybcj-1.0.8-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a50b58f9b9d9978c55e3219b6816a1021a778b028a810b36aa754407591cb5ae", size = 52332, upload-time = "2026-07-16T22:46:45.252Z" }, - { url = "https://files.pythonhosted.org/packages/b2/0a/c5bd982957b5fd785f02dffcb3f6f45a93143e1e8ccc8224e19b3915fc84/pybcj-1.0.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1997badf9e59221470f84e193ac8c1bab158acfe6b058ffdc28c331807967ff9", size = 51192, upload-time = "2026-07-16T22:46:46.674Z" }, - { url = "https://files.pythonhosted.org/packages/7a/79/1d421d2d45e565a0f8eab8ce6f795e31beca96f658c1e483dac64a466a28/pybcj-1.0.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4f0818cf48fbfddbae487536f3fcd69cfadfb7293630ab8658b66e89a0836d6a", size = 50849, upload-time = "2026-07-16T22:46:48.006Z" }, - { url = "https://files.pythonhosted.org/packages/7b/c3/daddd6edc01689b1cb75733bd3098231bae20c9e77d7022dc0b1c40e56fd/pybcj-1.0.8-cp312-cp312-win_amd64.whl", hash = "sha256:26e3e4d287f306996902289fc0e88b36d0fc817802f4fc4537b40a6518726585", size = 24956, upload-time = "2026-07-16T22:46:49.159Z" }, - { url = "https://files.pythonhosted.org/packages/a7/fc/9c668e2cd1432f7ede31bc131ab336c8602659374bc731bfaca6cf208bbe/pybcj-1.0.8-cp312-cp312-win_arm64.whl", hash = "sha256:82d2e46eff6c3fe8d16f6515f9ab0598eb960af9a2218907c5e0e9f993d7a666", size = 24251, upload-time = "2026-07-16T22:46:50.33Z" }, - { url = "https://files.pythonhosted.org/packages/25/c1/9d8822f1b97813f21b5907b351edb0f607c9736e21637812edf407a2dae6/pybcj-1.0.8-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9f0e496c49dce294fb41a2221e7b3f96156bb940d8cfe359d441909f1cf241ea", size = 32799, upload-time = "2026-07-16T22:46:51.625Z" }, - { url = "https://files.pythonhosted.org/packages/6f/8b/248154c815e683c0f991c471bedb7476d7c91fd8a56918f1ef66d2341ea5/pybcj-1.0.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0657c9534d480a43b11743cad4209d140d09d417adaf19213ff395686ed08812", size = 24673, upload-time = "2026-07-16T22:46:52.799Z" }, - { url = "https://files.pythonhosted.org/packages/e0/f7/f168c7b091fc41fc7ef6d9ed6cde2ec10bb4814f14ad21b493881476636e/pybcj-1.0.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:784443d0c075871689692679ef01cfe85eca789cc8d091f842fa02f62dead9d5", size = 24955, upload-time = "2026-07-16T22:46:54.069Z" }, - { url = "https://files.pythonhosted.org/packages/cc/a1/7b802ee7c7730521a102dadbdf944943795b3e9ca3ca665dbbdd1213f781/pybcj-1.0.8-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9195ce382f21e13df7ecc0df8fb42c5f391a7ac516066af16b023e6bd2f86046", size = 53344, upload-time = "2026-07-16T22:46:55.272Z" }, - { url = "https://files.pythonhosted.org/packages/4b/cf/c4b0248051cdb7af7f38223db63427175e755db1f1a7905e781e923f6d53/pybcj-1.0.8-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e5e67ec32176985bbf941185319a3fe385527b6826d457a8ec67dd43b5f0b5fa", size = 52410, upload-time = "2026-07-16T22:46:56.541Z" }, - { url = "https://files.pythonhosted.org/packages/52/77/9afed44c590a19940e04fdf38b7f55e7db3a8b35e3f6320340d99be25ca8/pybcj-1.0.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:20b657e4fe3e701a0f64a7c1224694820687334b17593d74a878f7124f10b24f", size = 51282, upload-time = "2026-07-16T22:46:57.748Z" }, - { url = "https://files.pythonhosted.org/packages/10/4b/7eaf8cf0ad598cc2035a24186a3e2bf45ec798279dad58484d0eb940d4b3/pybcj-1.0.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5b4c66b5358cd241b6ff81a8fafd5806e816d378c810a796ad51865be5533f7", size = 50935, upload-time = "2026-07-16T22:46:58.94Z" }, - { url = "https://files.pythonhosted.org/packages/39/f4/04d46f5059af00d2fae6086a7f47ebc23e553900ca75ea2a2e276d3a436c/pybcj-1.0.8-cp313-cp313-win_amd64.whl", hash = "sha256:e47d9c655d276200e5d08f7b550097dacc826364b44931f0fbdc0da2e4bdf448", size = 24956, upload-time = "2026-07-16T22:47:00.127Z" }, - { url = "https://files.pythonhosted.org/packages/63/cc/387af6844cdc53be20a9271998bc4a15a96360f06ce8829193d4a45f6b19/pybcj-1.0.8-cp313-cp313-win_arm64.whl", hash = "sha256:f561988aef99f07e991d0708ca6fe86e766d545c0a20e58bdbd38615a615e419", size = 24249, upload-time = "2026-07-16T22:47:01.28Z" }, -] - -[[package]] -name = "pycparser" -version = "3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, -] - -[[package]] -name = "pycryptodomex" -version = "3.23.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c9/85/e24bf90972a30b0fcd16c73009add1d7d7cd9140c2498a68252028899e41/pycryptodomex-3.23.0.tar.gz", hash = "sha256:71909758f010c82bc99b0abf4ea12012c98962fbf0583c2164f8b84533c2e4da", size = 4922157, upload-time = "2025-05-17T17:23:41.434Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2e/00/10edb04777069a42490a38c137099d4b17ba6e36a4e6e28bdc7470e9e853/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:7b37e08e3871efe2187bc1fd9320cc81d87caf19816c648f24443483005ff886", size = 2498764, upload-time = "2025-05-17T17:22:21.453Z" }, - { url = "https://files.pythonhosted.org/packages/6b/3f/2872a9c2d3a27eac094f9ceaa5a8a483b774ae69018040ea3240d5b11154/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:91979028227543010d7b2ba2471cf1d1e398b3f183cb105ac584df0c36dac28d", size = 1643012, upload-time = "2025-05-17T17:22:23.702Z" }, - { url = "https://files.pythonhosted.org/packages/70/af/774c2e2b4f6570fbf6a4972161adbb183aeeaa1863bde31e8706f123bf92/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b8962204c47464d5c1c4038abeadd4514a133b28748bcd9fa5b6d62e3cec6fa", size = 2187643, upload-time = "2025-05-17T17:22:26.37Z" }, - { url = "https://files.pythonhosted.org/packages/de/a3/71065b24cb889d537954cedc3ae5466af00a2cabcff8e29b73be047e9a19/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a33986a0066860f7fcf7c7bd2bc804fa90e434183645595ae7b33d01f3c91ed8", size = 2273762, upload-time = "2025-05-17T17:22:28.313Z" }, - { url = "https://files.pythonhosted.org/packages/c9/0b/ff6f43b7fbef4d302c8b981fe58467b8871902cdc3eb28896b52421422cc/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7947ab8d589e3178da3d7cdeabe14f841b391e17046954f2fbcd941705762b5", size = 2313012, upload-time = "2025-05-17T17:22:30.57Z" }, - { url = "https://files.pythonhosted.org/packages/02/de/9d4772c0506ab6da10b41159493657105d3f8bb5c53615d19452afc6b315/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c25e30a20e1b426e1f0fa00131c516f16e474204eee1139d1603e132acffc314", size = 2186856, upload-time = "2025-05-17T17:22:32.819Z" }, - { url = "https://files.pythonhosted.org/packages/28/ad/8b30efcd6341707a234e5eba5493700a17852ca1ac7a75daa7945fcf6427/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:da4fa650cef02db88c2b98acc5434461e027dce0ae8c22dd5a69013eaf510006", size = 2347523, upload-time = "2025-05-17T17:22:35.386Z" }, - { url = "https://files.pythonhosted.org/packages/0f/02/16868e9f655b7670dbb0ac4f2844145cbc42251f916fc35c414ad2359849/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:58b851b9effd0d072d4ca2e4542bf2a4abcf13c82a29fd2c93ce27ee2a2e9462", size = 2272825, upload-time = "2025-05-17T17:22:37.632Z" }, - { url = "https://files.pythonhosted.org/packages/ca/18/4ca89ac737230b52ac8ffaca42f9c6f1fd07c81a6cd821e91af79db60632/pycryptodomex-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:a9d446e844f08299236780f2efa9898c818fe7e02f17263866b8550c7d5fb328", size = 1772078, upload-time = "2025-05-17T17:22:40Z" }, - { url = "https://files.pythonhosted.org/packages/73/34/13e01c322db027682e00986873eca803f11c56ade9ba5bbf3225841ea2d4/pycryptodomex-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:bc65bdd9fc8de7a35a74cab1c898cab391a4add33a8fe740bda00f5976ca4708", size = 1803656, upload-time = "2025-05-17T17:22:42.139Z" }, - { url = "https://files.pythonhosted.org/packages/54/68/9504c8796b1805d58f4425002bcca20f12880e6fa4dc2fc9a668705c7a08/pycryptodomex-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c885da45e70139464f082018ac527fdaad26f1657a99ee13eecdce0f0ca24ab4", size = 1707172, upload-time = "2025-05-17T17:22:44.704Z" }, - { url = "https://files.pythonhosted.org/packages/dd/9c/1a8f35daa39784ed8adf93a694e7e5dc15c23c741bbda06e1d45f8979e9e/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:06698f957fe1ab229a99ba2defeeae1c09af185baa909a31a5d1f9d42b1aaed6", size = 2499240, upload-time = "2025-05-17T17:22:46.953Z" }, - { url = "https://files.pythonhosted.org/packages/7a/62/f5221a191a97157d240cf6643747558759126c76ee92f29a3f4aee3197a5/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b2c2537863eccef2d41061e82a881dcabb04944c5c06c5aa7110b577cc487545", size = 1644042, upload-time = "2025-05-17T17:22:49.098Z" }, - { url = "https://files.pythonhosted.org/packages/8c/fd/5a054543c8988d4ed7b612721d7e78a4b9bf36bc3c5ad45ef45c22d0060e/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43c446e2ba8df8889e0e16f02211c25b4934898384c1ec1ec04d7889c0333587", size = 2186227, upload-time = "2025-05-17T17:22:51.139Z" }, - { url = "https://files.pythonhosted.org/packages/c8/a9/8862616a85cf450d2822dbd4fff1fcaba90877907a6ff5bc2672cafe42f8/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f489c4765093fb60e2edafdf223397bc716491b2b69fe74367b70d6999257a5c", size = 2272578, upload-time = "2025-05-17T17:22:53.676Z" }, - { url = "https://files.pythonhosted.org/packages/46/9f/bda9c49a7c1842820de674ab36c79f4fbeeee03f8ff0e4f3546c3889076b/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdc69d0d3d989a1029df0eed67cc5e8e5d968f3724f4519bd03e0ec68df7543c", size = 2312166, upload-time = "2025-05-17T17:22:56.585Z" }, - { url = "https://files.pythonhosted.org/packages/03/cc/870b9bf8ca92866ca0186534801cf8d20554ad2a76ca959538041b7a7cf4/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6bbcb1dd0f646484939e142462d9e532482bc74475cecf9c4903d4e1cd21f003", size = 2185467, upload-time = "2025-05-17T17:22:59.237Z" }, - { url = "https://files.pythonhosted.org/packages/96/e3/ce9348236d8e669fea5dd82a90e86be48b9c341210f44e25443162aba187/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:8a4fcd42ccb04c31268d1efeecfccfd1249612b4de6374205376b8f280321744", size = 2346104, upload-time = "2025-05-17T17:23:02.112Z" }, - { url = "https://files.pythonhosted.org/packages/a5/e9/e869bcee87beb89040263c416a8a50204f7f7a83ac11897646c9e71e0daf/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:55ccbe27f049743a4caf4f4221b166560d3438d0b1e5ab929e07ae1702a4d6fd", size = 2271038, upload-time = "2025-05-17T17:23:04.872Z" }, - { url = "https://files.pythonhosted.org/packages/8d/67/09ee8500dd22614af5fbaa51a4aee6e342b5fa8aecf0a6cb9cbf52fa6d45/pycryptodomex-3.23.0-cp37-abi3-win32.whl", hash = "sha256:189afbc87f0b9f158386bf051f720e20fa6145975f1e76369303d0f31d1a8d7c", size = 1771969, upload-time = "2025-05-17T17:23:07.115Z" }, - { url = "https://files.pythonhosted.org/packages/69/96/11f36f71a865dd6df03716d33bd07a67e9d20f6b8d39820470b766af323c/pycryptodomex-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:52e5ca58c3a0b0bd5e100a9fbc8015059b05cffc6c66ce9d98b4b45e023443b9", size = 1803124, upload-time = "2025-05-17T17:23:09.267Z" }, - { url = "https://files.pythonhosted.org/packages/f9/93/45c1cdcbeb182ccd2e144c693eaa097763b08b38cded279f0053ed53c553/pycryptodomex-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:02d87b80778c171445d67e23d1caef279bf4b25c3597050ccd2e13970b57fd51", size = 1707161, upload-time = "2025-05-17T17:23:11.414Z" }, -] - -[[package]] -name = "pydantic" -version = "2.13.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "annotated-types" }, - { name = "pydantic-core" }, - { name = "typing-extensions" }, - { name = "typing-inspection" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/53/ef/fc4f868f4e2cee79f863883abffceff107875f569b848507319842d2a681/pydantic-2.13.5.tar.gz", hash = "sha256:51a9c5f7b2f8e636f04c6cada605d9b6a3bf1348fdf945a3d8869b19bba0ee08", size = 845750, upload-time = "2026-08-28T14:04:00.916Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl", hash = "sha256:346a034f080da3755d8e9cb5e00e8b07de1d39e4f6e2c87d8ab7cafa0b269a73", size = 472589, upload-time = "2026-08-28T14:03:59.136Z" }, -] - -[[package]] -name = "pydantic-core" -version = "2.46.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/af/f9/8a06bea35ef8daf588f707784c973a7046e0034c8d8cfb08828eeffb8b75/pydantic_core-2.46.5.tar.gz", hash = "sha256:10416c15b8839ecc4ef4d0885da76da6fd0f67333a0eb8aff6d93c4b8f2910fc", size = 472262, upload-time = "2026-08-28T10:01:31.677Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/82/3f/76358795aa7a8c6d4f36e2cb828ad1c90ee118e1393a9281664f5aade9d4/pydantic_core-2.46.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b9fe6fb92520e3fd61f2e49000b6911b188824f089b75973ea06d6267f0b476d", size = 2076516, upload-time = "2026-08-28T09:58:21.576Z" }, - { url = "https://files.pythonhosted.org/packages/db/50/26b091836076ce4cb2fac264186936acc069e0595772cfd02a563bc4761a/pydantic_core-2.46.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a39ac25a9a2fa4072efdb429833c4a4c8009a51ff9eea3eeae131713cd27991e", size = 1922874, upload-time = "2026-08-28T09:58:23.766Z" }, - { url = "https://files.pythonhosted.org/packages/09/f0/2a8ce3849e299d44e2d2c196b6082643a3235565a735cb51db7a6261f614/pydantic_core-2.46.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4fdc8b93a41521988916eeaa271173fcca7fa0803d62f87675aac8dcec1c8e29", size = 1951772, upload-time = "2026-08-28T09:58:25.435Z" }, - { url = "https://files.pythonhosted.org/packages/87/46/ac0dc8bdd9e6048183a14eb127764e7ad9240021c17513074a4711b0e31e/pydantic_core-2.46.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b98134087d9de723658d17a42c7d0da8d6e2ef08015dee7dc93889047315f5e4", size = 2031832, upload-time = "2026-08-28T09:58:27.102Z" }, - { url = "https://files.pythonhosted.org/packages/c4/c2/339de5bef7be36301a2231eaa52e62163742c2281f11b5f4892bc79785cd/pydantic_core-2.46.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e652ab17569c94bff5475520f907b7148b8c24036a8ebbe5cf7cf7493d28579a", size = 2208645, upload-time = "2026-08-28T09:58:28.948Z" }, - { url = "https://files.pythonhosted.org/packages/7b/a0/9ff22b797724262da14427abaed4dd1d864a139693fc5e7809114376a716/pydantic_core-2.46.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d925f3d9afd05a8c0fb3a1031463a8d59ebe5e2afad297e29c78be19e13b4e62", size = 2265935, upload-time = "2026-08-28T09:58:30.625Z" }, - { url = "https://files.pythonhosted.org/packages/c0/a4/eb9409ec0736e50aa70a412f16c204ed149516846912f7e6724d4c73ee53/pydantic_core-2.46.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fc5be0abd4a407e200d844b404e33639a554e7bd0d448e7b9ae181be4789ac2", size = 2066284, upload-time = "2026-08-28T09:58:32.289Z" }, - { url = "https://files.pythonhosted.org/packages/c0/02/7f6156ffc926857f1c37c07d9a388682865a81830ab6a1b637082c25e399/pydantic_core-2.46.5-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:816ff0a6550ffc06c098ccd2e0698600f9aa7da192a79eaa6f9af504a35db869", size = 2105889, upload-time = "2026-08-28T09:58:33.986Z" }, - { url = "https://files.pythonhosted.org/packages/92/b1/e781d357ebe09fc929f995700f1b3503e8897f1cece183ecb1300d4d67e9/pydantic_core-2.46.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c7ea57fc63aa7da93a1bd2d644e6577befae10c52c4e36377635eea1056a74f5", size = 2158006, upload-time = "2026-08-28T09:58:35.647Z" }, - { url = "https://files.pythonhosted.org/packages/70/0a/644597d84ab400e50609c192120b85c9681c22d3a20461b9060a79be0a7a/pydantic_core-2.46.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:efd62a42486f1bda5d24cb4f63d15a3c7768375fe83d36f9417b4ad7a2fb20b3", size = 2158408, upload-time = "2026-08-28T09:58:37.38Z" }, - { url = "https://files.pythonhosted.org/packages/1e/ee/ca3b7b3a4b3769ffe9ce9432a7c9be755de9593a46d3b0d54d0409323e44/pydantic_core-2.46.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:2bc9419666990c06d7397831f2126a1ecc3594aaa3ff7de5bf2d066802f4e07b", size = 2309609, upload-time = "2026-08-28T09:58:39.22Z" }, - { url = "https://files.pythonhosted.org/packages/ce/52/39fa1f451486019524ca685020390e7ca351832fd874530ba30c8628e6dc/pydantic_core-2.46.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:18a09e1e1011b462f2e32774f25859ef1223d5c2b0546a633cf56654710721e0", size = 2342618, upload-time = "2026-08-28T09:58:40.89Z" }, - { url = "https://files.pythonhosted.org/packages/81/5e/468fc630568c61dcef3cd47ad32ffbeed9af643f49208d1ea86ab4f890c4/pydantic_core-2.46.5-cp312-cp312-win32.whl", hash = "sha256:5cb482e9e84c851f4e623fe4acc1ced89168cf1fe18f7089db4548c8f5bbb65b", size = 1939475, upload-time = "2026-08-28T09:58:42.591Z" }, - { url = "https://files.pythonhosted.org/packages/cf/c9/4c19f41b84cf6b622a72fbeed7665b25d47a187d68d47d0d430c07f23268/pydantic_core-2.46.5-cp312-cp312-win_amd64.whl", hash = "sha256:5e81740c09e310f5aa5cbd3e434a01c154d4bef93241c7877b39f211d2b78ba8", size = 2043140, upload-time = "2026-08-28T09:58:44.272Z" }, - { url = "https://files.pythonhosted.org/packages/af/dd/0c1a050299147c746e5256db16d645ab5efd4f78c59937d581a0524e74a2/pydantic_core-2.46.5-cp312-cp312-win_arm64.whl", hash = "sha256:f7b0ec93a2893de856652154d73b7ba622f26fa97726487dcac373de5f4c6084", size = 1997729, upload-time = "2026-08-28T09:58:46.13Z" }, - { url = "https://files.pythonhosted.org/packages/f5/37/5abe39a8372a61d3dc3c1338fc504281c01b32fdb3169cd7187153b56d3e/pydantic_core-2.46.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:b7ca9034437b6022f941f4857459562ee00a560b97e7cce8a0ec5a74fc6766e0", size = 2075885, upload-time = "2026-08-28T09:58:47.856Z" }, - { url = "https://files.pythonhosted.org/packages/21/43/6323b1f8b217780454c61304bcd2b38ae4762f50754414124603ccc90bb2/pydantic_core-2.46.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f332f0e72a5a0400141f830744e141bf9f97917878dbe968669e8a7fefea78ff", size = 1922768, upload-time = "2026-08-28T09:58:49.58Z" }, - { url = "https://files.pythonhosted.org/packages/0f/a3/c05ca796e1197618a774b01e596aeedfefc2f7d8c01ae3054e910b120e8a/pydantic_core-2.46.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:193375f3548919d3f0b60936ca113ada3e38f264f91b9b8e0508efaad57be931", size = 1951241, upload-time = "2026-08-28T09:58:51.511Z" }, - { url = "https://files.pythonhosted.org/packages/68/32/33bc39ac705c52cffc908e8389f9754fdb208aea5c69cceddf4eb3ce99af/pydantic_core-2.46.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:79bdfa52f843137045b2d081cc05c120ba6665d29b7559c2c47690906f39279f", size = 2031975, upload-time = "2026-08-28T09:58:53.166Z" }, - { url = "https://files.pythonhosted.org/packages/b0/70/2333e885c0f6a67bc105c5916965dac9b57f2718ee20d81d1a06a4ebdc13/pydantic_core-2.46.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:24922243639cbdac66c75fcb6fd6495a9cb52b213d62f9a0d16f0310b1ff8038", size = 2208542, upload-time = "2026-08-28T09:58:55.017Z" }, - { url = "https://files.pythonhosted.org/packages/f7/ea/296debfb4264207bbda5936133892e027c0a58875ad53ebd512fba8ec3a2/pydantic_core-2.46.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c76fe65e607be28c7fd4d56fc3c42b1583aa058ce3408b7ad0fd540171d31f9f", size = 2264692, upload-time = "2026-08-28T09:58:56.767Z" }, - { url = "https://files.pythonhosted.org/packages/d3/f2/9e4de77a6271e07a76d2d58b11c091a979c191ed2939bf80067568b369d2/pydantic_core-2.46.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f7b393a8b3da82f5c1fc0751e6d01ac6c55b93c18226a60bdfba4a724efafd1", size = 2066633, upload-time = "2026-08-28T09:58:58.531Z" }, - { url = "https://files.pythonhosted.org/packages/8d/db/f9e9d0c97445987b2084823d5c240de88087338f04fc2cfaa2df186b8049/pydantic_core-2.46.5-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:7ac031912d54f3d83ef3b3eb98dfabc1608802e2202263d25957eeed40b94761", size = 2105235, upload-time = "2026-08-28T09:59:00.421Z" }, - { url = "https://files.pythonhosted.org/packages/07/c5/79169b047b3b2c3e99e04bc76372af9637e0bf6db638274fa927df96369e/pydantic_core-2.46.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:837b396ca3d7b74091ca623f6cbd8351bd42d670a79c2683e79fb089f06a2de5", size = 2157367, upload-time = "2026-08-28T09:59:02.442Z" }, - { url = "https://files.pythonhosted.org/packages/26/b5/ba6057afb7c291bd449f51b867f95aef2072941c4ce4e5c31d6ffd132d3b/pydantic_core-2.46.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:5ee239d575f80b08eca11f6e20f90c4c695de7825c67eefe6091fbf20dda648e", size = 2158420, upload-time = "2026-08-28T09:59:04.2Z" }, - { url = "https://files.pythonhosted.org/packages/6e/28/2057abecaafdc22912afa819603a51f0a62d40643b7c4871c51721fea9be/pydantic_core-2.46.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:e80675d75ae2cd14372cb65cad5400d9347a3d3f6c13000183f22dfd027283ed", size = 2309588, upload-time = "2026-08-28T09:59:06.048Z" }, - { url = "https://files.pythonhosted.org/packages/71/9d/881156dc404e27479c4246128d73538464cab4a239bec61995e227644c30/pydantic_core-2.46.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:9c4b71f10dd532fb7a5cbc8f58707779e64f03a258c2bf8bfbaecfcd9970b519", size = 2341866, upload-time = "2026-08-28T09:59:08.539Z" }, - { url = "https://files.pythonhosted.org/packages/5a/38/d66f443a259f84d13babdceae568e572b0ed26da17ca5d0a649ebb110a67/pydantic_core-2.46.5-cp313-cp313-win32.whl", hash = "sha256:97bf8de4d541598c94a59344eeb988a94c08ff76b5723c41f6567ec18c7892ea", size = 1938580, upload-time = "2026-08-28T09:59:10.402Z" }, - { url = "https://files.pythonhosted.org/packages/2c/1e/1d5371213f4cc9a7ed70c0bfcc7911de22311ee99a662a56077d7292d2ac/pydantic_core-2.46.5-cp313-cp313-win_amd64.whl", hash = "sha256:15f4a94963c95accac15b7b657bb177d3ad82bb90b0d0526d9a9b85079925db5", size = 2041980, upload-time = "2026-08-28T09:59:12.396Z" }, - { url = "https://files.pythonhosted.org/packages/5a/48/4222d90b1c67568bace4dec6dca6271449c66de3595d72b6d098f5fde597/pydantic_core-2.46.5-cp313-cp313-win_arm64.whl", hash = "sha256:d22a945598fb91236b4dd793a6e42e4f3dd7740bb5aace5ebd7d4c08d13bb575", size = 1997213, upload-time = "2026-08-28T09:59:14.245Z" }, - { url = "https://files.pythonhosted.org/packages/df/dd/053c2e4303f791f3b8f8a14ab0b22008e8eb21d868c0c90b4f9be705b76a/pydantic_core-2.46.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:013d6f3483d81e02e7c328831808f336c8596ee33b4bd4026b9ffb1e960b8942", size = 2062540, upload-time = "2026-08-28T10:01:00.318Z" }, - { url = "https://files.pythonhosted.org/packages/d7/dd/a18df751a5e37dd51bfad7f68e766999125bebe68c9e1d10a493ad01bd63/pydantic_core-2.46.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:e9c134bb666dd54b778b9fc0d2b50cbb7f979b9e3716f26a88c9ab3b6fc1dd0f", size = 1902040, upload-time = "2026-08-28T10:01:02.529Z" }, - { url = "https://files.pythonhosted.org/packages/b7/13/01d40f9d07ce8a779fd6e0bd8ad4fba91309500dd67b869e2e219d261a6d/pydantic_core-2.46.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:347ec774390c87326a2e4929d58d3f7e8763a104d5d35f4cd595a4c952366433", size = 1967479, upload-time = "2026-08-28T10:01:05.004Z" }, - { url = "https://files.pythonhosted.org/packages/fa/04/c81d4841331c2178b6fb09ae225425e110ed72d990c9fe556c4ec03d1013/pydantic_core-2.46.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e24d8f05fa2d28513d94e877e9c75ad66175376209b3977f916e240e623193c", size = 2111034, upload-time = "2026-08-28T10:01:07.345Z" }, -] - -[[package]] -name = "pydata-sphinx-theme" -version = "0.19.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "accessible-pygments" }, - { name = "babel" }, - { name = "beautifulsoup4" }, - { name = "docutils" }, - { name = "pygments" }, - { name = "sphinx" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/39/7e/e3defb93f30557ae825a3b3fbc2c6728301e5e9505a85e00d8503345c42c/pydata_sphinx_theme-0.19.0.tar.gz", hash = "sha256:148ba092bd6937b3321385dc482cc69a29ad2ede36547b4f010ade782bc6a062", size = 5004933, upload-time = "2026-06-15T09:31:02.268Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/54/77/bdb5a4c0e8e33c08f31fd175a5af0bc5e29f1b43ffa9e963f4c4f9bfbc97/pydata_sphinx_theme-0.19.0-py3-none-any.whl", hash = "sha256:5d7dfe3beb0facc88b5d78ff4a4c948f214cc0e03aae27e7fc58286e963b588b", size = 6201132, upload-time = "2026-06-15T09:30:59.966Z" }, -] - -[[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 = "pykwalify" -version = "1.8.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "docopt" }, - { name = "python-dateutil" }, - { name = "ruamel-yaml" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d5/77/2d6849510dbfce5f74f1f69768763630ad0385ad7bb0a4f39b55de3920c7/pykwalify-1.8.0.tar.gz", hash = "sha256:796b2ad3ed4cb99b88308b533fb2f559c30fa6efb4fa9fda11347f483d245884", size = 62462, upload-time = "2020-12-30T22:31:10.745Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/fd/ac2161cce19fd67a18c269073f8e86292b5511acec6f8ef6eab88615d032/pykwalify-1.8.0-py2.py3-none-any.whl", hash = "sha256:731dfa87338cca9f559d1fca2bdea37299116e3139b73f78ca90a543722d6651", size = 24860, upload-time = "2020-12-30T22:31:09.09Z" }, -] - -[[package]] -name = "pyparsing" -version = "3.3.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e4/11/b213bebff182584360cb8d17c72c1677fec5c5c228de439e63bcf8ab1c8f/pyparsing-3.3.3.tar.gz", hash = "sha256:928ae7e20211f3b6f3915a72f06a0cfd29ab9d24279dd6346b6b1a7146397d36", size = 1050487, upload-time = "2026-09-20T20:59:05.609Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/38/bb/d215ee7c73b61497b28a5503f9f53523f294fcc936762b7caf90e0c1c2b5/pyparsing-3.3.3-py3-none-any.whl", hash = "sha256:ece8c00a69cf01b45d0b1dedabb469c90d8caf996d4fda40f147627a122849a4", size = 126420, upload-time = "2026-09-20T20:59:04.025Z" }, -] - -[[package]] -name = "pypeline-runner" -version = "1.39.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "poks" }, - { name = "py-app-dev" }, - { name = "pyyaml" }, - { name = "typer" }, - { name = "west" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/95/41/bedb03c38505e88b7fbca3dc8fe6f2ec3c3733b08b0db7967fa2779087ac/pypeline_runner-1.39.0.tar.gz", hash = "sha256:fd387cf5a70f8b41b3363dc8064077ad28b903295913dc427acf06c73b7f2ad9", size = 40523, upload-time = "2026-09-04T15:10:55.246Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b0/80/1343cbc76ebe62a004576df9bca5ff31bf2765d70b9915f5d6288cd04b48/pypeline_runner-1.39.0-py3-none-any.whl", hash = "sha256:a6993ca2410e02c7e68004879f4b50fa64b1cc6f9c2fb6187837d96e81d89e01", size = 48884, upload-time = "2026-09-04T15:10:53.824Z" }, -] - -[[package]] -name = "pypeline-semantic-release" -version = "0.5.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "py-app-dev" }, - { name = "pypeline-runner" }, - { name = "python-semantic-release" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d2/f5/c54da09b40ebee03f0401778d4a83743e5807ce321e892dc4f96fe038b2a/pypeline_semantic_release-0.5.1.tar.gz", hash = "sha256:b1e5bd84143f9d0250da5e3b78c900587535d8a4419390898e93b2fdb0fee016", size = 16505, upload-time = "2026-04-21T05:35:29.442Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e3/50/584083a8dccd9010a977d5ea39fc9830bf5374421ee32459b5b821b66836/pypeline_semantic_release-0.5.1-py3-none-any.whl", hash = "sha256:9ef3602f4659f600b243a09d243cb3c861c5446eacbf6210bc79065efed0781b", size = 15443, upload-time = "2026-04-21T05:35:27.73Z" }, -] - -[[package]] -name = "pyppmd" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/81/d7/803232913cab9163a1a97ecf2236cd7135903c46ac8d49613448d88e8759/pyppmd-1.3.1.tar.gz", hash = "sha256:ced527f08ade4408c1bfc5264e9f97ffac8d221c9d13eca4f35ec1ec0c7b6b2e", size = 1351815, upload-time = "2025-11-27T22:08:44.175Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3e/89/696046e53c7aea98bb563aed3f15c3e2fa20c33e3d6c9de3c20992c586cc/pyppmd-1.3.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3faa58ab2ebe3b13ec23b1904639d687fb727270d2962fd2d239ca00fd6eb865", size = 77796, upload-time = "2025-11-27T22:07:50.362Z" }, - { url = "https://files.pythonhosted.org/packages/f1/c5/a708cdb58e76889bc65201eda12211486548ffe00ecddc5dfbdce6d4d252/pyppmd-1.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:27703f041ee96912a5410fd3ce31c5cde32f9323bd67f72f100bd960ee67bf13", size = 48185, upload-time = "2025-11-27T22:07:51.736Z" }, - { url = "https://files.pythonhosted.org/packages/9e/5d/f299535c18009addb866d89a7044f1086e4eecf50542e57ff5bb15840195/pyppmd-1.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e773d8353b36f7e7973a43526993fb276b98a97839cb5dc8f4e6465ad873f41a", size = 48496, upload-time = "2025-11-27T22:07:52.866Z" }, - { url = "https://files.pythonhosted.org/packages/aa/9d/4a59b73ea8e305f9192ee26ceb7c3d57e17ccb9bcca0e99ef335db29fcf7/pyppmd-1.3.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:37b1883accf840cb0b711785d353f8548853a1401d381da007c0aec362f3ffac", size = 142620, upload-time = "2025-11-27T22:07:54.411Z" }, - { url = "https://files.pythonhosted.org/packages/88/d7/fe32c2a4f8539365e6292aed25545830a5e718a510cdb4caddd6fd8d8056/pyppmd-1.3.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1bd6d179ad39b6191ca0cbe62fb9592f33f49277b4384ad7bc5eb0e6ca27ebee", size = 144306, upload-time = "2025-11-27T22:07:55.727Z" }, - { url = "https://files.pythonhosted.org/packages/20/20/e3907cf263b58f4ed4c5315bc1ac91721c85332fd0d73a89e3e2752904ef/pyppmd-1.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:806cf8d33606e44bf5ff5786c57891f57993f1eef1c763da3c58ea97de3a13c8", size = 139522, upload-time = "2025-11-27T22:07:57.034Z" }, - { url = "https://files.pythonhosted.org/packages/0a/03/22d5f93251e481f23bf741dde7f59cfc3e315f60b32b63f215a2d7bb8944/pyppmd-1.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1826cbce9a2c944aa08df79310a7e6d4a61fd20636b6dff64a77ea4bc43da30f", size = 142340, upload-time = "2025-11-27T22:07:58.49Z" }, - { url = "https://files.pythonhosted.org/packages/34/88/38d36c1394d5e331db9708dae08863c87c059bd5b6e43b20234be02a0503/pyppmd-1.3.1-cp312-cp312-win32.whl", hash = "sha256:d3ff96671319318d941dd34300d641745048e8a3251b077bddf98652d6ddc513", size = 42102, upload-time = "2025-11-27T22:08:00.124Z" }, - { url = "https://files.pythonhosted.org/packages/ee/29/1398c6f67dfb66367babeed2980caee837d0a488705e3dff7ff159e017e7/pyppmd-1.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:c8c1ad39e7ebde71bf5a54cf61f489bf4790f1dd0beb70dc2e8f5ad3329d7ca7", size = 46957, upload-time = "2025-11-27T22:08:01.587Z" }, - { url = "https://files.pythonhosted.org/packages/d2/41/ee3193c16472a5a1c5f1965abb8fa87a7ad455c39688e9a0c2d87d6a7027/pyppmd-1.3.1-cp312-cp312-win_arm64.whl", hash = "sha256:391b2bf76d7dc45b343781754d0b734dcbf539b92667986a343f5488c4bf9ca0", size = 45214, upload-time = "2025-11-27T22:08:02.721Z" }, - { url = "https://files.pythonhosted.org/packages/f0/01/7cc3854b0e1304b90d2435e946db5e1c42e103adf840a68400002fc838b4/pyppmd-1.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:4b4edb3e9619fd0bc39c1a07eb03e8731db833a93b23134f36c7ef581a94b37a", size = 77800, upload-time = "2025-11-27T22:08:03.856Z" }, - { url = "https://files.pythonhosted.org/packages/dd/02/caf6305224b9432ea7373670d101392f620c1ce741d6f95458b1fb9a16a4/pyppmd-1.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b8b5c813e462c91048b88e2adfbcc0c69f2c905f70097001d32066f86f675bd4", size = 48195, upload-time = "2025-11-27T22:08:05.323Z" }, - { url = "https://files.pythonhosted.org/packages/45/82/8c5d3f0f738a3cf5c209d1471efda105a16417c0aaa91a2ad39efb3d4efb/pyppmd-1.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e8d372d9fac382183e0371cf0c2d736b494b1857a1befe98d563342b1205265b", size = 48482, upload-time = "2025-11-27T22:08:06.441Z" }, - { url = "https://files.pythonhosted.org/packages/76/9c/09ab8b4f00473f210284dacf837cae8355ad900f3fd8fd98b2bba12de4fa/pyppmd-1.3.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3b765ae21f7ed2f4ea8f32bfd9e3a4a8d738e73fc8f8dcddec9cbe2c898d60be", size = 142828, upload-time = "2025-11-27T22:08:07.611Z" }, - { url = "https://files.pythonhosted.org/packages/64/fd/673d429df719affa1445611288aab6111c0bc87e51eb4677fe2421a1dd64/pyppmd-1.3.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bd00522ddfcc292304577386b6c217758c0c10e1fb9ce7877ad7d3b7b821a808", size = 144502, upload-time = "2025-11-27T22:08:08.869Z" }, - { url = "https://files.pythonhosted.org/packages/cf/0f/64dad213f56eaf23210ac7d3a5dedb19ad8f186f8b8682f65e7d51d9fa4a/pyppmd-1.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3de62099ff2ca876c2d39bc547bcba6f7b878988663abd782a5bad4edac3bb44", size = 139718, upload-time = "2025-11-27T22:08:10.114Z" }, - { url = "https://files.pythonhosted.org/packages/74/61/bd5dbe8d7374748687d48f0bc44e6b930470e09552b1bbc65ef899ab673e/pyppmd-1.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:011f845de195d60fe973a635a1f4be981b7d80f357a8acb1b2d83bdf5087c808", size = 142578, upload-time = "2025-11-27T22:08:11.388Z" }, - { url = "https://files.pythonhosted.org/packages/42/ae/0af00a9b1cd59b6821eb182413033d5ddbe05dfcde7511e3a6b1a5b83f6d/pyppmd-1.3.1-cp313-cp313-win32.whl", hash = "sha256:7d61bd01f25289b6ae54832db4254602fb0c6d105f6e6bf0aee39b803b698b98", size = 42102, upload-time = "2025-11-27T22:08:13.297Z" }, - { url = "https://files.pythonhosted.org/packages/6c/6d/311d8faca142f39b4d158c94ed7eb237a197d41dd7eb67f53442a7904e04/pyppmd-1.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:df8d84ab72381058a964ba66e5e81ed52dbd0b5ad734a5ef8353452983506098", size = 46962, upload-time = "2025-11-27T22:08:14.759Z" }, - { url = "https://files.pythonhosted.org/packages/bb/42/24b59b6bb73a3fec96c7f81521d146c2ac89ffcb89cf9e848f62e0660381/pyppmd-1.3.1-cp313-cp313-win_arm64.whl", hash = "sha256:124a04aab6936ba011f9ad57067798c7f052fdb1848b0cc4318606eea55475e6", size = 45209, upload-time = "2025-11-27T22:08:15.933Z" }, -] - -[[package]] -name = "pytest" -version = "8.4.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "iniconfig" }, - { name = "packaging" }, - { name = "pluggy" }, - { name = "pygments" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" }, -] - -[[package]] -name = "python-dateutil" -version = "2.9.0.post0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, -] - -[[package]] -name = "python-decouple" -version = "3.8" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e1/97/373dcd5844ec0ea5893e13c39a2c67e7537987ad8de3842fe078db4582fa/python-decouple-3.8.tar.gz", hash = "sha256:ba6e2657d4f376ecc46f77a3a615e058d93ba5e465c01bbe57289bfb7cce680f", size = 9612, upload-time = "2023-03-01T19:38:38.143Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/d4/9193206c4563ec771faf2ccf54815ca7918529fe81f6adb22ee6d0e06622/python_decouple-3.8-py3-none-any.whl", hash = "sha256:d0d45340815b25f4de59c974b855bb38d03151d81b037d9e3f463b0c9f8cbd66", size = 9947, upload-time = "2023-03-01T19:38:36.015Z" }, -] - -[[package]] -name = "python-gitlab" -version = "5.6.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "requests" }, - { name = "requests-toolbelt" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d6/08/d35d0f28549c43611e942f39b6321a7b35c02189d5badceefe601c0207ce/python_gitlab-5.6.0.tar.gz", hash = "sha256:bc531e8ba3e5641b60409445d4919ace68a2c18cb0ec6d48fbced6616b954166", size = 396148, upload-time = "2025-01-28T16:33:39.136Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/5e/2e1ed7145835afaad87664b2f675a1d7b6e1211ad6ecfe57e200ae45f0bd/python_gitlab-5.6.0-py3-none-any.whl", hash = "sha256:68980cd70929fc7f8f06d8a7b09bd046a6b79e1995c19d61249f046005099100", size = 148836, upload-time = "2025-01-28T16:33:36.818Z" }, -] - -[[package]] -name = "python-magic" -version = "0.4.24" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.13'", -] -sdist = { url = "https://files.pythonhosted.org/packages/3a/70/76b185393fecf78f81c12f9dc7b1df814df785f6acb545fc92b016e75a7e/python-magic-0.4.24.tar.gz", hash = "sha256:de800df9fb50f8ec5974761054a708af6e4246b03b4bdaee993f948947b0ebcf", size = 17295, upload-time = "2021-06-03T13:49:24.116Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d3/99/c89223c6547df268596899334ee77b3051f606077317023617b1c43162fb/python_magic-0.4.24-py2.py3-none-any.whl", hash = "sha256:4fec8ee805fea30c07afccd1592c0f17977089895bdfaae5fec870a84e997626", size = 12785, upload-time = "2021-06-03T13:49:22.828Z" }, -] - -[[package]] -name = "python-magic" -version = "0.4.27" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.13'", -] -sdist = { url = "https://files.pythonhosted.org/packages/da/db/0b3e28ac047452d079d375ec6798bf76a036a08182dbb39ed38116a49130/python-magic-0.4.27.tar.gz", hash = "sha256:c1ba14b08e4a5f5c31a302b7721239695b2f0f058d125bd5ce1ee36b9d9d3c3b", size = 14677, upload-time = "2022-06-07T20:16:59.508Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6c/73/9f872cb81fc5c3bb48f7227872c28975f998f3e7c2b1c16e95e6432bbb90/python_magic-0.4.27-py2.py3-none-any.whl", hash = "sha256:c212960ad306f700aa0d01e5d7a325d20548ff97eb9920dcd29513174f0294d3", size = 13840, upload-time = "2022-06-07T20:16:57.763Z" }, -] - -[[package]] -name = "python-semantic-release" -version = "9.21.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "click-option-group" }, - { name = "deprecated" }, - { name = "dotty-dict" }, - { name = "gitpython" }, - { name = "importlib-resources" }, - { name = "jinja2" }, - { name = "pydantic" }, - { name = "python-gitlab" }, - { name = "requests" }, - { name = "rich" }, - { name = "shellingham" }, - { name = "tomlkit" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1d/2b/8395fa3b7bd31fd4d0a4181ad660b2f8ee14961334945d3bfc6e73dec21a/python_semantic_release-9.21.2.tar.gz", hash = "sha256:84d4f90f77528bcc0cbdcf3bc262172e3a4eeb7670b82fa45b4c859455e9cdf2", size = 308976, upload-time = "2026-07-04T01:11:42.085Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/95/9059bf101c4147dd18c65f9323b57c2a3e1e152ff12a6a316ab7562d79bb/python_semantic_release-9.21.2-py3-none-any.whl", hash = "sha256:856b13c025aadf52180d5704477c2e3582fc0d5f6b2746641d3006b9eed4a0b4", size = 132839, upload-time = "2026-07-04T01:11:40.502Z" }, -] - -[[package]] -name = "python-slugify" -version = "9.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "text-unidecode" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d8/ca/5740963aa82f2c9dd025d71f1b6cce2159545f9e60dcb86a447d1cf92252/python_slugify-9.1.0.tar.gz", hash = "sha256:3f02e8a0639c61e37eca5a783aae09112796d15d331ee3d5372241b61ee05f1c", size = 63567, upload-time = "2026-09-18T22:30:42.72Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ae/f1/e450f6f6eb1217a6dc5f015589a21566839297920304961a7c2230477837/python_slugify-9.1.0-py3-none-any.whl", hash = "sha256:ab2d1d0e7ad5fa46b3756f0f3fcfb37d6d5baa006ccd1f22c2481a6ab53b8c12", size = 15641, upload-time = "2026-09-18T22:30:41.612Z" }, -] - -[[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/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" }, -] - -[[package]] -name = "referencing" -version = "0.37.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "attrs" }, - { name = "rpds-py" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload-time = "2025-10-13T15:30:48.871Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" }, -] - -[[package]] -name = "requests" -version = "2.34.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "charset-normalizer" }, - { name = "idna" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" }, -] - -[[package]] -name = "requests-file" -version = "3.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3c/f8/5dc70102e4d337063452c82e1f0d95e39abfe67aa222ed8a5ddeb9df8de8/requests_file-3.0.1.tar.gz", hash = "sha256:f14243d7796c588f3521bd423c5dea2ee4cc730e54a3cac9574d78aca1272576", size = 6967, upload-time = "2025-10-20T18:56:42.279Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e1/d5/de8f089119205a09da657ed4784c584ede8381a0ce6821212a6d4ca47054/requests_file-3.0.1-py2.py3-none-any.whl", hash = "sha256:d0f5eb94353986d998f80ac63c7f146a307728be051d4d1cd390dbdb59c10fa2", size = 4514, upload-time = "2025-10-20T18:56:41.184Z" }, -] - -[[package]] -name = "requests-toolbelt" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", size = 206888, upload-time = "2023-05-01T04:11:33.229Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", size = 54481, upload-time = "2023-05-01T04:11:28.427Z" }, -] - -[[package]] -name = "rich" -version = "14.3.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, - { name = "pygments" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e9/67/cae617f1351490c25a4b8ac3b8b63a4dda609295d8222bad12242dfdc629/rich-14.3.4.tar.gz", hash = "sha256:817e02727f2b25b40ef56f5aa2217f400c8489f79ca8f46ea2b70dd5e14558a9", size = 230524, upload-time = "2026-04-11T02:57:45.419Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/76/6d163cfac87b632216f71879e6b2cf17163f773ff59c00b5ff4900a80fa3/rich-14.3.4-py3-none-any.whl", hash = "sha256:07e7adb4690f68864777b1450859253bed81a99a31ac321ac1817b2313558952", size = 310480, upload-time = "2026-04-11T02:57:47.484Z" }, -] - -[[package]] -name = "roman-numerals" -version = "4.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ae/f9/41dc953bbeb056c17d5f7a519f50fdf010bd0553be2d630bc69d1e022703/roman_numerals-4.1.0.tar.gz", hash = "sha256:1af8b147eb1405d5839e78aeb93131690495fe9da5c91856cb33ad55a7f1e5b2", size = 9077, upload-time = "2025-12-17T18:25:34.381Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/54/6f679c435d28e0a568d8e8a7c0a93a09010818634c3c3907fc98d8983770/roman_numerals-4.1.0-py3-none-any.whl", hash = "sha256:647ba99caddc2cc1e55a51e4360689115551bf4476d90e8162cf8c345fe233c7", size = 7676, upload-time = "2025-12-17T18:25:33.098Z" }, -] - -[[package]] -name = "roman-numerals-py" -version = "4.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "roman-numerals" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/cb/b5/de96fca640f4f656eb79bbee0e79aeec52e3e0e359f8a3e6a0d366378b64/roman_numerals_py-4.1.0.tar.gz", hash = "sha256:f5d7b2b4ca52dd855ef7ab8eb3590f428c0b1ea480736ce32b01fef2a5f8daf9", size = 4274, upload-time = "2025-12-17T18:25:41.153Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/27/2c/daca29684cbe9fd4bc711f8246da3c10adca1ccc4d24436b17572eb2590e/roman_numerals_py-4.1.0-py3-none-any.whl", hash = "sha256:553114c1167141c1283a51743759723ecd05604a1b6b507225e91dc1a6df0780", size = 4547, upload-time = "2025-12-17T18:25:40.136Z" }, -] - -[[package]] -name = "rpds-py" -version = "2026.6.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/aa/2a/9618a122aeb2a169a28b03889a2995fe297588964333d4a7d67bdf46e147/rpds_py-2026.6.3.tar.gz", hash = "sha256:1cebd1337c242e4ec2293e541f712b2da849b29f48f0c293684b71c0632625d4", size = 64051, upload-time = "2026-06-30T07:17:53.009Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5c/be/2e8974163072e7bab7df1a5acd54c4498e75e35d6d18b864d3a9d5dadc92/rpds_py-2026.6.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a0811d33247c3d6128a3001d763f2aa056bb3425204335400ac54f89eec3a0d0", size = 343691, upload-time = "2026-06-30T07:15:14.96Z" }, - { url = "https://files.pythonhosted.org/packages/a4/73/319dfa745dd668efe89309141ded489126461fcecd2b8f3a3cda185129b6/rpds_py-2026.6.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:538949e262e46caa31ac01bdb3c1e8f642622922cacbabbae6a8445d9dc33eaf", size = 338542, upload-time = "2026-06-30T07:15:16.267Z" }, - { url = "https://files.pythonhosted.org/packages/21/63/4239893be1c4d09b709b1a8f6be4188f0870084ff547f46606b8a75f1b03/rpds_py-2026.6.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55927d532399c2c646100ff7feb48eaa940ad70f42cd68e1328f3ded9f81ca24", size = 368180, upload-time = "2026-06-30T07:15:17.62Z" }, - { url = "https://files.pythonhosted.org/packages/1c/ca/9c5de382225234ceb37b1844ebdb140db12b2a278bb9efe2fcd19f6c82ce/rpds_py-2026.6.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f56f1695bc5c0871cbc33dc0130fcf503aab0c57dcc5a6700a4f49eba4f2652e", size = 375067, upload-time = "2026-06-30T07:15:18.952Z" }, - { url = "https://files.pythonhosted.org/packages/87/dc/863f69d1bf04ade34b7fe0d59b9fdf6f0135fe2d7cbca74f1d665589559d/rpds_py-2026.6.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:270b293dae9058fc9fcedab50f13cebf46fb8ed1d1d54e0521a9da5d6b211975", size = 490509, upload-time = "2026-06-30T07:15:20.434Z" }, - { url = "https://files.pythonhosted.org/packages/ce/ef/eac16a12048b45ec7c7fa94f2be3438a5f26bf9cc8580b18a1cfd609b7f6/rpds_py-2026.6.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:127565fead0a10943b282957bd5447804ff3160ad79f2ad2635e6d249e380680", size = 382754, upload-time = "2026-06-30T07:15:21.831Z" }, - { url = "https://files.pythonhosted.org/packages/04/8f/d2f3f532616be4d06c316ef119683e832bd3d41e112bf3a88f4151c95b17/rpds_py-2026.6.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ecabd69db66de867690f9797f2f8fa27ba501bbc24540cbdbdc649cd15888ba6", size = 366189, upload-time = "2026-06-30T07:15:23.371Z" }, - { url = "https://files.pythonhosted.org/packages/e3/29/41a7b0e98a4b44cd676ab7598419623373eb43b20be68c084935c1a8cf88/rpds_py-2026.6.3-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:58eadac9cd119677b60e1cf8ac4052f35949d71b8a9e5556efccbe82533cf22a", size = 377750, upload-time = "2026-06-30T07:15:24.659Z" }, - { url = "https://files.pythonhosted.org/packages/2e/05/ecda0bec46f9a1565090bcdc941d023f6a25aff85fda28f89f8d19878152/rpds_py-2026.6.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7491ee23305ac3eb59e492b6945881f5cd77a6f731061a3f25b77fd40f9e99a4", size = 395576, upload-time = "2026-06-30T07:15:25.987Z" }, - { url = "https://files.pythonhosted.org/packages/68/a8/6ed52f03ee6cb854ce78785cc9a9a672eb880e83fd7224d471f667d151f1/rpds_py-2026.6.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2c99f7e8ccb3dd6e3e4bfeac657a7b208c9bac8075f4b078c02d7404c34107fa", size = 543807, upload-time = "2026-06-30T07:15:27.356Z" }, - { url = "https://files.pythonhosted.org/packages/8f/d6/156c0d3eea27ba09b92562ba2364ba124c0a061b199e17eac637cd25a5e2/rpds_py-2026.6.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:62698275682bf121181861295c9181e789030a2d516071f5b8f3c23c170cd0fc", size = 611187, upload-time = "2026-06-30T07:15:28.931Z" }, - { url = "https://files.pythonhosted.org/packages/f1/31/774212ed989c62f7f310220089f9b0a3fb8f40f5443d1727abd5d9f52bc9/rpds_py-2026.6.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a214c993455f99a89aaeadc9b21241900037adc9d97203e374d75513c5911822", size = 573030, upload-time = "2026-06-30T07:15:30.553Z" }, - { url = "https://files.pythonhosted.org/packages/c9/50/22f73127a41f1ce4f87fe39aadfb9a126345801c274aa93ae88456249327/rpds_py-2026.6.3-cp312-cp312-win32.whl", hash = "sha256:501f9f04a588d6a09179368c57071301445191767c64e4b52a6aa9871f1ef5ed", size = 202185, upload-time = "2026-06-30T07:15:32.027Z" }, - { url = "https://files.pythonhosted.org/packages/04/3a/f0ee4d4dde9d3b69dedf1b5f74e7a40017046d55052d173e418c6a94f960/rpds_py-2026.6.3-cp312-cp312-win_amd64.whl", hash = "sha256:2c958bf94822e9290a40aaf2a822d4bc5c88099093e3948ad6c571eca9272e5f", size = 220394, upload-time = "2026-06-30T07:15:33.359Z" }, - { url = "https://files.pythonhosted.org/packages/f3/83/3382fe37f809b59f02aac04dbc4e765b480b46ee0227ed516e3bdc4d3dfc/rpds_py-2026.6.3-cp312-cp312-win_arm64.whl", hash = "sha256:22bffe6042b9bcb0822bcd1955ec00e245daf17b4344e4ed8e9551b976b63e96", size = 215753, upload-time = "2026-06-30T07:15:34.778Z" }, - { url = "https://files.pythonhosted.org/packages/a4/9e/b818ee580026ec578138e961027a68820c40afeb1ec8f6819b54fb99e196/rpds_py-2026.6.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3cfe765c1da0072636ca06628261e0ea05688e160d5c8a03e0217c3854037223", size = 343012, upload-time = "2026-06-30T07:15:36.005Z" }, - { url = "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f4d78253f6996be4901669ad25319f842f740eccf4d58e3c7f3dd39e6dde1d8f", size = 338203, upload-time = "2026-06-30T07:15:37.462Z" }, - { url = "https://files.pythonhosted.org/packages/9e/9b/069aa329940f8207615e091f5eedbbd40e1e15eac68a0790fd05ccdf796c/rpds_py-2026.6.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54f45a148e28767bf343d33a684693c70e451c6f4c0e9904709a723fafbdfc1f", size = 367984, upload-time = "2026-06-30T07:15:39.008Z" }, - { url = "https://files.pythonhosted.org/packages/14/db/34c203e4becff3703e4d3bc121842c00b8689197f398161203a880052f4e/rpds_py-2026.6.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:842e7b070435622248c7a2c44ae53fa1440e073cc3023bc919fed570884097a7", size = 374815, upload-time = "2026-06-30T07:15:40.253Z" }, - { url = "https://files.pythonhosted.org/packages/ee/7d/8071067d2cc453d916ad836e828c943f575e8a44612537759002a1e07381/rpds_py-2026.6.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8020133a74bd81b4572dd8e4be028a6b1ebcd70e6726edc3918008c08bee6ee6", size = 490545, upload-time = "2026-06-30T07:15:41.729Z" }, - { url = "https://files.pythonhosted.org/packages/a3/42/da06c5aa8f0484ff07f270787434204d9f4535e2f8c3b51ed402267e63c3/rpds_py-2026.6.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cdc7e35386f3847df728fbcb5e887e2d79c19e2fa1eba9e51b6621d23e3243af", size = 382828, upload-time = "2026-06-30T07:15:43.327Z" }, - { url = "https://files.pythonhosted.org/packages/57/d7/fe978efc2ae50abe48eb7464668ea99f53c010c60aeebb7b35ad27f23661/rpds_py-2026.6.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acac386b453c2516111b50985d60ce46e7fadb5ea71ae7b25f4c946935bf27cf", size = 365678, upload-time = "2026-06-30T07:15:44.992Z" }, - { url = "https://files.pythonhosted.org/packages/69/9d/1d8922e1990b2a6eb532b6ff53d3e73d2b3bbffc84116c75826bee73dfc6/rpds_py-2026.6.3-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:425560c6fa0415f27261727bb20bd097568485e5eb0c121f1949417d1c516885", size = 377811, upload-time = "2026-06-30T07:15:46.523Z" }, - { url = "https://files.pythonhosted.org/packages/b1/3d/198dceafb4fb034a6a47347e1b0735d34e0bd4a50be4e898d408ee66cb14/rpds_py-2026.6.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a550fb4950a06dde3beb4721f5ad4b25bf4513784665b0a8522c792e2bd822a4", size = 395382, upload-time = "2026-06-30T07:15:47.955Z" }, - { url = "https://files.pythonhosted.org/packages/1f/f1/13968e49655d40b6b19d8b9140296bbc6f1d86b3f0f6c346cf9f1adddf4b/rpds_py-2026.6.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4f4bca01b63096f606e095734dd56e74e175f94cfbf24ff3d63281cec61f7bb7", size = 543832, upload-time = "2026-06-30T07:15:49.33Z" }, - { url = "https://files.pythonhosted.org/packages/ac/ab/289bcb1b90bd3e40a2900c561fa0e2087345ecbb094f0b870f2345142b7c/rpds_py-2026.6.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ccffae9a092a00deb7efd545fe5e2c33c33b88e7c054337e9a74c179347d0b7d", size = 611011, upload-time = "2026-06-30T07:15:50.847Z" }, - { url = "https://files.pythonhosted.org/packages/1e/16/5043105e679436ccfbc8e5e0dd2d663ed18a8b8113515fd06a5e5d77c83e/rpds_py-2026.6.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1cf01971c4f2c5553b772a542e4aaf191789cd331bc2cd4ff0e6e65ba49e1e97", size = 572431, upload-time = "2026-06-30T07:15:52.394Z" }, - { url = "https://files.pythonhosted.org/packages/85/ed/adab103321c0a6565d5ae1c2998349bc3ee175b82ccc5ae8fc04cc413075/rpds_py-2026.6.3-cp313-cp313-win32.whl", hash = "sha256:8c3d1e9c15b9d51ca0391e13da1a25a0a4df3c58a37c9dc368e0736cf7f69df0", size = 201710, upload-time = "2026-06-30T07:15:53.894Z" }, - { url = "https://files.pythonhosted.org/packages/7b/ed/a03b09668e74e5dabbf2e211f6468e1820c0552f7b0500082da31841bf7b/rpds_py-2026.6.3-cp313-cp313-win_amd64.whl", hash = "sha256:9250a9a0a6fd4648b3f868da8d91a4c52b5811a62df58e753d50ae4454a36f80", size = 219454, upload-time = "2026-06-30T07:15:55.25Z" }, - { url = "https://files.pythonhosted.org/packages/27/17/b8642c12930b71bc2b25831f6708ccf0f75abcd11883932ec9ce54ba3a78/rpds_py-2026.6.3-cp313-cp313-win_arm64.whl", hash = "sha256:900a67df3fd1660b035a4761c4ce73c382ea6b35f90f9863c36c6fd8bf8b09bb", size = 215063, upload-time = "2026-06-30T07:15:56.573Z" }, -] - -[[package]] -name = "ruamel-yaml" -version = "0.19.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c7/3b/ebda527b56beb90cb7652cb1c7e4f91f48649fbcd8d2eb2fb6e77cd3329b/ruamel_yaml-0.19.1.tar.gz", hash = "sha256:53eb66cd27849eff968ebf8f0bf61f46cdac2da1d1f3576dd4ccee9b25c31993", size = 142709, upload-time = "2026-01-02T16:50:31.84Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/0c/51f6841f1d84f404f92463fc2b1ba0da357ca1e3db6b7fbda26956c3b82a/ruamel_yaml-0.19.1-py3-none-any.whl", hash = "sha256:27592957fedf6e0b62f281e96effd28043345e0e66001f97683aa9a40c667c93", size = 118102, upload-time = "2026-01-02T16:50:29.201Z" }, -] - -[[package]] -name = "shellingham" -version = "1.5.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, -] - -[[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 = "smmap" -version = "5.0.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1f/ea/49c993d6dfdd7338c9b1000a0f36817ed7ec84577ae2e52f890d1a4ff909/smmap-5.0.3.tar.gz", hash = "sha256:4d9debb8b99007ae47165abc08670bd74cb74b5227dda7f643eccc4e9eb5642c", size = 22506, upload-time = "2026-03-09T03:43:26.1Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/d4/59e74daffcb57a07668852eeeb6035af9f32cbfd7a1d2511f17d2fe6a738/smmap-5.0.3-py3-none-any.whl", hash = "sha256:c106e05d5a61449cf6ba9a1e650227ecfb141590d2a98412103ff35d89fc7b2f", size = 24390, upload-time = "2026-03-09T03:43:24.361Z" }, -] - -[[package]] -name = "snowballstemmer" -version = "3.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/f8/0a71edf031f03c40db17503cb8ca78a69a171254e568e7db241b0ab57ea1/snowballstemmer-3.1.1.tar.gz", hash = "sha256:e07bbc54a0d798fe6010a12398422e62a8bfbba95c394fd0956ef58cb4d3e260", size = 123314, upload-time = "2026-06-03T00:56:40.194Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4c/07/2ebca9b11fb9be7340a818d8d6f63feaebb146be2c4afbd6061701d6df6e/snowballstemmer-3.1.1-py3-none-any.whl", hash = "sha256:7e207fa178741da09cdee59d3ecec3827ad5f92b1fc5c9ff3755b639f71f5752", size = 104164, upload-time = "2026-06-03T00:56:38.614Z" }, -] - -[[package]] -name = "soupsieve" -version = "2.9.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/69/99/a6ca3beb3ccacb41fb3321d8a60e5566f9e6467601ef8eba6a17e1b89778/soupsieve-2.9.2.tar.gz", hash = "sha256:4a55d8cf158a9c2e587fa4922f1bbb91d68ac829e2d6f25403a85747c71daf74", size = 122445, upload-time = "2026-08-07T00:57:24.801Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/dc/ad025c1ee131eba60c69f4dd5779b18fcf1e6b21a343e2162a84d5d133c7/soupsieve-2.9.2-py3-none-any.whl", hash = "sha256:8089a26fd974ca7a1f30276d3d8492ab266ab15af581642dfe8aa162e0c1c823", size = 37370, upload-time = "2026-08-07T00:57:23.524Z" }, -] - -[[package]] -name = "sphinx" -version = "8.2.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "alabaster" }, - { name = "babel" }, - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "docutils" }, - { name = "imagesize" }, - { name = "jinja2" }, - { name = "packaging" }, - { name = "pygments" }, - { name = "requests" }, - { name = "roman-numerals-py" }, - { name = "snowballstemmer" }, - { name = "sphinxcontrib-applehelp" }, - { name = "sphinxcontrib-devhelp" }, - { name = "sphinxcontrib-htmlhelp" }, - { name = "sphinxcontrib-jsmath" }, - { name = "sphinxcontrib-qthelp" }, - { name = "sphinxcontrib-serializinghtml" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/38/ad/4360e50ed56cb483667b8e6dadf2d3fda62359593faabbe749a27c4eaca6/sphinx-8.2.3.tar.gz", hash = "sha256:398ad29dee7f63a75888314e9424d40f52ce5a6a87ae88e7071e80af296ec348", size = 8321876, upload-time = "2025-03-02T22:31:59.658Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/31/53/136e9eca6e0b9dc0e1962e2c908fbea2e5ac000c2a2fbd9a35797958c48b/sphinx-8.2.3-py3-none-any.whl", hash = "sha256:4405915165f13521d875a8c29c8970800a0141c14cc5416a38feca4ea5d9b9c3", size = 3589741, upload-time = "2025-03-02T22:31:56.836Z" }, -] - -[[package]] -name = "sphinx-book-theme" -version = "1.1.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydata-sphinx-theme" }, - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/89/69/61dfa3b3851610b5f45960737bd99f8c5b2d70ba73f9ac84a527e0c564ae/sphinx_book_theme-1.1.3.tar.gz", hash = "sha256:1f25483b1846cb3d353a6bc61b3b45b031f4acf845665d7da90e01ae0aef5b4d", size = 434230, upload-time = "2024-06-12T14:11:22.128Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2b/80/90574e2e82c955b9c6f6b77f7badb2cf2ef4ef77599e4343cced2d098681/sphinx_book_theme-1.1.3-py3-none-any.whl", hash = "sha256:a554a9a7ac3881979a87a2b10f633aa2a5706e72218a10f71be38b3c9e831ae9", size = 430129, upload-time = "2024-06-12T14:11:20.002Z" }, -] - -[[package]] -name = "sphinx-codelinks" -version = "1.4.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "comment-parser", version = "1.2.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13'" }, - { name = "comment-parser", version = "1.2.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13'" }, - { name = "docutils" }, - { name = "giturlparse" }, - { name = "ignore-python" }, - { name = "jinja2" }, - { name = "jsonschema" }, - { name = "pygments" }, - { name = "sphinx" }, - { name = "sphinx-needs" }, - { name = "tree-sitter" }, - { name = "tree-sitter-bash" }, - { name = "tree-sitter-c-sharp" }, - { name = "tree-sitter-cpp" }, - { name = "tree-sitter-go" }, - { name = "tree-sitter-json" }, - { name = "tree-sitter-python" }, - { name = "tree-sitter-rust" }, - { name = "tree-sitter-yaml" }, - { name = "typer" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/30/ae/bf4b642c72b7d383723ea9ef1830d5fef5d5505165fa83e3ee1c547aea5e/sphinx_codelinks-1.4.0.tar.gz", hash = "sha256:bf8a5f88ad4747f4964d4e4da23999a4608db6a86e4935151c17b56338d6f50d", size = 47372, upload-time = "2026-07-30T16:09:57.83Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/28/52/95e8e7020619e8750fbb6ebfa4470d6c5ff2d0adebd37fcbc777065f510b/sphinx_codelinks-1.4.0-py3-none-any.whl", hash = "sha256:5cdc712a327b6ba09ea56836392cc750beaf157a342f0853ee0a773b887a7534", size = 54875, upload-time = "2026-07-30T16:09:56.623Z" }, -] - -[[package]] -name = "sphinx-copybutton" -version = "0.5.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fc/2b/a964715e7f5295f77509e59309959f4125122d648f86b4fe7d70ca1d882c/sphinx-copybutton-0.5.2.tar.gz", hash = "sha256:4cf17c82fb9646d1bc9ca92ac280813a3b605d8c421225fd9913154103ee1fbd", size = 23039, upload-time = "2023-04-14T08:10:22.998Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/48/1ea60e74949eecb12cdd6ac43987f9fd331156388dcc2319b45e2ebb81bf/sphinx_copybutton-0.5.2-py3-none-any.whl", hash = "sha256:fb543fd386d917746c9a2c50360c7905b605726b9355cd26e9974857afeae06e", size = 13343, upload-time = "2023-04-14T08:10:20.844Z" }, -] - -[[package]] -name = "sphinx-data-viewer" -version = "0.1.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/71/3a/7aeeb805327af5b0e6f072312f9bc660615045e791a5a8f7258276fdddd1/sphinx_data_viewer-0.1.5.tar.gz", hash = "sha256:a7d5e58613562bb745380bfe61ca8b69997998167fd6fa9aea55606c9a4b17e4", size = 103260, upload-time = "2024-08-28T10:34:21.427Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/57/60/5e902d53a5eb3ec7166a8eda602bd78d4b8671a73917567edc8f13a3b366/sphinx_data_viewer-0.1.5-py3-none-any.whl", hash = "sha256:b74b1d304c505c464d07c7b225ed0d84ea02dcc88bc1c49cdad7c2275fbbdad4", size = 8215, upload-time = "2024-08-28T10:34:20.136Z" }, -] - -[[package]] -name = "sphinx-design" -version = "0.6.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2b/69/b34e0cb5336f09c6866d53b4a19d76c227cdec1bbc7ac4de63ca7d58c9c7/sphinx_design-0.6.1.tar.gz", hash = "sha256:b44eea3719386d04d765c1a8257caca2b3e6f8421d7b3a5e742c0fd45f84e632", size = 2193689, upload-time = "2024-08-02T13:48:44.277Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/43/65c0acbd8cc6f50195a3a1fc195c404988b15c67090e73c7a41a9f57d6bd/sphinx_design-0.6.1-py3-none-any.whl", hash = "sha256:b11f37db1a802a183d61b159d9a202314d4d2fe29c163437001324fe2f19549c", size = 2215338, upload-time = "2024-08-02T13:48:42.106Z" }, -] - -[[package]] -name = "sphinx-mounts" -version = "0.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "ignore-python" }, - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ed/06/85e09e90824dbf9b81c4f60fe156855d13249c1f1f7b208452b75d8fdc34/sphinx_mounts-0.2.0.tar.gz", hash = "sha256:7c19e867b463bccbff35281e2c6c20dfaa75d4fa88eef6abe97c9c371df6914b", size = 98441, upload-time = "2026-08-27T11:42:44.383Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c4/4c/c92fe023dec5204dae85690fc110b47d0c6a0fe9e57c2f8b8d82228ef168/sphinx_mounts-0.2.0-py3-none-any.whl", hash = "sha256:9e43cba60834bb648a7d3f0f43bb3fbbf9743e69933a89081a90a30d6d42d230", size = 100201, upload-time = "2026-08-27T11:42:43.045Z" }, -] - -[[package]] -name = "sphinx-needs" -version = "8.5.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jsonschema-rs" }, - { name = "minijinja" }, - { name = "requests" }, - { name = "requests-file" }, - { name = "sphinx" }, - { name = "sphinx-data-viewer" }, - { name = "sphinxcontrib-jquery" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a8/c2/9db8259372467a85da7d07aa9f642d292f56feadebb37caab73683bbcfed/sphinx_needs-8.5.0.tar.gz", hash = "sha256:42d327baaf39f5041f692cb85609ef7023c0a73b688cde5803db444e577bb63d", size = 28245371, upload-time = "2026-09-03T11:42:25.929Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/02/96/e0a0b6fdf37460b7aaf8fb887922138aa23bbef7635ddaf09fb64823927a/sphinx_needs-8.5.0-py3-none-any.whl", hash = "sha256:aa7548d1ec33cd66cd0223cf8d5c0a934dc4c67d67ad471b5351b817d5f02750", size = 2767023, upload-time = "2026-09-03T11:42:23.717Z" }, -] - -[[package]] -name = "sphinx-new-tab-link" -version = "0.8.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "sphinx" }, - { name = "sphinxcontrib-extdevhelper-kasane" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d2/b9/ee505f904abefa6b574736c93813275a22821933cf2293c83893107eecb6/sphinx_new_tab_link-0.8.2.tar.gz", hash = "sha256:8a339fbfcb1712db8eb3d503c61b86da11a52f1216bd308d6f6dcec6139dd8ea", size = 7820, upload-time = "2026-08-26T13:08:21.037Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/65/67/ff27727d2a27dcd8e7c5a3fc27102aacd2063dbb33364d4ad245bd915266/sphinx_new_tab_link-0.8.2-py3-none-any.whl", hash = "sha256:c347d2a228d24f522d8b2c7e9aa453fcea87cfc0a98f50617a4dac702e9e3f9f", size = 6154, upload-time = "2026-08-26T13:08:19.713Z" }, -] - -[[package]] -name = "sphinx-test-reports" -version = "1.4.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "lxml" }, - { name = "packaging" }, - { name = "sphinx" }, - { name = "sphinx-needs" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/67/e1/1e1fe898f7ec7ce651ca8738548459a721fdb9d170c4a96f3faccdce9cb0/sphinx_test_reports-1.4.0.tar.gz", hash = "sha256:8a7918946453802380a352b4685f3bdb59efd98cb026921145381c5f558c0a4b", size = 20125, upload-time = "2026-06-16T19:58:05.682Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/b3/283af1e4ad11c88aee669cc170849b028170ec56b6bb6e24e62db3fbdae6/sphinx_test_reports-1.4.0-py3-none-any.whl", hash = "sha256:1ac7af2bc437a4ff3da580d8f7b49eef8f534d4973b8880880833751fa96a794", size = 27336, upload-time = "2026-06-16T19:58:04.399Z" }, -] - -[[package]] -name = "sphinxcontrib-applehelp" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ba/6e/b837e84a1a704953c62ef8776d45c3e8d759876b4a84fe14eba2859106fe/sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", size = 20053, upload-time = "2024-07-29T01:09:00.465Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5", size = 119300, upload-time = "2024-07-29T01:08:58.99Z" }, -] - -[[package]] -name = "sphinxcontrib-datatemplates" -version = "0.11.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "defusedxml" }, - { name = "pyyaml" }, - { name = "sphinx" }, - { name = "sphinxcontrib-runcmd" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b9/9e/8ac54a6a3e7a00339f417568899b64a0c0d622429db73cc1a28c8122c8e2/sphinxcontrib.datatemplates-0.11.0.tar.gz", hash = "sha256:793222e803430076341509cc167f8d715830b05e418c885313101d60fd442557", size = 30996, upload-time = "2023-12-21T14:59:10.199Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d4/8d/7a7dd95ad1eedec8dc770570c8b1f3dc1d13357383635607b6629ccf329c/sphinxcontrib.datatemplates-0.11.0-py3-none-any.whl", hash = "sha256:88d02f5edab32b88211ebb72a90553e3676a5737877bad1de412f84058ac282e", size = 12493, upload-time = "2023-12-21T14:59:07.96Z" }, -] - -[[package]] -name = "sphinxcontrib-devhelp" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f6/d2/5beee64d3e4e747f316bae86b55943f51e82bb86ecd325883ef65741e7da/sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", size = 12967, upload-time = "2024-07-29T01:09:23.417Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2", size = 82530, upload-time = "2024-07-29T01:09:21.945Z" }, -] - -[[package]] -name = "sphinxcontrib-extdevhelper-kasane" -version = "0.2.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ec/18/ac3c641c56ea92a66c311353833e004884560fb67545055ec3c2829855db/sphinxcontrib_extdevhelper_kasane-0.2.1.tar.gz", hash = "sha256:97576f7f09216bc57e54d44a1e92091bafb56cfa90dc26dad7508df158edbc6f", size = 4514, upload-time = "2025-10-08T12:30:23.574Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/52/d513a1fa3d6d66564d1f5f442d085def8c3eb19f695d2e7fc5e2f0ac1bdb/sphinxcontrib_extdevhelper_kasane-0.2.1-py3-none-any.whl", hash = "sha256:dfa63809d1c4b3cab62aae74854dcb1a2c7d797cf52bb496e9806d5af032cdf9", size = 3936, upload-time = "2025-10-08T12:30:22.337Z" }, -] - -[[package]] -name = "sphinxcontrib-htmlhelp" -version = "2.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/93/983afd9aa001e5201eab16b5a444ed5b9b0a7a010541e0ddfbbfd0b2470c/sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9", size = 22617, upload-time = "2024-07-29T01:09:37.889Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", size = 98705, upload-time = "2024-07-29T01:09:36.407Z" }, -] - -[[package]] -name = "sphinxcontrib-jquery" -version = "4.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/de/f3/aa67467e051df70a6330fe7770894b3e4f09436dea6881ae0b4f3d87cad8/sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a", size = 122331, upload-time = "2023-03-14T15:01:01.944Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/85/749bd22d1a68db7291c89e2ebca53f4306c3f205853cf31e9de279034c3c/sphinxcontrib_jquery-4.1-py2.py3-none-any.whl", hash = "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae", size = 121104, upload-time = "2023-03-14T15:01:00.356Z" }, -] - -[[package]] -name = "sphinxcontrib-jsmath" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787, upload-time = "2019-01-21T16:10:16.347Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071, upload-time = "2019-01-21T16:10:14.333Z" }, -] - -[[package]] -name = "sphinxcontrib-mermaid" -version = "2.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jinja2" }, - { name = "pyyaml" }, - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/8c/87/06537dff20aa57df2d0f2afa87edff4afa85dec6f57f03f7acc24f83ff88/sphinxcontrib_mermaid-2.1.1.tar.gz", hash = "sha256:f8d7f1b2f0ad69b7ebdd5cbf532fb4ee107893b5373bc2d0e9634089c0b2cfee", size = 22353, upload-time = "2026-09-01T16:10:23.671Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/50/6a/5bf2222b8084c7a7bc3ec23d470c91e3e03e82e4ce0bbacaa61f456ce7c1/sphinxcontrib_mermaid-2.1.1-py3-none-any.whl", hash = "sha256:3b9ac1a8e0b5154dec3c0acf9b5c54dd9ba58540e416f20858c300814c25648f", size = 16368, upload-time = "2026-09-01T16:10:22.377Z" }, -] - -[[package]] -name = "sphinxcontrib-plantuml" -version = "0.31" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/08/8f/f26dd61b92176c4cba6b7898ca2875e7dfc29263d8e1b3b63d6acf81434f/sphinxcontrib_plantuml-0.31.tar.gz", hash = "sha256:fd74752f8ea070e641c3f8a402fccfa1d4a4056e0967b56033d2a76282d9f956", size = 15736, upload-time = "2025-09-03T11:11:35.028Z" } - -[[package]] -name = "sphinxcontrib-qthelp" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/68/bc/9104308fc285eb3e0b31b67688235db556cd5b0ef31d96f30e45f2e51cae/sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", size = 17165, upload-time = "2024-07-29T01:09:56.435Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb", size = 88743, upload-time = "2024-07-29T01:09:54.885Z" }, -] - -[[package]] -name = "sphinxcontrib-runcmd" -version = "0.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a2/03/6eb30814c9839f36131284a46ec9fc39d7bd356078648bc7125d5d1c05e8/sphinxcontrib-runcmd-0.2.0.tar.gz", hash = "sha256:3551c389d9c5fe82d693c7222feb9658b1a1a5a1abcb0063e8385e5528c64c76", size = 5376, upload-time = "2018-11-08T20:19:34.32Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/83/d9/67a79080b5d9fcb367470af9e525a9c53122e95744665de09462dcd676d8/sphinxcontrib_runcmd-0.2.0-py2.py3-none-any.whl", hash = "sha256:7b739b68e27210b4c7c12ba16e5b3da7b313c49991401f896d29bea0f0771934", size = 6043, upload-time = "2018-11-08T20:19:33.17Z" }, -] - -[[package]] -name = "sphinxcontrib-serializinghtml" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3b/44/6716b257b0aa6bfd51a1b31665d1c205fb12cb5ad56de752dfa15657de2f/sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d", size = 16080, upload-time = "2024-07-29T01:10:09.332Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072, upload-time = "2024-07-29T01:10:08.203Z" }, -] - -[[package]] -name = "spl-core" -version = "8.9.0" -source = { git = "https://github.com/useblocks/spl-core.git?rev=010727d08b27ca73994772444d25d7bc6e028c31#010727d08b27ca73994772444d25d7bc6e028c31" } -dependencies = [ - { name = "clanguru" }, - { name = "cookiecutter" }, - { name = "gcovr" }, - { name = "hammocking" }, - { name = "junitparser" }, - { name = "kconfiglib" }, - { name = "mlx-traceability" }, - { name = "myst-parser" }, - { name = "py-app-dev" }, - { name = "pydata-sphinx-theme" }, - { name = "pypeline-runner" }, - { name = "pypeline-semantic-release" }, - { name = "sphinx" }, - { name = "sphinx-book-theme" }, - { name = "sphinx-copybutton" }, - { name = "sphinx-design" }, - { name = "sphinx-needs" }, - { name = "sphinx-new-tab-link" }, - { name = "sphinx-test-reports" }, - { name = "sphinxcontrib-datatemplates" }, - { name = "sphinxcontrib-mermaid" }, - { name = "sphinxcontrib-plantuml" }, - { name = "typer" }, -] - -[[package]] -name = "spled" -version = "0.0.1" -source = { virtual = "." } -dependencies = [ - { name = "myst-parser" }, - { name = "object-deps-report" }, - { name = "poks" }, - { name = "pypeline-runner" }, - { name = "pypeline-semantic-release" }, - { name = "pytest" }, - { name = "sphinx-codelinks" }, - { name = "sphinx-mounts" }, - { name = "spl-core" }, -] - -[package.metadata] -requires-dist = [ - { name = "myst-parser", specifier = ">=4.0,<5" }, - { name = "object-deps-report", specifier = ">=0,<1" }, - { name = "poks", specifier = ">=0.9.4,<1" }, - { name = "pypeline-runner", specifier = ">=1.33,<2" }, - { name = "pypeline-semantic-release", specifier = ">=0,<1" }, - { name = "pytest", specifier = ">=8,<9" }, - { name = "sphinx-codelinks", specifier = ">=1.2,<2" }, - { name = "sphinx-mounts", specifier = ">=0.2,<1" }, - { name = "spl-core", git = "https://github.com/useblocks/spl-core.git?rev=010727d08b27ca73994772444d25d7bc6e028c31" }, -] - -[[package]] -name = "text-unidecode" -version = "1.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ab/e2/e9a00f0ccb71718418230718b3d900e71a5d16e701a3dae079a21e9cd8f8/text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93", size = 76885, upload-time = "2019-08-30T21:36:45.405Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a6/a5/c0b6468d3824fe3fde30dbb5e1f687b291608f9473681bbf7dabbf5a87d7/text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8", size = 78154, upload-time = "2019-08-30T21:37:03.543Z" }, -] - -[[package]] -name = "texttable" -version = "1.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1c/dc/0aff23d6036a4d3bf4f1d8c8204c5c79c4437e25e0ae94ffe4bbb55ee3c2/texttable-1.7.0.tar.gz", hash = "sha256:2d2068fb55115807d3ac77a4ca68fa48803e84ebb0ee2340f858107a36522638", size = 12831, upload-time = "2023-10-03T09:48:12.272Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/24/99/4772b8e00a136f3e01236de33b0efda31ee7077203ba5967fcc76da94d65/texttable-1.7.0-py2.py3-none-any.whl", hash = "sha256:72227d592c82b3d7f672731ae73e4d1f88cd8e2ef5b075a7a7f01a23a3743917", size = 10768, upload-time = "2023-10-03T09:48:10.434Z" }, -] - -[[package]] -name = "tomlkit" -version = "0.13.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cc/18/0bbf3884e9eaa38819ebe46a7bd25dcd56b67434402b66a58c4b8e552575/tomlkit-0.13.3.tar.gz", hash = "sha256:430cf247ee57df2b94ee3fbe588e71d362a941ebb545dec29b53961d61add2a1", size = 185207, upload-time = "2025-06-05T07:13:44.947Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bd/75/8539d011f6be8e29f339c42e633aae3cb73bffa95dd0f9adec09b9c58e85/tomlkit-0.13.3-py3-none-any.whl", hash = "sha256:c89c649d79ee40629a9fda55f8ace8c6a1b42deb912b2a8fd8d942ddadb606b0", size = 38901, upload-time = "2025-06-05T07:13:43.546Z" }, -] - -[[package]] -name = "tree-sitter" -version = "0.25.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/66/7c/0350cfc47faadc0d3cf7d8237a4e34032b3014ddf4a12ded9933e1648b55/tree-sitter-0.25.2.tar.gz", hash = "sha256:fe43c158555da46723b28b52e058ad444195afd1db3ca7720c59a254544e9c20", size = 177961, upload-time = "2025-09-25T17:37:59.751Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3c/9e/20c2a00a862f1c2897a436b17edb774e831b22218083b459d0d081c9db33/tree_sitter-0.25.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ddabfff809ffc983fc9963455ba1cecc90295803e06e140a4c83e94c1fa3d960", size = 146941, upload-time = "2025-09-25T17:37:34.813Z" }, - { url = "https://files.pythonhosted.org/packages/ef/04/8512e2062e652a1016e840ce36ba1cc33258b0dcc4e500d8089b4054afec/tree_sitter-0.25.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c0c0ab5f94938a23fe81928a21cc0fac44143133ccc4eb7eeb1b92f84748331c", size = 137699, upload-time = "2025-09-25T17:37:36.349Z" }, - { url = "https://files.pythonhosted.org/packages/47/8a/d48c0414db19307b0fb3bb10d76a3a0cbe275bb293f145ee7fba2abd668e/tree_sitter-0.25.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dd12d80d91d4114ca097626eb82714618dcdfacd6a5e0955216c6485c350ef99", size = 607125, upload-time = "2025-09-25T17:37:37.725Z" }, - { url = "https://files.pythonhosted.org/packages/39/d1/b95f545e9fc5001b8a78636ef942a4e4e536580caa6a99e73dd0a02e87aa/tree_sitter-0.25.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b43a9e4c89d4d0839de27cd4d6902d33396de700e9ff4c5ab7631f277a85ead9", size = 635418, upload-time = "2025-09-25T17:37:38.922Z" }, - { url = "https://files.pythonhosted.org/packages/de/4d/b734bde3fb6f3513a010fa91f1f2875442cdc0382d6a949005cd84563d8f/tree_sitter-0.25.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fbb1706407c0e451c4f8cc016fec27d72d4b211fdd3173320b1ada7a6c74c3ac", size = 631250, upload-time = "2025-09-25T17:37:40.039Z" }, - { url = "https://files.pythonhosted.org/packages/46/f2/5f654994f36d10c64d50a192239599fcae46677491c8dd53e7579c35a3e3/tree_sitter-0.25.2-cp312-cp312-win_amd64.whl", hash = "sha256:6d0302550bbe4620a5dc7649517c4409d74ef18558276ce758419cf09e578897", size = 127156, upload-time = "2025-09-25T17:37:41.132Z" }, - { url = "https://files.pythonhosted.org/packages/67/23/148c468d410efcf0a9535272d81c258d840c27b34781d625f1f627e2e27d/tree_sitter-0.25.2-cp312-cp312-win_arm64.whl", hash = "sha256:0c8b6682cac77e37cfe5cf7ec388844957f48b7bd8d6321d0ca2d852994e10d5", size = 113984, upload-time = "2025-09-25T17:37:42.074Z" }, - { url = "https://files.pythonhosted.org/packages/8c/67/67492014ce32729b63d7ef318a19f9cfedd855d677de5773476caf771e96/tree_sitter-0.25.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0628671f0de69bb279558ef6b640bcfc97864fe0026d840f872728a86cd6b6cd", size = 146926, upload-time = "2025-09-25T17:37:43.041Z" }, - { url = "https://files.pythonhosted.org/packages/4e/9c/a278b15e6b263e86c5e301c82a60923fa7c59d44f78d7a110a89a413e640/tree_sitter-0.25.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f5ddcd3e291a749b62521f71fc953f66f5fd9743973fd6dd962b092773569601", size = 137712, upload-time = "2025-09-25T17:37:44.039Z" }, - { url = "https://files.pythonhosted.org/packages/54/9a/423bba15d2bf6473ba67846ba5244b988cd97a4b1ea2b146822162256794/tree_sitter-0.25.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bd88fbb0f6c3a0f28f0a68d72df88e9755cf5215bae146f5a1bdc8362b772053", size = 607873, upload-time = "2025-09-25T17:37:45.477Z" }, - { url = "https://files.pythonhosted.org/packages/ed/4c/b430d2cb43f8badfb3a3fa9d6cd7c8247698187b5674008c9d67b2a90c8e/tree_sitter-0.25.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b878e296e63661c8e124177cc3084b041ba3f5936b43076d57c487822426f614", size = 636313, upload-time = "2025-09-25T17:37:46.68Z" }, - { url = "https://files.pythonhosted.org/packages/9d/27/5f97098dbba807331d666a0997662e82d066e84b17d92efab575d283822f/tree_sitter-0.25.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d77605e0d353ba3fe5627e5490f0fbfe44141bafa4478d88ef7954a61a848dae", size = 631370, upload-time = "2025-09-25T17:37:47.993Z" }, - { url = "https://files.pythonhosted.org/packages/d4/3c/87caaed663fabc35e18dc704cd0e9800a0ee2f22bd18b9cbe7c10799895d/tree_sitter-0.25.2-cp313-cp313-win_amd64.whl", hash = "sha256:463c032bd02052d934daa5f45d183e0521ceb783c2548501cf034b0beba92c9b", size = 127157, upload-time = "2025-09-25T17:37:48.967Z" }, - { url = "https://files.pythonhosted.org/packages/d5/23/f8467b408b7988aff4ea40946a4bd1a2c1a73d17156a9d039bbaff1e2ceb/tree_sitter-0.25.2-cp313-cp313-win_arm64.whl", hash = "sha256:b3f63a1796886249bd22c559a5944d64d05d43f2be72961624278eff0dcc5cb8", size = 113975, upload-time = "2025-09-25T17:37:49.922Z" }, -] - -[[package]] -name = "tree-sitter-bash" -version = "0.25.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/0e/f0108be910f1eef6499eabce517e79fe3b12057280ed398da67ce2426cba/tree_sitter_bash-0.25.1.tar.gz", hash = "sha256:bfc0bdaa77bc1e86e3c6652e5a6e140c40c0a16b84185c2b63ad7cd809b88f14", size = 419703, upload-time = "2025-12-02T17:01:08.849Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/30/8e/37e7364d9c9c58da89e05c510671d8c45818afd7b31c6939ab72f8dc6c04/tree_sitter_bash-0.25.1-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:0e6235f59e366d220dde7d830196bed597d01e853e44d8ccd1a82c5dd2500acf", size = 194160, upload-time = "2025-12-02T17:00:59.047Z" }, - { url = "https://files.pythonhosted.org/packages/23/bb/2d2cfbb1f89aaeb1ec892624f069d92d058d06bb66f16b9ec9fb5873ab60/tree_sitter_bash-0.25.1-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:f4a34a6504c7c5b2a9b8c5c4065531dea19ca2c35026e706cf2eeeebe2c92512", size = 202659, upload-time = "2025-12-02T17:01:00.275Z" }, - { url = "https://files.pythonhosted.org/packages/25/f0/1bb25519be27460255d3899db677313cfa1e6306988fbf456a3d7e211bbb/tree_sitter_bash-0.25.1-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e76c4cfb20b076552406782b7f8c2a3946835993df0a44df006de54b7030c7dc", size = 230596, upload-time = "2025-12-02T17:01:01.759Z" }, - { url = "https://files.pythonhosted.org/packages/d7/22/9f70bc3d3b942ab9fc0f89c1dc9e087519a3a94f64ae6b7377aae3a7a0f0/tree_sitter_bash-0.25.1-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3f484c4bb8796cde7a87ca351e6116f09653edac0eb3c6d238566359dd28b117", size = 231981, upload-time = "2025-12-02T17:01:02.859Z" }, - { url = "https://files.pythonhosted.org/packages/7a/c3/f1540e42cd41b323c6821e45e52e1aed6ed386209aad52db996f05703963/tree_sitter_bash-0.25.1-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:5e76af6df46d958c7f5b6d5884c9743218e3902a00ccb493ec92728b1084430b", size = 228364, upload-time = "2025-12-02T17:01:03.997Z" }, - { url = "https://files.pythonhosted.org/packages/f7/a0/c3050a6277dfcac8c480f514dc4fe49f3f65f0eac68b4702cbaca2584e85/tree_sitter_bash-0.25.1-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a3332d71c7b7d5f78259b19d02d0ea111fcb82b72712ee4a93aaa5b226d3f0a8", size = 230074, upload-time = "2025-12-02T17:01:05.05Z" }, - { url = "https://files.pythonhosted.org/packages/71/0f/203fe6b27211387f4b9ba8c4a321567ca4ded2624dae6ccdbd2b6e940e17/tree_sitter_bash-0.25.1-cp310-abi3-win_amd64.whl", hash = "sha256:52a6802d9218f86278aa3e8b459c3abdad67eed0fde1f9f13aca5b6c634217a6", size = 195574, upload-time = "2025-12-02T17:01:06.412Z" }, - { url = "https://files.pythonhosted.org/packages/47/75/4ca1a9fabd8fb5aea78cea70f7837ce4dbf2afae115f62051e5fa99cba1c/tree_sitter_bash-0.25.1-cp310-abi3-win_arm64.whl", hash = "sha256:59115057ec2bae319e8082ff29559861045002964c3431ccb0fc92aa4bc9bccb", size = 191196, upload-time = "2025-12-02T17:01:07.486Z" }, -] - -[[package]] -name = "tree-sitter-c-sharp" -version = "0.23.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9f/fb/7e2962bc1901daf264e7ce263b168e0139304a5f8f66c9b2baf20e550f87/tree_sitter_c_sharp-0.23.5.tar.gz", hash = "sha256:2635c7d5ec93e59f2e831b571bed99c4cc68a5d183a0994020aa769e1b990a71", size = 1147914, upload-time = "2026-04-14T16:11:22.441Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/c4/86d8d469400a856757a464a6ac01af97d8cdacbb595e62bdb98bf1e9db90/tree_sitter_c_sharp-0.23.5-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:61e1981cf21b09ee547b9c4c68e64fb4394325f8fc8d5f6d50d41471eba923ea", size = 333658, upload-time = "2026-04-14T16:11:11.288Z" }, - { url = "https://files.pythonhosted.org/packages/c8/13/593c8603f834eaf15082b81e079289fc9f062b4c0ab5b9489134084eec06/tree_sitter_c_sharp-0.23.5-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:a75994a11f6fed3f5b8c36ad6a00e5dc43205bd912c43af3a2a54fdf649664eb", size = 376296, upload-time = "2026-04-14T16:11:12.972Z" }, - { url = "https://files.pythonhosted.org/packages/41/5a/a8855cbb5bbab28adb29c2c7f0e7be5a9f1d21450c13b3c3e613190d9b8c/tree_sitter_c_sharp-0.23.5-cp310-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:aa88a780204cd153c4c1ae2d59c654cee1402212fa0d069823d6d34301587438", size = 358333, upload-time = "2026-04-14T16:11:14.214Z" }, - { url = "https://files.pythonhosted.org/packages/0a/c8/e0f391e343f5424d0627e3b6886c77baeb1249a3f10986be00b0b64ecdab/tree_sitter_c_sharp-0.23.5-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ea38fb095d85d360dc5a0bec2fa605e496228876f798c9e089d5f0e72bcef46", size = 359448, upload-time = "2026-04-14T16:11:15.419Z" }, - { url = "https://files.pythonhosted.org/packages/6f/fc/10f807ac79f928241c5e0d827fdaf91e97dfba662fc7e07d7bd664140ec1/tree_sitter_c_sharp-0.23.5-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:05a9256415e7f24d4f133133794a9c224c60d19f677a04e2f6a94c25090b6d65", size = 358144, upload-time = "2026-04-14T16:11:17.087Z" }, - { url = "https://files.pythonhosted.org/packages/de/2a/6c3e12ef0cf09138717fcc02e1de8b76a3928d1bed65c7e3c2bd3172bcef/tree_sitter_c_sharp-0.23.5-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8636dc70b5a373c35c1036ed5de98e801f2e4d105ae41e2e20b6804c36e3bf33", size = 357525, upload-time = "2026-04-14T16:11:18.214Z" }, - { url = "https://files.pythonhosted.org/packages/2b/e0/bd287b092d611df95a9149117fd27b5947ce75527113d6898a4b4e2c8858/tree_sitter_c_sharp-0.23.5-cp310-abi3-win_amd64.whl", hash = "sha256:41a28cfa3d9ea50f5629e44550a03188c8fbd5079803dfc03554b6fd594b33fa", size = 338756, upload-time = "2026-04-14T16:11:19.661Z" }, - { url = "https://files.pythonhosted.org/packages/7f/fb/114ff43fdd256d0befed32f77c1dadee9517867181c70794571f718ed05c/tree_sitter_c_sharp-0.23.5-cp310-abi3-win_arm64.whl", hash = "sha256:2de4ebf95ddc2e92cd3105c8a8e0e7ec646bc82f52bfaf2f3acec0fa2401ec09", size = 337260, upload-time = "2026-04-14T16:11:20.849Z" }, -] - -[[package]] -name = "tree-sitter-cpp" -version = "0.23.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/2c/4dd63d705a8933543cad9b92ff31be849b164fec91a6eb63475ebc9ce668/tree_sitter_cpp-0.23.4.tar.gz", hash = "sha256:6a59c4cebb1ad1dc2e8d586cf8a72b39d21b8108b7b139d089719e81a339e41d", size = 940358, upload-time = "2024-11-11T06:59:24.934Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b6/ac/11d56670f7b048362db872ca866fd00ba2002a322ab179f047b7c0fb2910/tree_sitter_cpp-0.23.4-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:aacb1759f0efd9dbc25bd8ee88184a340483018869f75412d9c3bc32c039a520", size = 287861, upload-time = "2024-11-11T06:59:15.005Z" }, - { url = "https://files.pythonhosted.org/packages/12/1c/0337c016bdc00a77a3326d12f10ee836401dd28f27db6fd5b7734bfb21ed/tree_sitter_cpp-0.23.4-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:bc3c404d9f0cbd87951213a85440afbf4c31e718f8d907fa9ee12bea4b8d276f", size = 315513, upload-time = "2024-11-11T06:59:16.679Z" }, - { url = "https://files.pythonhosted.org/packages/b3/7b/dd38c049b10ed7fda118b903a1d28a8b55a36b98c30606ef90e8f374c6de/tree_sitter_cpp-0.23.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ccc43ddf1279d5d5a4ef190373f4cb16522801bec4492bcd4754edf2aeba2b7b", size = 334813, upload-time = "2024-11-11T06:59:18.253Z" }, - { url = "https://files.pythonhosted.org/packages/6a/4d/23e390234d2acd351f5563b1079c515d7c1fe13ddb7392cee543be74dda3/tree_sitter_cpp-0.23.4-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:773d2cafc08bbc0f998687fa33f42f378c1a371cdb582870c4d13abb06092706", size = 316110, upload-time = "2024-11-11T06:59:19.823Z" }, - { url = "https://files.pythonhosted.org/packages/32/c7/b94a7e0e803af9d3bd4608fb4f0cfb2e9e233abaf0a38c928bfb0b1a025d/tree_sitter_cpp-0.23.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:247d127f0eb6574b0f6b30c0151e0bd0774e2e7acf9c558bdf9fbb8adc2e80c0", size = 308242, upload-time = "2024-11-11T06:59:21.466Z" }, - { url = "https://files.pythonhosted.org/packages/37/7e/909e52b3dec09c475140b0e175511e275d0d00ba2dbd7c68102d377ae0f6/tree_sitter_cpp-0.23.4-cp39-abi3-win_amd64.whl", hash = "sha256:68606a45bea92669d155399e1239f771a7767d8683cd8f8e30e7d813107030ca", size = 290997, upload-time = "2024-11-11T06:59:22.432Z" }, - { url = "https://files.pythonhosted.org/packages/d4/6a/65435d4d1f4c735be7ffe52d7c2e7b8a7f7c2790343a2719c60c548611c8/tree_sitter_cpp-0.23.4-cp39-abi3-win_arm64.whl", hash = "sha256:712f84f18be94cbe2a148fa4fdf40fcf4a8c25a8f7670efb9f8a47ddec2fc281", size = 288203, upload-time = "2024-11-11T06:59:23.404Z" }, -] - -[[package]] -name = "tree-sitter-go" -version = "0.25.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/05/727308adbbc79bcb1c92fc0ea10556a735f9d0f0a5435a18f59d40f7fd77/tree_sitter_go-0.25.0.tar.gz", hash = "sha256:a7466e9b8d94dda94cae8d91629f26edb2d26166fd454d4831c3bf6dfa2e8d68", size = 93890, upload-time = "2025-08-29T06:20:25.044Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ca/aa/0984707acc2b9bb461fe4a41e7e0fc5b2b1e245c32820f0c83b3c602957c/tree_sitter_go-0.25.0-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b852993063a3429a443e7bd0aa376dd7dd329d595819fabf56ac4cf9d7257b54", size = 47117, upload-time = "2025-08-29T06:20:14.286Z" }, - { url = "https://files.pythonhosted.org/packages/32/16/dd4cb124b35e99239ab3624225da07d4cb8da4d8564ed81d03fcb3a6ba9f/tree_sitter_go-0.25.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:503b81a2b4c31e302869a1de3a352ad0912ccab3df9ac9950197b0a9ceeabd8f", size = 48674, upload-time = "2025-08-29T06:20:17.557Z" }, - { url = "https://files.pythonhosted.org/packages/86/fb/b30d63a08044115d8b8bd196c6c2ab4325fb8db5757249a4ef0563966e2e/tree_sitter_go-0.25.0-cp310-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:04b3b3cb4aff18e74e28d49b716c6f24cb71ddfdd66768987e26e4d0fa812f74", size = 66418, upload-time = "2025-08-29T06:20:18.345Z" }, - { url = "https://files.pythonhosted.org/packages/26/21/d3d88a30ad007419b2c97b3baeeef7431407faf9f686195b6f1cad0aedf9/tree_sitter_go-0.25.0-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:148255aca2f54b90d48c48a9dbb4c7faad6cad310a980b2c5a5a9822057ed145", size = 72006, upload-time = "2025-08-29T06:20:19.14Z" }, - { url = "https://files.pythonhosted.org/packages/cd/d0/0dd6442353ced8a88bbda9e546f4ea29e381b59b5a40b122e5abb586bb6c/tree_sitter_go-0.25.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4d338116cdf8a6c6ff990d2441929b41323ef17c710407abe0993c13417d6aad", size = 70603, upload-time = "2025-08-29T06:20:21.544Z" }, - { url = "https://files.pythonhosted.org/packages/01/e2/ee5e09f63504fc286539535d374d2eaa0e7d489b80f8f744bb3962aff22a/tree_sitter_go-0.25.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5608e089d2a29fa8d2b327abeb2ad1cdb8e223c440a6b0ceab0d3fa80bdeebae", size = 66088, upload-time = "2025-08-29T06:20:22.336Z" }, - { url = "https://files.pythonhosted.org/packages/6e/b6/d9142583374720e79aca9ccb394b3795149a54c012e1dfd80738df2d984e/tree_sitter_go-0.25.0-cp310-abi3-win_amd64.whl", hash = "sha256:30d4ada57a223dfc2c32d942f44d284d40f3d1215ddcf108f96807fd36d53022", size = 48152, upload-time = "2025-08-29T06:20:23.089Z" }, - { url = "https://files.pythonhosted.org/packages/9e/00/9a2638e7339236f5b01622952a4d71c1474dd3783d1982a89555fc1f03b1/tree_sitter_go-0.25.0-cp310-abi3-win_arm64.whl", hash = "sha256:d5d62362059bf79997340773d47cc7e7e002883b527a05cca829c46e40b70ded", size = 46752, upload-time = "2025-08-29T06:20:24.235Z" }, -] - -[[package]] -name = "tree-sitter-json" -version = "0.24.8" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/29/e92df6dca3a6b2ab1c179978be398059817e1173fbacd47e832aaff3446b/tree_sitter_json-0.24.8.tar.gz", hash = "sha256:ca8486e52e2d261819311d35cf98656123d59008c3b7dcf91e61d2c0c6f3120e", size = 8155, upload-time = "2024-11-11T06:05:00.667Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/41/84866232980fb3cf0cff46f5af2dbb9bfa3324b32614c6a9af3d08926b72/tree_sitter_json-0.24.8-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:59ac06c6db1877d0e2076bce54a5fddcdd2fc38ca778905662e80fa9ffcea2ab", size = 8718, upload-time = "2024-11-11T06:04:49.779Z" }, - { url = "https://files.pythonhosted.org/packages/5c/31/102c15948d97b135611d6a995c97a3933c0e9745f25737723977f58e142c/tree_sitter_json-0.24.8-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:62b4c45b561db31436a81a3f037f71ec29049f4fc9bf5269b6ec3ebaaa35a1cd", size = 9163, upload-time = "2024-11-11T06:04:51.275Z" }, - { url = "https://files.pythonhosted.org/packages/28/64/aa44ea2f3d2e76ec086ce83902eb26b2ed0a92d3fd5e2714c9cb007e90d1/tree_sitter_json-0.24.8-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8627f7d375fda9fc193ebee368c453f374f65c2f25c58b6fea4e6b49a7fccbc", size = 17726, upload-time = "2024-11-11T06:04:52.732Z" }, - { url = "https://files.pythonhosted.org/packages/77/08/10001992526670e0d6f24c571b179f0ece90e5e014a4b98a3ce076884f32/tree_sitter_json-0.24.8-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85cca779872f7278f3a74eb38533d34b9c4de4fd548615e3361fa64fe350ad0a", size = 17236, upload-time = "2024-11-11T06:04:54.189Z" }, - { url = "https://files.pythonhosted.org/packages/92/64/908e9e0bd84fe3c81c564115d3bbe0e49b0e152784bbaf153d749d00bbe6/tree_sitter_json-0.24.8-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:deeb45850dcc52990fbb52c80196492a099e3fa3512d928a390a91cf061068cc", size = 16071, upload-time = "2024-11-11T06:04:55.628Z" }, - { url = "https://files.pythonhosted.org/packages/53/df/31daab1eedb445bef208a04fc35428de3afe2b37075fec84d7737e1c69de/tree_sitter_json-0.24.8-cp39-abi3-win_amd64.whl", hash = "sha256:e4849a03cd7197267b2688a4506a90a13568a8e0e8588080bd0212fcb38974e3", size = 11457, upload-time = "2024-11-11T06:04:57.698Z" }, - { url = "https://files.pythonhosted.org/packages/6c/3d/902d2f3125b6b90cebf404b63ca775bc6d82071ccc76c0d10fabfeb2febe/tree_sitter_json-0.24.8-cp39-abi3-win_arm64.whl", hash = "sha256:591e0096c882d12668b88f30d3ca6f85b9db3406910eaaab6afb6b17d65367dd", size = 10174, upload-time = "2024-11-11T06:04:59.309Z" }, -] - -[[package]] -name = "tree-sitter-python" -version = "0.25.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b8/8b/c992ff0e768cb6768d5c96234579bf8842b3a633db641455d86dd30d5dac/tree_sitter_python-0.25.0.tar.gz", hash = "sha256:b13e090f725f5b9c86aa455a268553c65cadf325471ad5b65cd29cac8a1a68ac", size = 159845, upload-time = "2025-09-11T06:47:58.159Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cf/64/a4e503c78a4eb3ac46d8e72a29c1b1237fa85238d8e972b063e0751f5a94/tree_sitter_python-0.25.0-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:14a79a47ddef72f987d5a2c122d148a812169d7484ff5c75a3db9609d419f361", size = 73790, upload-time = "2025-09-11T06:47:47.652Z" }, - { url = "https://files.pythonhosted.org/packages/e6/1d/60d8c2a0cc63d6ec4ba4e99ce61b802d2e39ef9db799bdf2a8f932a6cd4b/tree_sitter_python-0.25.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:480c21dbd995b7fe44813e741d71fed10ba695e7caab627fb034e3828469d762", size = 76691, upload-time = "2025-09-11T06:47:49.038Z" }, - { url = "https://files.pythonhosted.org/packages/aa/cb/d9b0b67d037922d60cbe0359e0c86457c2da721bc714381a63e2c8e35eba/tree_sitter_python-0.25.0-cp310-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:86f118e5eecad616ecdb81d171a36dde9bef5a0b21ed71ea9c3e390813c3baf5", size = 108133, upload-time = "2025-09-11T06:47:50.499Z" }, - { url = "https://files.pythonhosted.org/packages/40/bd/bf4787f57e6b2860f3f1c8c62f045b39fb32d6bac4b53d7a9e66de968440/tree_sitter_python-0.25.0-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be71650ca2b93b6e9649e5d65c6811aad87a7614c8c1003246b303f6b150f61b", size = 110603, upload-time = "2025-09-11T06:47:51.985Z" }, - { url = "https://files.pythonhosted.org/packages/5d/25/feff09f5c2f32484fbce15db8b49455c7572346ce61a699a41972dea7318/tree_sitter_python-0.25.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e6d5b5799628cc0f24691ab2a172a8e676f668fe90dc60468bee14084a35c16d", size = 108998, upload-time = "2025-09-11T06:47:53.046Z" }, - { url = "https://files.pythonhosted.org/packages/75/69/4946da3d6c0df316ccb938316ce007fb565d08f89d02d854f2d308f0309f/tree_sitter_python-0.25.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:71959832fc5d9642e52c11f2f7d79ae520b461e63334927e93ca46cd61cd9683", size = 107268, upload-time = "2025-09-11T06:47:54.388Z" }, - { url = "https://files.pythonhosted.org/packages/ed/a2/996fc2dfa1076dc460d3e2f3c75974ea4b8f02f6bc925383aaae519920e8/tree_sitter_python-0.25.0-cp310-abi3-win_amd64.whl", hash = "sha256:9bcde33f18792de54ee579b00e1b4fe186b7926825444766f849bf7181793a76", size = 76073, upload-time = "2025-09-11T06:47:55.773Z" }, - { url = "https://files.pythonhosted.org/packages/07/19/4b5569d9b1ebebb5907d11554a96ef3fa09364a30fcfabeff587495b512f/tree_sitter_python-0.25.0-cp310-abi3-win_arm64.whl", hash = "sha256:0fbf6a3774ad7e89ee891851204c2e2c47e12b63a5edbe2e9156997731c128bb", size = 74169, upload-time = "2025-09-11T06:47:56.747Z" }, -] - -[[package]] -name = "tree-sitter-rust" -version = "0.24.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b7/87/75cbd22b927267d310f76cca1ab3c1d9d41035dfa3eb9cc95f96ee199440/tree_sitter_rust-0.24.2.tar.gz", hash = "sha256:54fb02a5911e345308b405174465112479f56dc39e3f1e7744d7568595f00db9", size = 339341, upload-time = "2026-03-27T21:08:55.629Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/24/2b2d33af5e27c84a4fde4e8cd2594bb4ab1e1cf48756a9f40dadc84956cc/tree_sitter_rust-0.24.2-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:3620cfd12340efa43082d45df76349ff511893a9c361da2f8d6d51e307020a59", size = 129507, upload-time = "2026-03-27T21:08:47.585Z" }, - { url = "https://files.pythonhosted.org/packages/78/2a/cf39f881a545360b5a86bb1accba1f4acc713daab01fb9edd35b6e84f473/tree_sitter_rust-0.24.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:01a46622735498493f29f3e628a90de95c96a07bfbeb88996243eb986b1cee36", size = 136812, upload-time = "2026-03-27T21:08:48.761Z" }, - { url = "https://files.pythonhosted.org/packages/ca/45/a051bbd3045a61182dde25b93ae9a33d2677c935b16952283e12eaf46051/tree_sitter_rust-0.24.2-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e033c5a93b57c88e0a835880de39fc802909ff69f57aaff6000211c196ea5190", size = 164706, upload-time = "2026-03-27T21:08:49.605Z" }, - { url = "https://files.pythonhosted.org/packages/b5/f6/a5a146df5c0a5daea3ffcd5d7245775fe7f084357770d5a313dd6245ae78/tree_sitter_rust-0.24.2-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9d76d1208c3638b871236090759dfc13d478921320653a6c9da5336e7c58f65a", size = 170310, upload-time = "2026-03-27T21:08:50.424Z" }, - { url = "https://files.pythonhosted.org/packages/95/a8/f85b1ca75e01361ca5f92d226593ca4857cea49551b9f6c8fa6fc08ea917/tree_sitter_rust-0.24.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:87930163a462408c49ab62c667e74029bc26b4cc7123dd1bdc7352215786c64a", size = 168668, upload-time = "2026-03-27T21:08:51.404Z" }, - { url = "https://files.pythonhosted.org/packages/a2/e1/3519f866a4679ca36acd9f5a06a779ecb8a92b18887c5546458d521df557/tree_sitter_rust-0.24.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:da2b86099028fd42c6cd32878b7b16b01f8aac0f7b0e98742b7fa6bc3cf09b89", size = 162403, upload-time = "2026-03-27T21:08:52.588Z" }, - { url = "https://files.pythonhosted.org/packages/34/71/7ef609894dbfe5699eb16f7471f9b8af1d958d8ba3e29c238d7607e8cb47/tree_sitter_rust-0.24.2-cp39-abi3-win_amd64.whl", hash = "sha256:4529c125d928882ddfb879fdc6bc0704913261ecc078b6fa7902559e0daf200d", size = 129422, upload-time = "2026-03-27T21:08:54.031Z" }, - { url = "https://files.pythonhosted.org/packages/b9/d8/050a781172745bc345f98abb7c56e72022ea0790f8e793de981c83c2ef15/tree_sitter_rust-0.24.2-cp39-abi3-win_arm64.whl", hash = "sha256:66ba90f61bd54f4c4f5d30434957daf64507c16b0313df76becb37d63f70a227", size = 128245, upload-time = "2026-03-27T21:08:54.803Z" }, -] - -[[package]] -name = "tree-sitter-yaml" -version = "0.7.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/57/b6/941d356ac70c90b9d2927375259e3a4204f38f7499ec6e7e8a95b9664689/tree_sitter_yaml-0.7.2.tar.gz", hash = "sha256:756db4c09c9d9e97c81699e8f941cb8ce4e51104927f6090eefe638ee567d32c", size = 84882, upload-time = "2025-10-07T14:40:36.071Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/38/29/c0b8dbff302c49ff4284666ffb6f2f21145006843bb4c3a9a85d0ec0b7ae/tree_sitter_yaml-0.7.2-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:7e269ddcfcab8edb14fbb1f1d34eed1e1e26888f78f94eedfe7cc98c60f8bc9f", size = 43898, upload-time = "2025-10-07T14:40:29.486Z" }, - { url = "https://files.pythonhosted.org/packages/18/0d/15a5add06b3932b5e4ce5f5e8e179197097decfe82a0ef000952c8b98216/tree_sitter_yaml-0.7.2-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:0807b7966e23ddf7dddc4545216e28b5a58cdadedcecca86b8d8c74271a07870", size = 44691, upload-time = "2025-10-07T14:40:30.369Z" }, - { url = "https://files.pythonhosted.org/packages/72/92/c4b896c90d08deb8308fadbad2210fdcc4c66c44ab4292eac4e80acb4b61/tree_sitter_yaml-0.7.2-cp310-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f1a5c60c98b6c4c037aae023569f020d0c489fad8dc26fdfd5510363c9c29a41", size = 91430, upload-time = "2025-10-07T14:40:31.16Z" }, - { url = "https://files.pythonhosted.org/packages/89/59/61f1fed31eb6d46ff080b8c0d53658cf29e10263f41ef5fe34768908037a/tree_sitter_yaml-0.7.2-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:88636d19d0654fd24f4f242eaaafa90f6f5ebdba8a62e4b32d251ed156c51a2a", size = 92428, upload-time = "2025-10-07T14:40:31.954Z" }, - { url = "https://files.pythonhosted.org/packages/e3/62/a33a04d19b7f9a0ded780b9c9fcc6279e37c5d00b89b00425bb807a22cc2/tree_sitter_yaml-0.7.2-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1d2e8f0bb14aa4537320952d0f9607eef3021d5aada8383c34ebeece17db1e06", size = 90580, upload-time = "2025-10-07T14:40:33.037Z" }, - { url = "https://files.pythonhosted.org/packages/6c/e7/9525defa7b30792623f56b1fba9bbba361752348875b165b8975b87398fd/tree_sitter_yaml-0.7.2-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:74ca712c50fc9d7dbc68cb36b4a7811d6e67a5466b5a789f19bf8dd6084ef752", size = 90455, upload-time = "2025-10-07T14:40:33.778Z" }, - { url = "https://files.pythonhosted.org/packages/4a/d6/8d1e1ace03db3b02e64e91daf21d1347941d1bbecc606a5473a1a605250d/tree_sitter_yaml-0.7.2-cp310-abi3-win_amd64.whl", hash = "sha256:7587b5ca00fc4f9a548eff649697a3b395370b2304b399ceefa2087d8a6c9186", size = 45514, upload-time = "2025-10-07T14:40:34.562Z" }, - { url = "https://files.pythonhosted.org/packages/d8/c7/dcf3ea1c4f5da9b10353b9af4455d756c92d728a8f58f03c480d3ef0ead5/tree_sitter_yaml-0.7.2-cp310-abi3-win_arm64.whl", hash = "sha256:f63c227b18e7ce7587bce124578f0bbf1f890ac63d3e3cd027417574273642c4", size = 44065, upload-time = "2025-10-07T14:40:35.337Z" }, -] - -[[package]] -name = "typer" -version = "0.26.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "annotated-doc" }, - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "rich" }, - { name = "shellingham" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5e/ed/ef06584ccdd5c410df0837951ecd7e15d9a6144ea1bd4c73cecab1a89891/typer-0.26.7.tar.gz", hash = "sha256:e314a34c617e419c091b2830dda3ea1f257134ff593061a8f5b9717ab8dddb3a", size = 201709, upload-time = "2026-06-03T07:18:06.843Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/24/25/2201973529af2c954de0bb725323c3aaed6d7f0ceee8f550dec9185df013/typer-0.26.7-py3-none-any.whl", hash = "sha256:5c87cfbc5d34491c5346ebf49c23e18d56ccb863268d3a8d592b26087c2f5e58", size = 122456, upload-time = "2026-06-03T07:18:05.732Z" }, -] - -[[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 = "typing-inspection" -version = "0.4.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a3/26/b09b8010994eccc3c09092e6b34058f36a460eea2d4c3e8b910c695975a0/typing_inspection-0.4.4.tar.gz", hash = "sha256:547274fa6b0a561ccf549cc9524b999a578e737d015d8709d021f9d0d13bea47", size = 76928, upload-time = "2026-08-12T12:37:25.997Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl", hash = "sha256:65b8397ba37ccbce054456aaccddfc91e6e3083c92824df348d96ca832f3f147", size = 14750, upload-time = "2026-08-12T12:37:24.648Z" }, -] - -[[package]] -name = "tzdata" -version = "2026.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e4/31/3d74fa778a63b98b7374323befcc0be5ab3bd94afd4096a0124e7379152c/tzdata-2026.4.tar.gz", hash = "sha256:f1b8bd365d8d210c55353f4d7f8d6d8561c0ba50d704b700d195a9424bba0d79", size = 199350, upload-time = "2026-09-12T12:56:03.251Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/bc/8737e8d54cf51106118039b83f485a4783112fab49ea9d044b234978a46e/tzdata-2026.4-py2.py3-none-any.whl", hash = "sha256:c2169a8b0a7a5e9674da5a135ccdfb2b3e671b333ed9fed17b41f73c34476e81", size = 347494, upload-time = "2026-09-12T12:56:01.67Z" }, -] - -[[package]] -name = "urllib3" -version = "2.8.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e3/05/b17359e1cefb4f909b5e40b1b90a496d987258916dbbf88e842c729f510e/urllib3-2.8.0.tar.gz", hash = "sha256:63bf2ead4c879426ebf22ef2a781eeb4aa3b4ae798a0435506f8687fd5bb9b63", size = 458972, upload-time = "2026-09-15T19:29:36.253Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl", hash = "sha256:0cf3cae568d36aa9576b28dfb35f11328f1cb974ca7647d9475ebb86c75ac6e3", size = 135717, upload-time = "2026-09-15T19:29:34.577Z" }, -] - -[[package]] -name = "west" -version = "1.5.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama" }, - { name = "packaging" }, - { name = "pykwalify" }, - { name = "pyyaml" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/54/8e/ddb81e2635e58d156092556934a2cffe245978c91e4a08e11d72591f46e4/west-1.5.0.tar.gz", hash = "sha256:7088fe0e9afe0719ebee95c51c529149f7bcfc919d83a8206d35fa9c683ed0a5", size = 149326, upload-time = "2025-09-23T14:45:52.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c5/1d/e50fb71de492abb549917fdbf13c4a8a8459af9d78a2fa47905804905c36/west-1.5.0-py3-none-any.whl", hash = "sha256:f71411d11ed9ed00847405c6a83600374c2e0cf8676ed5af5d8b572f92c4765a", size = 106991, upload-time = "2025-09-23T14:45:50.661Z" }, -] - -[[package]] -name = "win32-setctime" -version = "1.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b3/8f/705086c9d734d3b663af0e9bb3d4de6578d08f46b1b101c2442fd9aecaa2/win32_setctime-1.2.0.tar.gz", hash = "sha256:ae1fdf948f5640aae05c511ade119313fb6a30d7eabe25fef9764dca5873c4c0", size = 4867, upload-time = "2024-12-07T15:28:28.314Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e1/07/c6fe3ad3e685340704d314d765b7912993bcb8dc198f0e7a89382d37974b/win32_setctime-1.2.0-py3-none-any.whl", hash = "sha256:95d644c4e708aba81dc3704a116d8cbc974d70b3bdb8be1d150e36be6e9d1390", size = 4083, upload-time = "2024-12-07T15:28:26.465Z" }, -] - -[[package]] -name = "wrapt" -version = "2.4.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/42/a6/6375d56c44d590ef24acf0f8f5bf7ed768ff7a510b959306ec412611e90f/wrapt-2.4.1.tar.gz", hash = "sha256:fd6390aab9e8aa40c52eff3c180f098e8d9f5894b1fd4c4fd2c207067b33ed16", size = 164597, upload-time = "2026-09-10T23:12:16.811Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9f/1f/a2f3225c5ecf522684c1d051aea8ce8253f240e55be75826b787777afd6c/wrapt-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7e86fbc2ac8a363ea04abf631fad82720e16b17a25020f32dbe9b24a2ed2b0e3", size = 98890, upload-time = "2026-09-10T23:10:07.876Z" }, - { url = "https://files.pythonhosted.org/packages/68/6c/eb45660fd4d92cce11ec923f55bb2e647a6c18d30e53734eb07a3c530e31/wrapt-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:24389748f0b9d5b67e478fad4fc8b3f1108422ef80716e48eead6cebcebbff08", size = 98742, upload-time = "2026-09-10T23:10:09.236Z" }, - { url = "https://files.pythonhosted.org/packages/a3/4f/17a89a580cb0082e61b8375074d5c9e5d38e4aa83ee19b6174ee472d17c2/wrapt-2.4.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:30d11c289b013bf384ff1a1a6553f150d0b855901708a9bef667a5680f8247c9", size = 236301, upload-time = "2026-09-10T23:10:11.039Z" }, - { url = "https://files.pythonhosted.org/packages/01/ca/4700eb008a34bf02de328806ddde15fc84c8d1e65d3dcafb92a935a50319/wrapt-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9356dbb59199a0e4709de35fa4a1ac1a88ef6da99711a397f5b009233faff326", size = 237805, upload-time = "2026-09-10T23:10:12.594Z" }, - { url = "https://files.pythonhosted.org/packages/75/5d/26c1740299b29e190d5f4b4a99eb001401042a9d9ab338e3f8e1ce140ecb/wrapt-2.4.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8342f332dada211f64b74609e332d727b13315e9a83177f7918bf68c59f815f2", size = 217037, upload-time = "2026-09-10T23:10:14.028Z" }, - { url = "https://files.pythonhosted.org/packages/3a/55/ec72991153a2ae8b40238bc44cec7c3ddf7706ef6e2d314b0c6f5c7febce/wrapt-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2f86e328c482bc5383b4eda5094be0bed3617fc3076aa9225ff1a9eb6372de9b", size = 234659, upload-time = "2026-09-10T23:10:15.384Z" }, - { url = "https://files.pythonhosted.org/packages/51/32/7cfa1e070dcda76ea56a3e252341cba1cd1e9412baf23cd7adfebf1114e2/wrapt-2.4.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:4dc92697444ee380544fbb43c86612d8486529aadf917c22b5524141d4af074c", size = 214590, upload-time = "2026-09-10T23:10:16.744Z" }, - { url = "https://files.pythonhosted.org/packages/79/10/248841cb30107f6f32c53a02662e1c3e0c7c06bea0b8ebfaaee94885dcee/wrapt-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:edd03758a7578526642508b8833d43496fdfba0f64e0025dfca153a7c1777735", size = 225103, upload-time = "2026-09-10T23:10:18.346Z" }, - { url = "https://files.pythonhosted.org/packages/90/02/5b2bf7b35b008a39939a2908e85dba3b867596e535fc9f12ddf3ba1fcaf6/wrapt-2.4.1-cp312-cp312-win32.whl", hash = "sha256:5d83e412665aeb1e854eefbf1564d0d67872d9994b502a0bce96e6ff7f4970b7", size = 93441, upload-time = "2026-09-10T23:10:19.81Z" }, - { url = "https://files.pythonhosted.org/packages/d4/2a/47be56772bfb07ef242d6e924049688e38384af2b2fc99b0f31180988448/wrapt-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:b4e7efdd476ac631a0181551fd9aace844765ea3ce2b5133b194fae4421e8ad0", size = 98808, upload-time = "2026-09-10T23:10:21.084Z" }, - { url = "https://files.pythonhosted.org/packages/d7/ec/40e4c9735626afd1dc0eeb310310278361f192800503cda0f5b3d8d24db4/wrapt-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:38819761401baa2d11916d7265b82f23265f8fe5a31c431dd7c24a8863c65f88", size = 95240, upload-time = "2026-09-10T23:10:22.39Z" }, - { url = "https://files.pythonhosted.org/packages/5c/1a/9b5aa3c2391aa6d00fffa085c2219e8fc91cd4d2b9b080d2b4e4b6b93f42/wrapt-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:55f36bb1461f93beaf18d818e568b5de343dd8fade7456773d201a38ee723bd3", size = 98597, upload-time = "2026-09-10T23:10:23.723Z" }, - { url = "https://files.pythonhosted.org/packages/fe/07/dc98150c2f9ee5b5fcbd841765e178ea6cc6c43733ab8d1f5181a4fb9f3d/wrapt-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:53e15cd74bd6b84d7fa90b93dda7334d85f4641fae97632de8aa61d268dfd145", size = 98842, upload-time = "2026-09-10T23:10:25.109Z" }, - { url = "https://files.pythonhosted.org/packages/08/c2/0e772a570e8d75c1b3ec45930a3023492fa68223f8f5e3485af4844c10c3/wrapt-2.4.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:be6cdd7121adc89a6f52e3c2f4e26a2d4dcdc1c0fde47e3156234db8939e4cdc", size = 234642, upload-time = "2026-09-10T23:10:26.644Z" }, - { url = "https://files.pythonhosted.org/packages/76/25/4ce4d02dd95ff9ed972a2fc396d04fec636daa5a4ac18cc73a3dc20aa6c3/wrapt-2.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:03b5598edd435373278731d0d53449ce7a9626bc48d5548e4a71124ee3e526a1", size = 235484, upload-time = "2026-09-10T23:10:28.098Z" }, - { url = "https://files.pythonhosted.org/packages/fd/80/436ef1df620ef8edd9ef057b4d55a0cd704435ff66852a0ef26cbaa02a58/wrapt-2.4.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fdc997819a6df4c65bdb0a1c5601c98b479ee34cc2f94ffa98a767034ad6366d", size = 214371, upload-time = "2026-09-10T23:10:29.841Z" }, - { url = "https://files.pythonhosted.org/packages/6a/2c/cc5b7503843399087db3106a7cf60d60d0900f69539e96148b9fff116291/wrapt-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3bfc6907ebed560d2d3f677c3b17bf6199679163b6c6e475035c9dca497d1697", size = 232347, upload-time = "2026-09-10T23:10:31.511Z" }, - { url = "https://files.pythonhosted.org/packages/86/fb/17668b1ca572c44b458c09d76064d35f5f57d5ac7629248871604bef816c/wrapt-2.4.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:a0c3b217332cf0c4df085fec41c126bf7507d6c1ca0efb3ba8d2b3fd234d4e73", size = 212792, upload-time = "2026-09-10T23:10:32.968Z" }, - { url = "https://files.pythonhosted.org/packages/b8/2b/0c5de10d7259e07c478c44bf2fbe179c6878727d09edf0632b97884801db/wrapt-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a23b89621cfeb3329b1a290596bf402e61d7d5a647a65ca8ea735e48771b71d4", size = 223585, upload-time = "2026-09-10T23:10:34.43Z" }, - { url = "https://files.pythonhosted.org/packages/aa/36/013dce1c687f8f1c87b1e78f403d04c80ae9b2ae77de4ddba16069a3e7d1/wrapt-2.4.1-cp313-cp313-win32.whl", hash = "sha256:bc67d4872af5ab2dc1b88904097b92ac00e7658fdf010dee36807807fe882ac4", size = 93425, upload-time = "2026-09-10T23:10:35.901Z" }, - { url = "https://files.pythonhosted.org/packages/b7/1d/d53bcf5910209a45191c8bc173ff0e00830416547d8038772dc444932ee0/wrapt-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:1fe758b9c2d49138231ec3efabd106fec665f86fec50b3d02d7edd75f08a69ca", size = 98569, upload-time = "2026-09-10T23:10:37.316Z" }, - { url = "https://files.pythonhosted.org/packages/e8/1f/759d0c522918f9dfb620136622d8e1ce619570adda0de8fa2cfbb55cbb86/wrapt-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:0c974c36e8205255a3947dad9c2fe000431b57dd522946e56c192174a7f92a0f", size = 95272, upload-time = "2026-09-10T23:10:38.657Z" }, - { url = "https://files.pythonhosted.org/packages/4f/a2/edcfc8d9a30375791b775715f8501364588f65b494ec4f6930568a19e765/wrapt-2.4.1-py3-none-any.whl", hash = "sha256:1e84ec5d89a0a07a0ef6bcd343f5c8ecdc95601d71de3058cdc63274e86c193c", size = 75317, upload-time = "2026-09-10T23:12:14.82Z" }, -] - -[[package]] -name = "zstandard" -version = "0.25.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fd/aa/3e0508d5a5dd96529cdc5a97011299056e14c6505b678fd58938792794b1/zstandard-0.25.0.tar.gz", hash = "sha256:7713e1179d162cf5c7906da876ec2ccb9c3a9dcbdffef0cc7f70c3667a205f0b", size = 711513, upload-time = "2025-09-14T22:15:54.002Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/82/fc/f26eb6ef91ae723a03e16eddb198abcfce2bc5a42e224d44cc8b6765e57e/zstandard-0.25.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7b3c3a3ab9daa3eed242d6ecceead93aebbb8f5f84318d82cee643e019c4b73b", size = 795738, upload-time = "2025-09-14T22:16:56.237Z" }, - { url = "https://files.pythonhosted.org/packages/aa/1c/d920d64b22f8dd028a8b90e2d756e431a5d86194caa78e3819c7bf53b4b3/zstandard-0.25.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:913cbd31a400febff93b564a23e17c3ed2d56c064006f54efec210d586171c00", size = 640436, upload-time = "2025-09-14T22:16:57.774Z" }, - { url = "https://files.pythonhosted.org/packages/53/6c/288c3f0bd9fcfe9ca41e2c2fbfd17b2097f6af57b62a81161941f09afa76/zstandard-0.25.0-cp312-cp312-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:011d388c76b11a0c165374ce660ce2c8efa8e5d87f34996aa80f9c0816698b64", size = 5343019, upload-time = "2025-09-14T22:16:59.302Z" }, - { url = "https://files.pythonhosted.org/packages/1e/15/efef5a2f204a64bdb5571e6161d49f7ef0fffdbca953a615efbec045f60f/zstandard-0.25.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6dffecc361d079bb48d7caef5d673c88c8988d3d33fb74ab95b7ee6da42652ea", size = 5063012, upload-time = "2025-09-14T22:17:01.156Z" }, - { url = "https://files.pythonhosted.org/packages/b7/37/a6ce629ffdb43959e92e87ebdaeebb5ac81c944b6a75c9c47e300f85abdf/zstandard-0.25.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:7149623bba7fdf7e7f24312953bcf73cae103db8cae49f8154dd1eadc8a29ecb", size = 5394148, upload-time = "2025-09-14T22:17:03.091Z" }, - { url = "https://files.pythonhosted.org/packages/e3/79/2bf870b3abeb5c070fe2d670a5a8d1057a8270f125ef7676d29ea900f496/zstandard-0.25.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:6a573a35693e03cf1d67799fd01b50ff578515a8aeadd4595d2a7fa9f3ec002a", size = 5451652, upload-time = "2025-09-14T22:17:04.979Z" }, - { url = "https://files.pythonhosted.org/packages/53/60/7be26e610767316c028a2cbedb9a3beabdbe33e2182c373f71a1c0b88f36/zstandard-0.25.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5a56ba0db2d244117ed744dfa8f6f5b366e14148e00de44723413b2f3938a902", size = 5546993, upload-time = "2025-09-14T22:17:06.781Z" }, - { url = "https://files.pythonhosted.org/packages/85/c7/3483ad9ff0662623f3648479b0380d2de5510abf00990468c286c6b04017/zstandard-0.25.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:10ef2a79ab8e2974e2075fb984e5b9806c64134810fac21576f0668e7ea19f8f", size = 5046806, upload-time = "2025-09-14T22:17:08.415Z" }, - { url = "https://files.pythonhosted.org/packages/08/b3/206883dd25b8d1591a1caa44b54c2aad84badccf2f1de9e2d60a446f9a25/zstandard-0.25.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aaf21ba8fb76d102b696781bddaa0954b782536446083ae3fdaa6f16b25a1c4b", size = 5576659, upload-time = "2025-09-14T22:17:10.164Z" }, - { url = "https://files.pythonhosted.org/packages/9d/31/76c0779101453e6c117b0ff22565865c54f48f8bd807df2b00c2c404b8e0/zstandard-0.25.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1869da9571d5e94a85a5e8d57e4e8807b175c9e4a6294e3b66fa4efb074d90f6", size = 4953933, upload-time = "2025-09-14T22:17:11.857Z" }, - { url = "https://files.pythonhosted.org/packages/18/e1/97680c664a1bf9a247a280a053d98e251424af51f1b196c6d52f117c9720/zstandard-0.25.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:809c5bcb2c67cd0ed81e9229d227d4ca28f82d0f778fc5fea624a9def3963f91", size = 5268008, upload-time = "2025-09-14T22:17:13.627Z" }, - { url = "https://files.pythonhosted.org/packages/1e/73/316e4010de585ac798e154e88fd81bb16afc5c5cb1a72eeb16dd37e8024a/zstandard-0.25.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f27662e4f7dbf9f9c12391cb37b4c4c3cb90ffbd3b1fb9284dadbbb8935fa708", size = 5433517, upload-time = "2025-09-14T22:17:16.103Z" }, - { url = "https://files.pythonhosted.org/packages/5b/60/dd0f8cfa8129c5a0ce3ea6b7f70be5b33d2618013a161e1ff26c2b39787c/zstandard-0.25.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99c0c846e6e61718715a3c9437ccc625de26593fea60189567f0118dc9db7512", size = 5814292, upload-time = "2025-09-14T22:17:17.827Z" }, - { url = "https://files.pythonhosted.org/packages/fc/5f/75aafd4b9d11b5407b641b8e41a57864097663699f23e9ad4dbb91dc6bfe/zstandard-0.25.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:474d2596a2dbc241a556e965fb76002c1ce655445e4e3bf38e5477d413165ffa", size = 5360237, upload-time = "2025-09-14T22:17:19.954Z" }, - { url = "https://files.pythonhosted.org/packages/ff/8d/0309daffea4fcac7981021dbf21cdb2e3427a9e76bafbcdbdf5392ff99a4/zstandard-0.25.0-cp312-cp312-win32.whl", hash = "sha256:23ebc8f17a03133b4426bcc04aabd68f8236eb78c3760f12783385171b0fd8bd", size = 436922, upload-time = "2025-09-14T22:17:24.398Z" }, - { url = "https://files.pythonhosted.org/packages/79/3b/fa54d9015f945330510cb5d0b0501e8253c127cca7ebe8ba46a965df18c5/zstandard-0.25.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffef5a74088f1e09947aecf91011136665152e0b4b359c42be3373897fb39b01", size = 506276, upload-time = "2025-09-14T22:17:21.429Z" }, - { url = "https://files.pythonhosted.org/packages/ea/6b/8b51697e5319b1f9ac71087b0af9a40d8a6288ff8025c36486e0c12abcc4/zstandard-0.25.0-cp312-cp312-win_arm64.whl", hash = "sha256:181eb40e0b6a29b3cd2849f825e0fa34397f649170673d385f3598ae17cca2e9", size = 462679, upload-time = "2025-09-14T22:17:23.147Z" }, - { url = "https://files.pythonhosted.org/packages/35/0b/8df9c4ad06af91d39e94fa96cc010a24ac4ef1378d3efab9223cc8593d40/zstandard-0.25.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec996f12524f88e151c339688c3897194821d7f03081ab35d31d1e12ec975e94", size = 795735, upload-time = "2025-09-14T22:17:26.042Z" }, - { url = "https://files.pythonhosted.org/packages/3f/06/9ae96a3e5dcfd119377ba33d4c42a7d89da1efabd5cb3e366b156c45ff4d/zstandard-0.25.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a1a4ae2dec3993a32247995bdfe367fc3266da832d82f8438c8570f989753de1", size = 640440, upload-time = "2025-09-14T22:17:27.366Z" }, - { url = "https://files.pythonhosted.org/packages/d9/14/933d27204c2bd404229c69f445862454dcc101cd69ef8c6068f15aaec12c/zstandard-0.25.0-cp313-cp313-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:e96594a5537722fdfb79951672a2a63aec5ebfb823e7560586f7484819f2a08f", size = 5343070, upload-time = "2025-09-14T22:17:28.896Z" }, - { url = "https://files.pythonhosted.org/packages/6d/db/ddb11011826ed7db9d0e485d13df79b58586bfdec56e5c84a928a9a78c1c/zstandard-0.25.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bfc4e20784722098822e3eee42b8e576b379ed72cca4a7cb856ae733e62192ea", size = 5063001, upload-time = "2025-09-14T22:17:31.044Z" }, - { url = "https://files.pythonhosted.org/packages/db/00/87466ea3f99599d02a5238498b87bf84a6348290c19571051839ca943777/zstandard-0.25.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:457ed498fc58cdc12fc48f7950e02740d4f7ae9493dd4ab2168a47c93c31298e", size = 5394120, upload-time = "2025-09-14T22:17:32.711Z" }, - { url = "https://files.pythonhosted.org/packages/2b/95/fc5531d9c618a679a20ff6c29e2b3ef1d1f4ad66c5e161ae6ff847d102a9/zstandard-0.25.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:fd7a5004eb1980d3cefe26b2685bcb0b17989901a70a1040d1ac86f1d898c551", size = 5451230, upload-time = "2025-09-14T22:17:34.41Z" }, - { url = "https://files.pythonhosted.org/packages/63/4b/e3678b4e776db00f9f7b2fe58e547e8928ef32727d7a1ff01dea010f3f13/zstandard-0.25.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8e735494da3db08694d26480f1493ad2cf86e99bdd53e8e9771b2752a5c0246a", size = 5547173, upload-time = "2025-09-14T22:17:36.084Z" }, - { url = "https://files.pythonhosted.org/packages/4e/d5/ba05ed95c6b8ec30bd468dfeab20589f2cf709b5c940483e31d991f2ca58/zstandard-0.25.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3a39c94ad7866160a4a46d772e43311a743c316942037671beb264e395bdd611", size = 5046736, upload-time = "2025-09-14T22:17:37.891Z" }, - { url = "https://files.pythonhosted.org/packages/50/d5/870aa06b3a76c73eced65c044b92286a3c4e00554005ff51962deef28e28/zstandard-0.25.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:172de1f06947577d3a3005416977cce6168f2261284c02080e7ad0185faeced3", size = 5576368, upload-time = "2025-09-14T22:17:40.206Z" }, - { url = "https://files.pythonhosted.org/packages/5d/35/398dc2ffc89d304d59bc12f0fdd931b4ce455bddf7038a0a67733a25f550/zstandard-0.25.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3c83b0188c852a47cd13ef3bf9209fb0a77fa5374958b8c53aaa699398c6bd7b", size = 4954022, upload-time = "2025-09-14T22:17:41.879Z" }, - { url = "https://files.pythonhosted.org/packages/9a/5c/36ba1e5507d56d2213202ec2b05e8541734af5f2ce378c5d1ceaf4d88dc4/zstandard-0.25.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1673b7199bbe763365b81a4f3252b8e80f44c9e323fc42940dc8843bfeaf9851", size = 5267889, upload-time = "2025-09-14T22:17:43.577Z" }, - { url = "https://files.pythonhosted.org/packages/70/e8/2ec6b6fb7358b2ec0113ae202647ca7c0e9d15b61c005ae5225ad0995df5/zstandard-0.25.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0be7622c37c183406f3dbf0cba104118eb16a4ea7359eeb5752f0794882fc250", size = 5433952, upload-time = "2025-09-14T22:17:45.271Z" }, - { url = "https://files.pythonhosted.org/packages/7b/01/b5f4d4dbc59ef193e870495c6f1275f5b2928e01ff5a81fecb22a06e22fb/zstandard-0.25.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5f5e4c2a23ca271c218ac025bd7d635597048b366d6f31f420aaeb715239fc98", size = 5814054, upload-time = "2025-09-14T22:17:47.08Z" }, - { url = "https://files.pythonhosted.org/packages/b2/e5/fbd822d5c6f427cf158316d012c5a12f233473c2f9c5fe5ab1ae5d21f3d8/zstandard-0.25.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f187a0bb61b35119d1926aee039524d1f93aaf38a9916b8c4b78ac8514a0aaf", size = 5360113, upload-time = "2025-09-14T22:17:48.893Z" }, - { url = "https://files.pythonhosted.org/packages/8e/e0/69a553d2047f9a2c7347caa225bb3a63b6d7704ad74610cb7823baa08ed7/zstandard-0.25.0-cp313-cp313-win32.whl", hash = "sha256:7030defa83eef3e51ff26f0b7bfb229f0204b66fe18e04359ce3474ac33cbc09", size = 436936, upload-time = "2025-09-14T22:17:52.658Z" }, - { url = "https://files.pythonhosted.org/packages/d9/82/b9c06c870f3bd8767c201f1edbdf9e8dc34be5b0fbc5682c4f80fe948475/zstandard-0.25.0-cp313-cp313-win_amd64.whl", hash = "sha256:1f830a0dac88719af0ae43b8b2d6aef487d437036468ef3c2ea59c51f9d55fd5", size = 506232, upload-time = "2025-09-14T22:17:50.402Z" }, - { url = "https://files.pythonhosted.org/packages/d4/57/60c3c01243bb81d381c9916e2a6d9e149ab8627c0c7d7abb2d73384b3c0c/zstandard-0.25.0-cp313-cp313-win_arm64.whl", hash = "sha256:85304a43f4d513f5464ceb938aa02c1e78c2943b29f44a750b48b25ac999a049", size = 462671, upload-time = "2025-09-14T22:17:51.533Z" }, -]