pax_global_header00006660000000000000000000000064152657775030014533gustar00rootroot0000000000000052 comment=ff306fbe3ace85f892a5a9a428eb432d9a17fac4 monty-2026.10.21/000077500000000000000000000000001526577750300132745ustar00rootroot00000000000000monty-2026.10.21/.codacy.yml000066400000000000000000000000551526577750300153370ustar00rootroot00000000000000--- exclude_paths: - tests/** - docs*/** monty-2026.10.21/.github/000077500000000000000000000000001526577750300146345ustar00rootroot00000000000000monty-2026.10.21/.github/dependabot.yml000066400000000000000000000004521526577750300174650ustar00rootroot00000000000000version: 2 updates: - package-ecosystem: pip directory: "/" schedule: interval: daily time: "13:00" open-pull-requests-limit: 10 ignore: - dependency-name: pylint versions: - 2.7.0 - 2.7.1 - 2.8.1 - dependency-name: numpy versions: - 1.19.5 - 1.20.0 monty-2026.10.21/.github/workflows/000077500000000000000000000000001526577750300166715ustar00rootroot00000000000000monty-2026.10.21/.github/workflows/lint.yml000066400000000000000000000011461526577750300203640ustar00rootroot00000000000000name: Lint on: [push, pull_request] jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - name: Install uv with python version. uses: astral-sh/setup-uv@v7 with: enable-cache: true cache-dependency-glob: "uv.lock" - name: Install dependencies run: | uv sync --group lint - name: ruff run: | uv run ruff --version uv run ruff check src uv run ruff format src --check - name: mypy run: | uv run mypy --version uv run mypy -p monty monty-2026.10.21/.github/workflows/release.yml000066400000000000000000000017761526577750300210470ustar00rootroot00000000000000name: Release on: release: types: [created] workflow_dispatch: jobs: test: # run test.yml first to ensure that the test suite is passing uses: ./.github/workflows/test.yml build: needs: test runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - name: Install uv with python version. uses: astral-sh/setup-uv@v7 with: enable-cache: true cache-dependency-glob: "uv.lock" - name: Build run: | uv build - uses: actions/upload-artifact@v4 with: path: dist/*.* release: needs: build runs-on: ubuntu-latest permissions: # For pypi trusted publishing id-token: write steps: - name: Get build artifacts uses: actions/download-artifact@v5 with: name: artifact path: dist - name: Publish to PyPi uses: pypa/gh-action-pypi-publish@release/v1 with: skip-existing: true verbose: true monty-2026.10.21/.github/workflows/test.yml000066400000000000000000000017011526577750300203720ustar00rootroot00000000000000name: Test on: [push, pull_request, workflow_call] jobs: build: strategy: fail-fast: false max-parallel: 20 matrix: os: [ubuntu-latest, macos-latest, windows-latest] python-version: ["3.11", "3.12", "3.13", "3.14"] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v5 - name: Install uv uses: astral-sh/setup-uv@v7 with: python-version: ${{ matrix.python-version }} enable-cache: true cache-dependency-glob: "uv.lock" - name: Install dependencies run: uv sync --all-extras - name: pytest run: uv run pytest --cov=monty --cov-report=xml tests --color=yes - name: Upload coverage reports to Codecov if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.12' uses: codecov/codecov-action@v5 with: files: ./coverage.xml token: ${{ secrets.CODECOV_TOKEN }} monty-2026.10.21/.gitignore000066400000000000000000000006051526577750300152650ustar00rootroot00000000000000*.py[cod] # C extensions *.so # Packages *.egg *.egg-info dist build _build _site eggs parts bin var sdist develop-eggs .installed.cfg lib lib64 __pycache__ # Installer logs pip-log.txt # Unit test / coverage reports .coverage .tox .cache nosetests.xml # Translations *.mo # Mr Developer .mr.developer.cfg .project .pydevproject .idea .mypy_cache # vim files *.swp *.swo .DS_Store monty-2026.10.21/.pre-commit-config.yaml000066400000000000000000000025671526577750300175670ustar00rootroot00000000000000exclude: ^(docs|tests/test_files|tasks.py) default_install_hook_types: [pre-commit, commit-msg] ci: autoupdate_schedule: monthly skip: [mypy] autofix_commit_msg: pre-commit auto-fixes autoupdate_commit_msg: pre-commit autoupdate repos: - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.15.15 hooks: - id: ruff-check args: [--fix] - id: ruff-format - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 hooks: - id: check-yaml - id: end-of-file-fixer exclude: ^tests - id: trailing-whitespace exclude: ^tests - repo: https://github.com/pre-commit/mirrors-mypy rev: v2.1.0 hooks: - id: mypy - repo: https://github.com/codespell-project/codespell rev: v2.4.2 hooks: - id: codespell stages: [pre-commit, commit-msg] exclude_types: [html] - repo: https://github.com/adamchainz/blacken-docs rev: 1.20.0 hooks: - id: blacken-docs - repo: https://github.com/igorshubovych/markdownlint-cli rev: v0.48.0 hooks: - id: markdownlint # MD013: line too long # MD024: Multiple headings with the same content # MD033: no inline HTML # MD041: first line in a file should be a top-level heading # MD025: single title args: [--disable, MD013, MD024, MD025, MD033, MD041, "--"] monty-2026.10.21/LICENSE.rst000066400000000000000000000021001526577750300151010ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2014 Materials Virtual Lab Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. monty-2026.10.21/MANIFEST.in000066400000000000000000000001021526577750300150230ustar00rootroot00000000000000include *.md LICENSE.rst recursive-include monty *.py prune tests monty-2026.10.21/README.md000066400000000000000000000100271526577750300145530ustar00rootroot00000000000000[![GitHub license](https://img.shields.io/github/license/materialyzeai/monty)](https://github.com/materialyzeai/monty/blob/main/LICENSE.rst) [![Lint](https://github.com/materialyzeai/monty/actions/workflows/lint.yml/badge.svg)](https://github.com/materialyzeai/monty/actions/workflows/lint.yml) [![Test](https://github.com/materialyzeai/monty/actions/workflows/test.yml/badge.svg)](https://github.com/materialyzeai/monty/actions/workflows/test.yml) [![Downloads](https://static.pepy.tech/badge/monty)](https://pepy.tech/project/monty) [![codecov](https://codecov.io/gh/materialyzeai/monty/branch/main/graph/badge.svg)](https://codecov.io/gh/materialyzeai/monty) # Monty: Python Made Even Easier Monty is the missing complement to Python. It implements supplementary utilities that are not part of the standard library: transparent support for compressed files, JSON/YAML/msgpack serialization of arbitrary objects, design patterns such as `cached_class`, deprecation helpers, and many more. Python comes with "batteries included", but in building several large scientific frameworks (most notably [pymatgen](https://pymatgen.org)), we found ourselves repeatedly writing the same small utilities. Monty collects these into a single, well-tested, dependency-light library. Where the standard library has since caught up, Monty delegates to it. Monty supports Python 3.11+. ## Installation ```bash pip install monty # or uv add monty ``` Optional extras pull in dependencies for specific features: | Extra | Enables | |---|---| | `json` | Serialization of numpy, pandas, pint, pydantic, torch and bson objects | | `serialization` | msgpack support in `dumpfn`/`loadfn` | | `multiprocessing` | `imap_tqdm` progress bars | | `dev` | IPython-based `install_excepthook` | | `optional` | All of the above | ```bash pip install "monty[optional]" ``` ## Highlights **Transparent compressed I/O.** `zopen` opens plain, `.gz`, `.bz2`, `.xz` and `.lzma` files with one call; `reverse_readline` reads large files from the end. ```python from monty.io import reverse_readline, zopen with zopen("OUTCAR.gz", mode="rt", encoding="utf-8") as f: for line in reverse_readline(f): if "TOTAL-FORCE" in line: break ``` **Serialization of arbitrary objects.** Subclass `MSONable` to get `as_dict()`/`from_dict()` and JSON round-tripping for free; `dumpfn`/`loadfn` pick the format (JSON, JSON lines, YAML, msgpack) and compression from the file extension. ```python from monty.json import MSONable from monty.serialization import dumpfn, loadfn class Calculation(MSONable): def __init__(self, name: str, energy: float): self.name = name self.energy = energy dumpfn(Calculation("relax", -3.42), "calc.json.gz") calc = loadfn("calc.json.gz") # -> Calculation instance ``` **Scratch directories.** `ScratchDir` runs a block in a temporary directory and copies results back on exit. ```python from monty.tempfile import ScratchDir with ScratchDir(".", copy_from_current_on_enter=True, copy_to_current_on_exit=True): ... # run an expensive calculation ``` **Development helpers.** Mark deprecations with an optional removal deadline, and guard code paths on optional dependencies. ```python from monty.dev import deprecated, requires try: import torch except ImportError: torch = None @deprecated(replacement="new_func", deadline=(2028, 1, 1)) def old_func(): ... @requires(torch is not None, "torch is required for this function.") def train(): ... ``` Other modules include `monty.design_patterns` (`cached_class`, `singleton`), `monty.functools` (`lazy_property`, `return_if_raise`, `timeout`), `monty.shutil` (`compress_dir`, `decompress_dir`, `gzip_dir`), `monty.os.path` (`zpath`, `find_exts`), `monty.re` (`regrep`) and `monty.collections` (`frozendict`, `AttrDict`, `tree`). See the [official docs](https://materialyzeai.github.io/monty) for the full API. ## Development ```bash git clone https://github.com/materialyzeai/monty.git cd monty uv sync --all-extras uv run pytest uv run ruff check src && uv run ruff format src uv run mypy -p monty ``` monty-2026.10.21/docs/000077500000000000000000000000001526577750300142245ustar00rootroot00000000000000monty-2026.10.21/docs/Gemfile000066400000000000000000000024661526577750300155270ustar00rootroot00000000000000source "https://rubygems.org" # Hello! This is where you manage which Jekyll version is used to run. # When you want to use a different version, change it below, save the # file and run `bundle install`. Run Jekyll with `bundle exec`, like so: # # bundle exec jekyll serve # # This will help ensure the proper Jekyll version is running. # Happy Jekylling! # gem "jekyll", "~> 4.3.2" # This is the default theme for new Jekyll sites. You may change this to anything you like. gem "minima", "~> 2.5" # If you want to use GitHub Pages, remove the "gem "jekyll"" above and # uncomment the line below. To upgrade, run `bundle update github-pages`. gem "github-pages", group: :jekyll_plugins # If you have any plugins, put them here! group :jekyll_plugins do gem "jekyll-feed", "~> 0.12" end # Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem # and associated library. platforms :mingw, :x64_mingw, :mswin, :jruby do gem "tzinfo", ">= 1", "< 3" gem "tzinfo-data" end # Performance-booster for watching directories on Windows gem "wdm", "~> 0.1.1", :platforms => [:mingw, :x64_mingw, :mswin] # Lock `http_parser.rb` gem to `v0.6.x` on JRuby builds since newer versions of the gem # do not have a Java counterpart. gem "http_parser.rb", "~> 0.6.0", :platforms => [:jruby] gem "webrick", "~> 1.8" monty-2026.10.21/docs/Gemfile.lock000066400000000000000000000172641526577750300164600ustar00rootroot00000000000000GEM remote: https://rubygems.org/ specs: activesupport (7.2.3.1) base64 benchmark (>= 0.3) bigdecimal concurrent-ruby (~> 1.0, >= 1.3.1) connection_pool (>= 2.2.5) drb i18n (>= 1.6, < 2) logger (>= 1.4.2) minitest (>= 5.1, < 6) securerandom (>= 0.3) tzinfo (~> 2.0, >= 2.0.5) addressable (2.9.0) public_suffix (>= 2.0.2, < 8.0) base64 (0.3.0) benchmark (0.5.0) bigdecimal (4.1.2) coffee-script (2.4.1) coffee-script-source execjs coffee-script-source (1.11.1) colorator (1.1.0) commonmarker (0.23.10) concurrent-ruby (1.3.7) connection_pool (3.0.2) dnsruby (1.70.0) simpleidn (~> 0.2.1) drb (2.2.3) em-websocket (0.5.3) eventmachine (>= 0.12.9) http_parser.rb (~> 0) ethon (0.16.0) ffi (>= 1.15.0) eventmachine (1.2.7) execjs (2.8.1) faraday (2.14.2) faraday-net_http (>= 2.0, < 3.5) json logger faraday-net_http (3.4.2) net-http (~> 0.5) ffi (1.15.5) forwardable-extended (2.6.0) gemoji (3.0.1) github-pages (228) github-pages-health-check (= 1.17.9) jekyll (= 3.9.3) jekyll-avatar (= 0.7.0) jekyll-coffeescript (= 1.1.1) jekyll-commonmark-ghpages (= 0.4.0) jekyll-default-layout (= 0.1.4) jekyll-feed (= 0.15.1) jekyll-gist (= 1.5.0) jekyll-github-metadata (= 2.13.0) jekyll-include-cache (= 0.2.1) jekyll-mentions (= 1.6.0) jekyll-optional-front-matter (= 0.3.2) jekyll-paginate (= 1.1.0) jekyll-readme-index (= 0.3.0) jekyll-redirect-from (= 0.16.0) jekyll-relative-links (= 0.6.1) jekyll-remote-theme (= 0.4.3) jekyll-sass-converter (= 1.5.2) jekyll-seo-tag (= 2.8.0) jekyll-sitemap (= 1.4.0) jekyll-swiss (= 1.0.0) jekyll-theme-architect (= 0.2.0) jekyll-theme-cayman (= 0.2.0) jekyll-theme-dinky (= 0.2.0) jekyll-theme-hacker (= 0.2.0) jekyll-theme-leap-day (= 0.2.0) jekyll-theme-merlot (= 0.2.0) jekyll-theme-midnight (= 0.2.0) jekyll-theme-minimal (= 0.2.0) jekyll-theme-modernist (= 0.2.0) jekyll-theme-primer (= 0.6.0) jekyll-theme-slate (= 0.2.0) jekyll-theme-tactile (= 0.2.0) jekyll-theme-time-machine (= 0.2.0) jekyll-titles-from-headings (= 0.5.3) jemoji (= 0.12.0) kramdown (= 2.3.2) kramdown-parser-gfm (= 1.1.0) liquid (= 4.0.4) mercenary (~> 0.3) minima (= 2.5.1) nokogiri (>= 1.13.6, < 2.0) rouge (= 3.26.0) terminal-table (~> 1.4) github-pages-health-check (1.17.9) addressable (~> 2.3) dnsruby (~> 1.60) octokit (~> 4.0) public_suffix (>= 3.0, < 5.0) typhoeus (~> 1.3) html-pipeline (2.14.3) activesupport (>= 2) nokogiri (>= 1.4) http_parser.rb (0.8.0) i18n (1.14.8) concurrent-ruby (~> 1.0) jekyll (3.9.3) addressable (~> 2.4) colorator (~> 1.0) em-websocket (~> 0.5) i18n (>= 0.7, < 2) jekyll-sass-converter (~> 1.0) jekyll-watch (~> 2.0) kramdown (>= 1.17, < 3) liquid (~> 4.0) mercenary (~> 0.3.3) pathutil (~> 0.9) rouge (>= 1.7, < 4) safe_yaml (~> 1.0) jekyll-avatar (0.7.0) jekyll (>= 3.0, < 5.0) jekyll-coffeescript (1.1.1) coffee-script (~> 2.2) coffee-script-source (~> 1.11.1) jekyll-commonmark (1.4.0) commonmarker (~> 0.22) jekyll-commonmark-ghpages (0.4.0) commonmarker (~> 0.23.7) jekyll (~> 3.9.0) jekyll-commonmark (~> 1.4.0) rouge (>= 2.0, < 5.0) jekyll-default-layout (0.1.4) jekyll (~> 3.0) jekyll-feed (0.15.1) jekyll (>= 3.7, < 5.0) jekyll-gist (1.5.0) octokit (~> 4.2) jekyll-github-metadata (2.13.0) jekyll (>= 3.4, < 5.0) octokit (~> 4.0, != 4.4.0) jekyll-include-cache (0.2.1) jekyll (>= 3.7, < 5.0) jekyll-mentions (1.6.0) html-pipeline (~> 2.3) jekyll (>= 3.7, < 5.0) jekyll-optional-front-matter (0.3.2) jekyll (>= 3.0, < 5.0) jekyll-paginate (1.1.0) jekyll-readme-index (0.3.0) jekyll (>= 3.0, < 5.0) jekyll-redirect-from (0.16.0) jekyll (>= 3.3, < 5.0) jekyll-relative-links (0.6.1) jekyll (>= 3.3, < 5.0) jekyll-remote-theme (0.4.3) addressable (~> 2.0) jekyll (>= 3.5, < 5.0) jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0) rubyzip (>= 1.3.0, < 3.0) jekyll-sass-converter (1.5.2) sass (~> 3.4) jekyll-seo-tag (2.8.0) jekyll (>= 3.8, < 5.0) jekyll-sitemap (1.4.0) jekyll (>= 3.7, < 5.0) jekyll-swiss (1.0.0) jekyll-theme-architect (0.2.0) jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) jekyll-theme-cayman (0.2.0) jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) jekyll-theme-dinky (0.2.0) jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) jekyll-theme-hacker (0.2.0) jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) jekyll-theme-leap-day (0.2.0) jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) jekyll-theme-merlot (0.2.0) jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) jekyll-theme-midnight (0.2.0) jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) jekyll-theme-minimal (0.2.0) jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) jekyll-theme-modernist (0.2.0) jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) jekyll-theme-primer (0.6.0) jekyll (> 3.5, < 5.0) jekyll-github-metadata (~> 2.9) jekyll-seo-tag (~> 2.0) jekyll-theme-slate (0.2.0) jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) jekyll-theme-tactile (0.2.0) jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) jekyll-theme-time-machine (0.2.0) jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) jekyll-titles-from-headings (0.5.3) jekyll (>= 3.3, < 5.0) jekyll-watch (2.2.1) listen (~> 3.0) jemoji (0.12.0) gemoji (~> 3.0) html-pipeline (~> 2.2) jekyll (>= 3.0, < 5.0) json (2.19.9) kramdown (2.3.2) rexml kramdown-parser-gfm (1.1.0) kramdown (~> 2.0) liquid (4.0.4) listen (3.8.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) logger (1.7.0) mercenary (0.3.6) minima (2.5.1) jekyll (>= 3.5, < 5.0) jekyll-feed (~> 0.9) jekyll-seo-tag (~> 2.1) minitest (5.27.0) net-http (0.9.1) uri (>= 0.11.1) nokogiri (1.19.4-arm64-darwin) racc (~> 1.4) nokogiri (1.19.4-x86_64-linux-gnu) racc (~> 1.4) octokit (4.25.1) faraday (>= 1, < 3) sawyer (~> 0.9) pathutil (0.16.2) forwardable-extended (~> 2.6) public_suffix (4.0.7) racc (1.8.1) rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) rexml (3.4.2) rouge (3.26.0) rubyzip (2.3.2) safe_yaml (1.0.5) sass (3.7.4) sass-listen (~> 4.0.0) sass-listen (4.0.0) rb-fsevent (~> 0.9, >= 0.9.4) rb-inotify (~> 0.9, >= 0.9.7) sawyer (0.9.2) addressable (>= 2.3.5) faraday (>= 0.17.3, < 3) securerandom (0.4.1) simpleidn (0.2.1) unf (~> 0.1.4) terminal-table (1.8.0) unicode-display_width (~> 1.1, >= 1.1.1) typhoeus (1.4.0) ethon (>= 0.9.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) unf (0.1.4) unf_ext unf_ext (0.0.8.2) unicode-display_width (1.8.0) uri (1.1.1) webrick (1.8.2) PLATFORMS arm64-darwin-22 x86_64-linux DEPENDENCIES github-pages http_parser.rb (~> 0.6.0) jekyll-feed (~> 0.12) minima (~> 2.5) tzinfo (>= 1, < 3) tzinfo-data wdm (~> 0.1.1) webrick (~> 1.8) BUNDLED WITH 2.4.17 monty-2026.10.21/docs/Makefile000066400000000000000000000127051526577750300156710ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = ../docs # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/pymatgen.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/pymatgen.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/pymatgen" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/pymatgen" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." monty-2026.10.21/docs/_config.yml000066400000000000000000000010211526577750300163450ustar00rootroot00000000000000title: monty email: ongsp@ucsd.edu description: >- # this means to ignore newlines until "baseurl:" A graph deep learning library for materials science. # twitter_username: jekyllrb github_username: materialsvirtuallab # Build settings remote_theme: just-the-docs/just-the-docs plugins: - jekyll-feed # favicon_ico: "/assets/favicon.ico" nav_external_links: - title: "monty on GitHub" url: "https://github.com/materialsvirtuallab/monty" aux_links: "Materials Virtual Lab": - "https://materialsvirtuallab.org"monty-2026.10.21/docs/_includes/000077500000000000000000000000001526577750300161715ustar00rootroot00000000000000monty-2026.10.21/docs/_includes/footer_custom.html000066400000000000000000000000731526577750300217470ustar00rootroot00000000000000© Copyright 2022, Materials Virtual Labmonty-2026.10.21/docs/_includes/nav_footer_custom.html000066400000000000000000000001151526577750300226100ustar00rootroot00000000000000© Copyright 2022, Materials Virtual Labmonty-2026.10.21/docs/changelog.md000066400000000000000000000333741526577750300165070ustar00rootroot00000000000000# Change log ## 2026.10.21 - Fix `return_if_raise` raising `TypeError` when given a tuple of exceptions (#808). - Fix `subprocess.Command` raising `UnboundLocalError` for list/tuple commands (#808). - Fix `loadfn` ignoring a custom `cls` decoder for YAML files (#808). - Fix `bisect.index(..., atol=...)` missing values just above an element; it now returns the leftmost value within tolerance (#808). - Fix `dumpfn` error messages for a missing msgpack/YAML backend (#808). - Preserve callable signatures and types in the `requires` and `deprecated` decorators (#806, @Andrew-S-Rosen). - Replace hand-rolled helpers with stdlib equivalents: `Command.run` uses `Popen.communicate(timeout=...)`, `termcolor.get_terminal_size` wraps `shutil.get_terminal_size`, `iuptri` uses `itertools.combinations`, `singleton` uses `functools.cache`. Remove unused `functools._HashedSeq`/`_make_key` (#809). - Deprecate `monty.os.cd` and `monty.os.makedirs_p` in favor of `contextlib.chdir` and `os.makedirs(path, exist_ok=True)` (#809). - `lazy_property` now subclasses `functools.cached_property`. Fixes private (name-mangled) lazy properties never caching on subclass instances, and aliased names recomputing on every access (#810). - `monty.functools.TimeoutError` now subclasses the built-in `TimeoutError` (and therefore `OSError`) (#810). - Update README: Python 3.11+ requirement, installation, optional extras and usage examples (#810). ## 2026.7.16 - Add YAML round-trip support for MSONable and `TypeHandler`-registered types (numpy, pandas, pint, torch, uuid, pathlib, bson, and user-registered handlers). `dumpfn`/`loadfn` now treat YAML symmetrically with JSON via the `@module`/`@class` envelope, with a `cls=None` opt-out matching the JSON path (closes #587). - Fix `YAML` race condition by using a thread-local instance (closes #795). - Fix regression when decoding a `MSONable` object whose originating module is missing. ## 2026.5.18 - Add Python 3.14 support (#768, @DanielYang59). - Optimize hot paths across `monty.json`, `monty.collections`, `monty.dev`, `monty.inspect`, and `monty.io` (#791). - Introduce `monty.json.TypeHandler` + `register`/`unregister` plugin API so third-party packages can teach `MontyEncoder`/`MontyDecoder` about custom types without forking. Built-in types (datetime, uuid, pathlib, numpy, torch, pandas, pint, bson) are migrated to handlers with identical dict shapes. - Add serialization support for `bson.dbref.DBRef` (collection, id, optional database, optional extras; nested ids recurse through `MontyDecoder`). Closes #746, @mkhorton. - Deprecate `monty.fractions.gcd`, `monty.fractions.lcm`, `monty.functools.nCr`, `monty.functools.nPr`, and `monty.string.is_string` in favor of stdlib equivalents. - Modernize type hints to PEP 585/604 and add return type annotations to public functions. ## 2026.2.18 - Drop Python 3.9 and 3.10 support. - Deprecate `delete_removed_files` from `ScratchDir` (#762, @DanielYang59) - Support JSON lines in load/dumpfn (#770, @esoteric-ephemera) - Remove dev-facing `task` dependency group, merge into `maintain` (#771, @DanielYang59) - Fix pandas DataFrame type check for pandas 3 (#773, @DanielYang59) - ScratchDir: warn for copy-back race when overwriting newer file (#759, @DanielYang59) - Remove deprecated behavior: `zopen` no longer allows default/implicit text/binary `mode`; allow `mode` as positional argument (#752, @DanielYang59) - Include `size` when encoding torch tensor in JSON; release `<3.13` pin for `pint` and `torch` (#755, @DanielYang59) - Better return type annotation for `zopen` (#757, @DanielYang59) - Deprecate `copy_r` in favor of `shutil.copytree(src, dst, dirs_exist_ok=True)` (#761, @DanielYang59) ## 2025.3.3 - Move Partial Serialization out of MSONable (@jmmshn) ## 2025.1.9 - Re-add python 3.9 support ## 2025.1.3 - Drop deadline warning in dev.deprecated - allow strict="skip" for jsanitize ## 2024.12.10 - zopen changes: forbid implicit binary/text mode, signature change, default UTF-8 encoding in text mode, drop .z support after one-year. (@DanielYang59) - Add support for extended JSON to MontyDecoder (@esoteric-ephemera) - Fix jsanitize when recursive_msonable=True (@Andrew-S-Rosen) - Fix custom dict overriding in collections (@DanielYang59) ## 2024.10.21 * Lazily import torch/pydantic in json module, speedup from monty.json import by 10x (@DanielYang59) * Fix missing monty.os package. (@eamanu) * Fix zpath when passing pathlib.Path (@janosh) ## 2024.7.29 - Fix line ending in reverse_readfile/readline in Windows (@DanielYang59) - Add missing functools.wraps decorator to deprecated decorator and handle dataclass properly (@DanielYang59) - Add pint Quantity support to JSON (@rkingsbury) ## 2024.7.12 - Make cached_class decorated classes picklable (@janosh) - deprecated decorator allow replacement as string (@DanielYang59) - Fix (de)serialization datetime with timezone information (@DanielYang59) ## 2024.5.24 - Fix serious regression introduced in list_strings (@gmatteo) - Extend dev.deprecated to decorate classes and improve message (@DanielYang59) ## 2024.5.15 - Reimplemented support for pickle in MSONAble. (@matthewcarbone) ## 2024.4.17 - Revert changes to json.py for now. ## 2024.4.16 (yanked) - Misc bug fixes for jsanitize (@Andrew-S-Rosen). ## 2024.3.31 - Fix MSONable.REDIRECT when module name changed (@janosh) - Add native support for enums in jsanitize (@FabiPi3) - Make jsanitize(recursive_msonable=True) respect duck typing (@Andrew-S-Rosen) - Add optional arg target_dir in compress_file and decompress_file to allow specify target path (@DanielYang59) - Add MontyEncoder/MontyDecoder support for pathlib.Path (@Andrew-S-Rosen) - Add an optional arg deadline to dev.deprecated to raise warning after deadline (@DanielYang59) ## 2024.2.26 - Bug fix for symlinks when using copy_r (@Andrew-S-Rosen) ## 2024.2.2 - Bug fix for Enum subclasses with custom as_dict, from_dict (@jmmshn) ## 2024.1.26 - Fix import of optional libraries. ## 2024.1.23 - Lazy import of optional libraries to speed up startup. ## 2023.9.25 - Improved pydantic2 support (@munrojm). ## 2023.9.5 - Support pathlib.Path in shutil (@Andrew-S-Rosen). - Pydantic2 support (@munrojm). ## 2023.8.8 - Bug fix for decompress_file() to maintain backwards compatibility (@janosh) ## v2023.8.7 - Return path to decompressed file from decompress_file() (@janosh) - @deprecated change default category from FutureWarning to DeprecationWarning ## v2023.5.8 - Improved Pytorch tensor support for MontyEncoder/Decoder. - Bug fix to avoid torch dependency. ## v2023.5.7 - Pytorch tensor support for MontyEncoder/Decoder. ## v2023.4.10 -\* Fix for datetime support in jsanitize (@Andrew-S-Rosen). ## v2022.9.8 - Support for DataClasses in MontyEncoder, MontyDecoder and MSONable. ## v2022.4.26 -\* Fall back on json if orjson is not present. (@munrojm) ## v2022.3.12 -\* Allow recursive MSON in jsanitize (@Andrew-S-Rosen) - Option to use orjson for faster decoding. (@munrojm) ## v2022.1.19 -\* Fix ruamel.yaml backwards compatibility. ## v2022.1.12 -\* Fix decoding of dictionaries (@Andrew-S-Rosen). - Formal support for py3.10 ## v2021.12.1 -\* Adds support for lzma/xz format in zopen (@zhubonan). ## v2021.8.17 -\* Support serialization for Pandas DataFrames (@mkhorton). ## v2021.7.8 - Support the specification of `fmt` keyword arg in monty.serialization loadfn and dumpfn. ## v2021.6.10 -\* Expanded support for built-in functions, numpy types, etc. in MSON serialization (@utf). ## v2021.5.9 - Drop py3.5 support. ## v2021.3.3 - pydantic support (@shyamd) - UUID serialization support (@utf) ## v4.0.2 1. Allow specification of warning category in deprecated wrapper. ## v4.0.1 1. USe FutureWarning in the monty.dev.deprecated wrapper instead. ## v3.0.4 1. Add support for complex dtypes in MSONable numpy arrays. (@fracci) ## v3.0.3 1. Improvements to MSONAble to support Varidac Args (@shyamd). ## v3.0.1 1. Bug fixes for Windows. ## v3.0.0 1. Py3 only version. ## v2.0.7 1. MSONable now supports Enum types. (@mkhorton) ## v2.0.6 1. Revert py27 incompatible fmt spec for loadfn and dumpfn for now. This is a much less common use case. ## v2.0.5 1. Checking for extension type in loadfn and dumpfn now relies on ".json", ".yaml" or ".mpk". Further, now ".yml" and ".yaml" are both recognized as YAML files. (@clegaspi) 2. A fmt kwarg is now supported in loadfn and dumpfn to specify the format explicitly. (@clegaspi) ## v2.0.4 1. Bug fix for invert MSON caused by `@version`. ## v2.0.3 1. Support for nested MSONAble objects with MontyEncoder and dumpfn. (@davidwaroquiers) 2. Add @version to MSONAble. (@mkhorton) ## v2.0.0 1. Support for Path object in zopen. ## v1.0.5 1. Bug fix for io.reverse_readfile to ensure txt or binary string. ## v1.0.4 1. monty.shutil.remove which allows symlinks removal. Also improved monty.tempfile.ScratchDir cleanup. (@shyamd) ## v1.0.3 1. Bug fix for reverse_readfile for bz2 files (Alex Urban) ## v1.0.2 1. Misc bug fixes (tempdir on Windows) ## v1.0.1 1. Use CLoader and CDumper by default for speed. ## v1.0.0 1. Ruamel.yaml is now used as the default YAML parser and dumper. ## v0.9.8 1. Now ScratchDir functions as it should by replacing the original directory. ## v0.9.7 1. Minor update for inspect deprecation. ## v0.9.6 1. Allow private variable names (with leading underscores) to be auto-detected in default MSONable. ## v0.9.5 1. Favor use of inspect.signature in MSONAble. ## v0.9.3 1. Fix monty decoding of bson only if bson is present. ## v0.9.2 1. Minor update. ## v0.9.1 1. bson.objectid.ObjectId support for MontyEncoder and MontyDecoder. ## v0.9.0 1. Improved default as and from_dict. ## v0.8.5 1. Minor bug fixes. ## v0.8.4 1. Support for bson fields in jsanitize. ## v0.8.2 1. Fasetr gzip. ## v0.8.1 1. Update gcd for deprecated fractions.gcd in py >= 3.5. Try math.gcd by default first. ## v0.8.0 1. A new collections.tree object, which allows nested defaultdicts. ## v0.7.2 1. Added support for msgpack serialization in monty.serialization.dumpfn, loadfn and monty.msgpack.default and object_hook. ## v0.7.1 1. Added timeout function. Useful to limit function calls that take too long. ## v0.7.0 1. New backwards incompatible MSONable implementation that inspects init args to create a default dict representation for objects. ## v0.6.1 1. New jsanitize method to convert objects supporting the MSONable protocol to json serializable dicts. ## v0.6.0 1. New frozendict and MongoDict (allows for Javascript like access of nested dicts) classes (Matteo). 2. New Command class in subprocess which allows commands to be run in separate thread with timeout (Matteo). ## v0.5.9 1. More fixes for reverse read of gzipped files ofr Py3k. ## v0.5.8 1. Fix reverse read file for gzipped files. ## v0.5.7 1. Added a reverse_readfile method in monty.io, which is faster than reverse_readline for large files. ## v0.5.6 1. Provide way to specify Dumper and Loader in monty.serialization. 2. Better handling of unicode. ## v0.5.5 1. More robust handling of numpy arrays and datetime objects in json. 2. Refactor NotOverwritableDict to Namespace (Matteo). ## v0.5.4 1. Addition of many help functions in string, itertools, etc. (Matteo). 2. NullFile and NullStream in monty.design_patterns (Matteo). 3. FileLock in monty.io (Matteo) ## v0.5.3 1. Minor efficiency improvement. ## v0.5.2 1. Add unicode2str and str2unicode in monty.string. ## v0.5.0 1. Completely rewritten zopen which supports the "rt" keyword of Python 3 even when used in Python 2. 2. monty.string now has a marquee method which centers a string (contributed by Matteo). 3. Monty now supports only Python >= 3.3 as well as Python 2.7. Python 3.2 support is now dropped. ## v0.4.4 1. Refactor lazy_property to be in functools module. ## v0.4.3 1. Additional dev decorators lazy and logging functions. ## v0.4.2 1. Improve numpy array serialization with MontyEncoder. ## v0.4.1 1. Minor bug fix for module load in Py3k. ## v0.4.0 1. Remove deprecated json.loadf methods. 2. Add MSONable protocol for json/yaml based serialization. 3. deprecated now supports an additonal message. ## v0.3.6 1. :class:`monty.tempfile.ScratchDir` now checks for existence of root directory. If root path does not exist, will function as simple pass through. Makes it a lot more robust to bad mounting of scratch directories. ## v0.3.5 1. Added backport of functools.lru_cache. ## v0.3.4 1. Specialized json encoders / decoders with support for numpy arrays and objects supporting a to_dict() protocol used in pymatgen. ## v0.3.1 1. Proper support for libyaml auto-detect in yaml support. ## v0.3.0 1. Refactor serialization tools to shorten method names. ## v0.2.4 1. Added serialization module that supports both json and yaml. The latter requires pyyaml. ## v0.2.3 1. Added get_ncpus method in dev. (G. Matteo). ## v0.2.2 1. Add a Fabric-inspired cd context manager in monty.os. 2. Refactor ScratchDir context manager to monty.tempfile. ## v0.2.1 1. Add string module, which provides a function to remove non-ascii characters. More to be added. ## v0.2.0 1. ScratchDir now supports non-copying of files to and from current directory, and this is the default (different from prior releases). 2. Yet more improvements to copy_r to prevent recursive infinite loops in copying. ## v0.1.5 1. Added the useful monty.shutil.compress_file, compress_dir, decompress_file and decompress_dir methods. 2. Much more robust copy_r in shutil. ## v0.1.4 1. Bug fix for 0.1.3. ## v0.1.2 1. Added zpath method to return zipped paths. ## v0.1.1 1. Minor release to update description. ## v0.1.0 1. Ensure Python 3+ compatibility. 2. Travis testing implemented. ## v0.0.5 1. First official alpha release with unittests and docs. ## v0.0.2 1. Added several decorators and utilities. ## v0.0.1 1. Initial version. monty-2026.10.21/docs/conf.py000066400000000000000000000044371526577750300155330ustar00rootroot00000000000000# Configuration file for the Sphinx documentation builder. # # This file only contains a selection of the most common options. For a full # list see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html # -- Path setup -------------------------------------------------------------- # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # # import os # import sys # # sys.path.insert(0, os.path.abspath(".")) # sys.path.insert(0, os.path.dirname("..")) # sys.path.insert(0, os.path.dirname("../monty")) # sys.path.insert(0, os.path.dirname("../..")) # -- Project information ----------------------------------------------------- from __future__ import annotations project = "monty" copyright = "2022, Materials Virtual Lab" author = "Shyue Ping Ong" # -- General configuration --------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. # Napoleon is necessary to parse Google style docstrings. Markdown builder allows the generation of markdown output. extensions = [ "sphinx.ext.autodoc", "sphinx.ext.napoleon", "myst_parser", "sphinx_markdown_builder", ] # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] autoclass_content = "both" # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. exclude_patterns = [] # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # html_theme = "alabaster" # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ["_static"] myst_heading_anchors = 3 autodoc_default_options = {"private-members": False} monty-2026.10.21/docs/index.md000066400000000000000000000036461526577750300156660ustar00rootroot00000000000000--- layout: default title: Home nav_order: 1 --- [![GitHub license](https://img.shields.io/github/license/materialsvirtuallab/monty)](https://github.com/materialsvirtuallab/monty/blob/main/LICENSE) [![Linting](https://github.com/materialsvirtuallab/monty/workflows/Linting/badge.svg)](https://github.com/materialsvirtuallab/monty/workflows/Linting/badge.svg) [![Testing](https://github.com/materialsvirtuallab/monty/workflows/Testing/badge.svg)](https://github.com/materialsvirtuallab/monty/workflows/Testing/badge.svg) [![Downloads](https://static.pepy.tech/badge/monty)](https://pepy.tech/project/monty) [![codecov](https://codecov.io/gh/materialsvirtuallab/monty/branch/master/graph/badge.svg?token=QdfT2itxgu)](https://codecov.io/gh/materialsvirtuallab/monty) # Monty: Python Made Even Easier Monty is the missing complement to Python. Monty implements supplementary useful functions for Python that are not part of the standard library. Examples include useful utilities like transparent support for zipped files, useful design patterns such as singleton and cached_class, and many more. Python is a great programming language and comes with "batteries included". However, even Python has missing functionality and/or quirks that make it more difficult to do many simple tasks. In the process of creating several large scientific frameworks based on Python, my co-developers and I have found that it is often useful to create reusable utility functions to supplement the Python standard library. Our forays in various developer sites and forums also found that many developers are looking for solutions to the same problems. Monty is created to serve as a complement to the Python standard library. It provides suite of tools to solve many common problems, and hopefully, be a resource to collect the best solutions. Monty supports Python 3.9+. Please visit the [official docs](https://materialsvirtuallab.github.io/monty) for more information. monty-2026.10.21/docs/make.bat000066400000000000000000000117541526577750300156410ustar00rootroot00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\pymatgen.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\pymatgen.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) :end monty-2026.10.21/docs/monty.bisect.md000066400000000000000000000014631526577750300171700ustar00rootroot00000000000000--- layout: default title: monty.bisect.md nav_exclude: true --- # monty.bisect module Additional bisect functions. Taken from [https://docs.python.org/2/library/bisect.html](https://docs.python.org/2/library/bisect.html) The above bisect() functions are useful for finding insertion points but can be tricky or awkward to use for common searching tasks. The functions show how to transform them into the standard lookups for sorted lists. ## monty.bisect.find_ge(a, x) Find leftmost item greater than or equal to x. ## monty.bisect.find_gt(a, x) Find leftmost value greater than x. ## monty.bisect.find_le(a, x) Find rightmost value less than or equal to x. ## monty.bisect.find_lt(a, x) Find rightmost value less than x. ## monty.bisect.index(a, x, atol=None) Locate the leftmost value exactly equal to x.monty-2026.10.21/docs/monty.collections.md000066400000000000000000000073241526577750300202370ustar00rootroot00000000000000--- layout: default title: monty.collections.md nav_exclude: true --- # monty.collections module Useful collection classes, e.g., tree, frozendict, etc. ## *class* monty.collections.AttrDict(\*args, \*\*kwargs) Bases: `dict` Allows to access dict keys as obj.foo in addition to the traditional way obj[‘foo’]â€� ## Example ```python >>> d = AttrDict(foo=1, bar=2) >>> assert d["foo"] == d.foo >>> d.bar = "hello" >>> assert d.bar == "hello" ``` * **Parameters** * **args** – Passthrough arguments for standard dict. * **kwargs** – Passthrough keyword arguments for standard dict. ### copy() * **Returns** Copy of AttrDict ## *class* monty.collections.FrozenAttrDict(\*args, \*\*kwargs) Bases: `frozendict` A dictionary that: ```none * does not permit changes. * Allows to access dict keys as obj.foo in addition to the traditional way obj[‘foo’] ``` * **Parameters** * **args** – Passthrough arguments for standard dict. * **kwargs** – Passthrough keyword arguments for standard dict. ## *class* monty.collections.MongoDict(\*args, \*\*kwargs) Bases: `object` This dict-like object allows one to access the entries in a nested dict as attributes. Entries (attributes) cannot be modified. It also provides Ipython tab completion hence this object is particularly useful if you need to analyze a nested dict interactively (e.g. documents extracted from a MongoDB database). ```python >>> m = MongoDict({'a': {'b': 1}, 'x': 2}) >>> assert m.a.b == 1 and m.x == 2 >>> assert "a" in m and "b" in m.a >>> m["a"] {'b': 1} ``` **NOTE**: Cannot inherit from ABC collections.Mapping because otherwise dict.keys and dict.items will pollute the namespace. e.g MongoDict({“keysâ€�: 1}).keys would be the ABC dict method. * **Parameters** * **args** – Passthrough arguments for standard dict. * **kwargs** – Passthrough keyword arguments for standard dict. ## *class* monty.collections.Namespace(\*args, \*\*kwargs) Bases: `dict` A dictionary that does not permit to redefine its keys. * **Parameters** * **args** – Passthrough arguments for standard dict. * **kwargs** – Passthrough keyword arguments for standard dict. ### update(\*args, \*\*kwargs) * **Parameters** * **args** – Passthrough arguments for standard dict. * **kwargs** – Passthrough keyword arguments for standard dict. ## monty.collections.dict2namedtuple(\*args, \*\*kwargs) Helper function to create a `namedtuple` from a dictionary. ## Example ```python >>> t = dict2namedtuple(foo=1, bar="hello") >>> assert t.foo == 1 and t.bar == "hello" ``` ```python >>> t = dict2namedtuple([("foo", 1), ("bar", "hello")]) >>> assert t[0] == t.foo and t[1] == t.bar ``` **WARNING**: * The order of the items in the namedtuple is not deterministic if kwargs are used. namedtuples, however, should always be accessed by attribute hence this behaviour should not represent a serious problem. * Don’t use this function in code in which memory and performance are crucial since a dict is needed to instantiate the tuple! ## *class* monty.collections.frozendict(\*args, \*\*kwargs) Bases: `dict` A dictionary that does not permit changes. The naming violates PEP8 to be consistent with standard Python’s “frozensetâ€� naming. * **Parameters** * **args** – Passthrough arguments for standard dict. * **kwargs** – Passthrough keyword arguments for standard dict. ### update(\*args, \*\*kwargs) * **Parameters** * **args** – Passthrough arguments for standard dict. * **kwargs** – Passthrough keyword arguments for standard dict. ## monty.collections.tree() A tree object, which is effectively a recursive defaultdict that adds tree as members. Usage: ```none x = tree() x[‘a’][‘b’][‘c’] = 1 ``` * **Returns** A tree.monty-2026.10.21/docs/monty.design_patterns.md000066400000000000000000000025031526577750300211040ustar00rootroot00000000000000--- layout: default title: monty.design_patterns.md nav_exclude: true --- # monty.design_patterns module Some common design patterns such as singleton and cached classes. ## *class* monty.design_patterns.NullFile() Bases: `object` A file object that is associated to /dev/null. no-op ## *class* monty.design_patterns.NullStream() Bases: `object` A fake stream with a no-op write. ### write(\*args) Does nothing… :param args: ## monty.design_patterns.cached_class(klass: type[Klass]) Decorator to cache class instances by constructor arguments. This results in a class that behaves like a singleton for each set of constructor arguments, ensuring efficiency. Note that this should be used for *immutable classes only*. Having a cached mutable class makes very little sense. For efficiency, avoid using this decorator for situations where there are many constructor arguments permutations. The keywords argument dictionary is converted to a tuple because dicts are mutable; keywords themselves are strings and so are always hashable, but if any arguments (keyword or positional) are non-hashable, that set of arguments is not cached. ## monty.design_patterns.singleton(cls) This decorator can be used to create a singleton out of a class. Usage: ```default @singleton class MySingleton(): def __init__(): pass ```monty-2026.10.21/docs/monty.dev.md000066400000000000000000000044221526577750300164730ustar00rootroot00000000000000--- layout: default title: monty.dev.md nav_exclude: true --- # monty.dev module This module implements several useful functions and decorators that can be particularly useful for developers. E.g., deprecating methods / classes, etc. ## monty.dev.deprecated(replacement=None, message=None, category=) Decorator to mark classes or functions as deprecated, with a possible replacement. * **Parameters** * **replacement** (*callable*) – A replacement class or method. * **message** (*str*) – A warning message to be displayed. * **category** (*Warning*) – Choose the category of the warning to issue. Defaults to FutureWarning. Another choice can be DeprecationWarning. Note that FutureWarning is meant for end users and is always shown unless silenced. DeprecationWarning is meant for developers and is never shown unless python is run in developmental mode or the filter is changed. Make the choice accordingly. * **Returns** Original function, but with a warning to use the updated class. ## monty.dev.install_excepthook(hook_type=’color’, \*\*kwargs) This function replaces the original python traceback with an improved version from Ipython. Use color for colourful traceback formatting, verbose for Ka-Ping Yee’s “cgitb.pyâ€� version kwargs are the keyword arguments passed to the constructor. See IPython.core.ultratb.py for more info. * **Returns** 0 if hook is installed successfully. ## *class* monty.dev.requires(condition, message) Bases: `object` Decorator to mark classes or functions as requiring a specified condition to be true. This can be used to present useful error messages for optional dependencies. For example, decorating the following code will check if scipy is present and if not, a runtime error will be raised if someone attempts to call the use_scipy function: ```default try: import scipy except ImportError: scipy = None @requires(scipy is not None, "scipy is not present.") def use_scipy(): print(scipy.majver) ``` * **Parameters** * **condition** – Condition necessary to use the class or function. * **message** – A message to be displayed if the condition is not True. * **condition** – A expression returning a bool. * **message** – Message to display if condition is False.monty-2026.10.21/docs/monty.fnmatch.md000066400000000000000000000014751526577750300173420ustar00rootroot00000000000000--- layout: default title: monty.fnmatch.md nav_exclude: true --- # monty.fnmatch module This module provides support for Unix shell-style wildcards ## *class* monty.fnmatch.WildCard(wildcard, sep=’|’) Bases: `object` This object provides an easy-to-use interface for filename matching with shell patterns (fnmatch). ```python >>> w = WildCard("*.nc|*.pdf") >>> w.filter(["foo.nc", "bar.pdf", "hello.txt"]) ['foo.nc', 'bar.pdf'] ``` ```python >>> w.filter("foo.nc") ['foo.nc'] ``` Initializes a WildCard. * **Parameters** * **wildcard** (*str*) – String of tokens separated by sep. Each token represents a pattern. * **sep** (*str*) – Separator for shell patterns. ### filter(names) Returns a list with the names matching the pattern. ### match(name) Returns True if name matches one of the patterns.monty-2026.10.21/docs/monty.fractions.md000066400000000000000000000015261526577750300177070ustar00rootroot00000000000000--- layout: default title: monty.fractions.md nav_exclude: true --- # monty.fractions module Math functions. ## monty.fractions.gcd(\*numbers) Returns the greatest common divisor for a sequence of numbers. * **Parameters** **\*numbers** – Sequence of numbers. * **Returns** (int) Greatest common divisor of numbers. ## monty.fractions.gcd_float(numbers, tol=1e-08) Returns the greatest common divisor for a sequence of numbers. Uses a numerical tolerance, so can be used on floats * **Parameters** * **numbers** – Sequence of numbers. * **tol** – Numerical tolerance * **Returns** (int) Greatest common divisor of numbers. ## monty.fractions.lcm(\*numbers) Return lowest common multiple of a sequence of numbers. * **Parameters** **\*numbers** – Sequence of numbers. * **Returns** (int) Lowest common multiple of numbers.monty-2026.10.21/docs/monty.functools.md000066400000000000000000000071351526577750300177350ustar00rootroot00000000000000--- layout: default title: monty.functools.md nav_exclude: true --- # monty.functools module functools, especially backported from Python 3. ## *exception* monty.functools.TimeoutError(message) Bases: `Exception` Exception class for timeouts. * **Parameters** **message** – Error message ## *class* monty.functools.lazy_property(func) Bases: `object` lazy_property descriptor Used as a decorator to create lazy attributes. Lazy attributes are evaluated on first use. * **Parameters** **func** – Function to decorate. ### *classmethod* invalidate(inst, name) Invalidate a lazy attribute. This obviously violates the lazy contract. A subclass of lazy may however have a contract where invalidation is appropriate. ## monty.functools.lru_cache(maxsize=128, typed=False) Least-recently-used cache decorator, which is a backport of the same function in Python >= 3.2. If *maxsize* is set to None, the LRU features are disabled and the cache can grow without bound. If *typed* is True, arguments of different types will be cached separately. For example, f(3.0) and f(3) will be treated as distinct calls with distinct results. Arguments to the cached function must be hashable. View the cache statistics named tuple (hits, misses, maxsize, currsize) with f.cache_info(). Clear the cache and statistics with f.cache_clear(). Access the underlying function with f.**wrapped**. See: [http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used](http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used) ## monty.functools.prof_main(main) Decorator for profiling main programs. Profiling is activated by prepending the command line options supported by the original main program with the keyword prof. .. rubric:: Example $ script.py arg –foo=1 becomes > $ script.py prof arg –foo=1 The decorated main accepts two new arguments: > prof_file: Name of the output file with profiling data > ```none > If not given, a temporary file is created. > ``` > sortby: Profiling data are sorted according to this value. > ```none > default is “timeâ€�. See sort_stats. > ``` ## monty.functools.return_if_raise(exception_tuple, retval_if_exc, disabled=False) Decorator for functions, methods or properties. Execute the callable in a try block, and return retval_if_exc if one of the exceptions listed in exception_tuple is raised (se also `return_node_if_raise`). Setting disabled to True disables the try except block (useful for debugging purposes). One can use this decorator to define properties. Example: ```default @return_if_raise(ValueError, None) def return_none_if_value_error(self): pass @return_if_raise((ValueError, KeyError), "hello") def another_method(self): pass @property @return_if_raise(AttributeError, None) def name(self): "Name of the object, None if not set." return self._name ``` ## monty.functools.return_none_if_raise(exception_tuple, \*, retval_if_exc=None, disabled=False) This decorator returns None if one of the exceptions is raised. > @return_none_if_raise(ValueError) > def method(self): ## *class* monty.functools.timeout(seconds=1, error_message=’Timeout’) Bases: `object` Timeout function. Use to limit matching to a certain time limit. Note that this works only on Unix-based systems as it uses signal. Usage: try: ```none with timeout(3): do_stuff() ``` except TimeoutError: ```none do_something_else() ``` * **Parameters** * **seconds** (*int*) – Allowed time for function in seconds. * **error_message** (*str*) – An error message. ### handle_timeout(signum, frame) * **Parameters** * **signum** – Return signal from call. * **frame** –monty-2026.10.21/docs/monty.inspect.md000066400000000000000000000015641526577750300173660ustar00rootroot00000000000000--- layout: default title: monty.inspect.md nav_exclude: true --- # monty.inspect module Useful additional functions to help get information about live objects ## monty.inspect.all_subclasses(cls) Given a class cls, this recursive function returns a list with all subclasses, subclasses of subclasses, and so on. ## monty.inspect.caller_name(skip=2) Get a name of a caller in the format module.class.method skip specifies how many levels of stack to skip while getting caller name. skip=1 means “who calls meâ€�, skip=2 “who calls my callerâ€� etc. An empty string is returned if skipped levels exceed stack height Taken from: > [https://gist.github.com/techtonik/2151727](https://gist.github.com/techtonik/2151727) Public Domain, i.e. feel free to copy/paste ## monty.inspect.find_top_pyfile() This function inspects the Cpython frame to find the path of the script.monty-2026.10.21/docs/monty.io.md000066400000000000000000000072721526577750300163320ustar00rootroot00000000000000--- layout: default title: monty.io.md nav_exclude: true --- # monty.io module Augments Python’s suite of IO functions with useful transparent support for compressed files. ## *class* monty.io.FileLock(file_name, timeout=10, delay=0.05) Bases: `object` A file locking mechanism that has context-manager support so you can use it in a with statement. This should be relatively cross-compatible as it doesn’t rely on msvcrt or fcntl for the locking. Taken from [http://www.evanfosmark.com/2009/01/cross-platform-file-locking](http://www.evanfosmark.com/2009/01/cross-platform-file-locking) -support-in-python/ Prepare the file locker. Specify the file to lock and optionally the maximum timeout and the delay between each attempt to lock. * **Parameters** * **file_name** – Name of file to lock. * **timeout** – Maximum timeout for locking. Defaults to 10. * **delay** – Delay between each attempt to lock. Defaults to 0.05. ### Error() alias of `FileLockException` ### acquire() Acquire the lock, if possible. If the lock is in use, it check again every delay seconds. It does this until it either gets the lock or exceeds timeout number of seconds, in which case it throws an exception. ### release() Get rid of the lock by deleting the lockfile. When working in a with statement, this gets automatically called at the end. ## *exception* monty.io.FileLockException() Bases: `Exception` Exception raised by FileLock. ## monty.io.get_open_fds() Return the number of open file descriptors for current process ## monty.io.reverse_readfile(filename: str | Path) A much faster reverse read of file by using Python’s mmap to generate a memory-mapped file. It is slower for very small files than reverse_readline, but at least 2x faster for large files (the primary use of such a method). * **Parameters** **filename** (*str*) – Name of file to read. * **Yields** Lines from the file in reverse order. ## monty.io.reverse_readline(m_file, blk_size=4096, max_mem=4000000) Generator method to read a file line-by-line, but backwards. This allows one to efficiently get data at the end of a file. Based on code by Peter Astrand <[astrand@cendio.se](mailto:astrand@cendio.se)>, using modifications by Raymond Hettinger and Kevin German. [http://code.activestate.com/recipes/439045-read-a-text-file-backwards](http://code.activestate.com/recipes/439045-read-a-text-file-backwards) -yet-another-implementat/ Reads file forwards and reverses in memory for files smaller than the max_mem parameter, or for gzip files where reverse seeks are not supported. Files larger than max_mem are dynamically read backwards. * **Parameters** * **m_file** (*File*) – File stream to read (backwards) * **blk_size** (*int*) – The buffer size. Defaults to 4096. * **max_mem** (*int*) – The maximum amount of memory to involve in this operation. This is used to determine when to reverse a file in-memory versus seeking portions of a file. For bz2 files, this sets the maximum block size. * **Returns** Generator that returns lines from the file. Similar behavior to the file.readline() method, except the lines are returned from the back of the file. ## monty.io.zopen(filename: str | Path, \*args, \*\*kwargs) This function wraps around the bz2, gzip, lzma, xz and standard python’s open function to deal intelligently with bzipped, gzipped or standard text files. * **Parameters** * **filename** (*str/Path*) – filename or pathlib.Path. * **\*args** – Standard args for python open(..). E.g., ‘r’ for read, ‘w’ for write. * **\*\*kwargs** – Standard kwargs for python open(..). * **Returns** File-like object. Supports with context.monty-2026.10.21/docs/monty.itertools.md000066400000000000000000000031621526577750300177410ustar00rootroot00000000000000--- layout: default title: monty.itertools.md nav_exclude: true --- # monty.itertools module Additional tools for iteration. ## monty.itertools.chunks(items, n) Yield successive n-sized chunks from a list-like object. ```python >>> import pprint >>> pprint.pprint(list(chunks(range(1, 25), 10))) [(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), (11, 12, 13, 14, 15, 16, 17, 18, 19, 20), (21, 22, 23, 24)] ``` ## monty.itertools.ilotri(items, diago=True, with_inds=False) A generator that yields the lower triangle of the matrix (items x items) * **Parameters** * **items** – Iterable object with elements [e0, e1, …] * **diago** – False if diagonal matrix elements should be excluded * **with_inds** – If True, (i,j) (e_i, e_j) is returned else (e_i, e_j) ```python >>> for (ij, mate) in ilotri([0,1], with_inds=True): ... print("ij:", ij, "mate:", mate) ij: (0, 0) mate: (0, 0) ij: (1, 0) mate: (1, 0) ij: (1, 1) mate: (1, 1) ``` ## monty.itertools.iterator_from_slice(s) Constructs an iterator given a slice object s. **NOTE**: The function returns an infinite iterator if s.stop is None ## monty.itertools.iuptri(items, diago=True, with_inds=False) A generator that yields the upper triangle of the matrix (items x items) * **Parameters** * **items** – Iterable object with elements [e0, e1, …] * **diago** – False if diagonal matrix elements should be excluded * **with_inds** – If True, (i,j) (e_i, e_j) is returned else (e_i, e_j) ```python >>> for (ij, mate) in iuptri([0,1], with_inds=True): ... print("ij:", ij, "mate:", mate) ij: (0, 0) mate: (0, 0) ij: (0, 1) mate: (0, 1) ij: (1, 1) mate: (1, 1) ```monty-2026.10.21/docs/monty.json.md000066400000000000000000000210171526577750300166650ustar00rootroot00000000000000--- layout: default title: monty.json.md nav_exclude: true --- # monty.json module JSON serialization and deserialization utilities. ## *exception* monty.json.MSONError() Bases: `Exception` Exception class for serialization errors. ## *class* monty.json.MSONable() Bases: `object` This is a mix-in base class specifying an API for msonable objects. MSON is Monty JSON. Essentially, MSONable objects must implement an as_dict method, which must return a json serializable dict and must also support no arguments (though optional arguments to finetune the output is ok), and a from_dict class method that regenerates the object from the dict generated by the as_dict method. The as_dict method should contain the “@moduleâ€� and “@classâ€� keys which will allow the MontyEncoder to dynamically deserialize the class. E.g.: ```default d["@module"] = self.__class__.__module__ d["@class"] = self.__class__.__name__ ``` A default implementation is provided in MSONable, which automatically determines if the class already contains self.argname or self._argname attributes for every arg. If so, these will be used for serialization in the dict format. Similarly, the default from_dict will deserialization classes of such form. An example is given below: ```default class MSONClass(MSONable): def __init__(self, a, b, c, d=1, **kwargs): self.a = a self.b = b self._c = c self._d = d self.kwargs = kwargs ``` For such classes, you merely need to inherit from MSONable and you do not need to implement your own as_dict or from_dict protocol. New to Monty V2.0.6…. Classes can be redirected to moved implementations by putting in the old fully qualified path and new fully qualified path into .monty.yaml in the home folder Example: old_module.old_class: new_module.new_class ### REDIRECT(_ = {_ ) ### as_dict() A JSON serializable dict representation of an object. ### *classmethod* from_dict(d) * **Parameters** **d** – Dict representation. * **Returns** MSONable class. ### to_json() Returns a json string representation of the MSONable object. ### unsafe_hash() Returns an hash of the current object. This uses a generic but low performance method of converting the object to a dictionary, flattening any nested keys, and then performing a hash on the resulting object ### *classmethod* validate_monty(v) pydantic Validator for MSONable pattern ## *class* monty.json.MontyDecoder(\*, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, strict=True, object_pairs_hook=None) Bases: `JSONDecoder` A Json Decoder which supports the MSONable API. By default, the decoder attempts to find a module and name associated with a dict. If found, the decoder will generate a Pymatgen as a priority. If that fails, the original decoded dictionary from the string is returned. Note that nested lists and dicts containing pymatgen object will be decoded correctly as well. Usage: `object_hook`, if specified, will be called with the result of every JSON object decoded and its return value will be used in place of the given `dict`. This can be used to provide custom deserializations (e.g. to support JSON-RPC class hinting). `object_pairs_hook`, if specified will be called with the result of every JSON object decoded with an ordered list of pairs. The return value of `object_pairs_hook` will be used instead of the `dict`. This feature can be used to implement custom decoders. If `object_hook` is also defined, the `object_pairs_hook` takes priority. `parse_float`, if specified, will be called with the string of every JSON float to be decoded. By default this is equivalent to float(num_str). This can be used to use another datatype or parser for JSON floats (e.g. decimal.Decimal). `parse_int`, if specified, will be called with the string of every JSON int to be decoded. By default this is equivalent to int(num_str). This can be used to use another datatype or parser for JSON integers (e.g. float). `parse_constant`, if specified, will be called with one of the following strings: -Infinity, Infinity, NaN. This can be used to raise an exception if invalid JSON numbers are encountered. If `strict` is false (true is the default), then control characters will be allowed inside strings. Control characters in this context are those with character codes in the 0-31 range, including `'\\\\\\\\t'` (tab), `'\\\\\\\\n'`, `'\\\\\\\\r'` and `'\\\\\\\\0'`. # Add it as a *cls* keyword when using json.load json.loads(json_string, cls=MontyDecoder) ## decode(s) Overrides decode from JSONDecoder. * **Parameters** **s** – string * **Returns** Object. ## process_decoded(d) Recursive method to support decoding dicts and lists containing pymatgen objects. ## *class* monty.json.MontyEncoder(\*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None) Bases: `JSONEncoder` A Json Encoder which supports the MSONable API, plus adds support for numpy arrays, datetime objects, bson ObjectIds (requires bson). Usage: ```default # Add it as a *cls* keyword when using json.dump json.dumps(object, cls=MontyEncoder) ``` Constructor for JSONEncoder, with sensible defaults. If skipkeys is false, then it is a TypeError to attempt encoding of keys that are not str, int, float or None. If skipkeys is True, such items are simply skipped. If ensure_ascii is true, the output is guaranteed to be str objects with all incoming non-ASCII characters escaped. If ensure_ascii is false, the output can contain non-ASCII characters. If check_circular is true, then lists, dicts, and custom encoded objects will be checked for circular references during encoding to prevent an infinite recursion (which would cause an RecursionError). Otherwise, no such check takes place. If allow_nan is true, then NaN, Infinity, and -Infinity will be encoded as such. This behavior is not JSON specification compliant, but is consistent with most JavaScript based encoders and decoders. Otherwise, it will be a ValueError to encode such floats. If sort_keys is true, then the output of dictionaries will be sorted by key; this is useful for regression tests to ensure that JSON serializations can be compared on a day-to-day basis. If indent is a non-negative integer, then JSON array elements and object members will be pretty-printed with that indent level. An indent level of 0 will only insert newlines. None is the most compact representation. If specified, separators should be an (item_separator, key_separator) tuple. The default is (’, ‘, ‘: ‘) if *indent* is `None` and (‘,’, ‘: ‘) otherwise. To get the most compact JSON representation, you should specify (‘,’, ‘:’) to eliminate whitespace. If specified, default is a function that gets called for objects that can’t otherwise be serialized. It should return a JSON encodable version of the object or raise a `TypeError`. ### default(o) Overriding default method for JSON encoding. This method does two things: (a) If an object has a to_dict property, return the to_dict output. (b) If the @module and @class keys are not in the to_dict, add them to the output automatically. If the object has no to_dict property, the default Python json encoder default method is called. :param o: Python object. * **Returns** Python dict representation. ## monty.json.jsanitize(obj, strict=False, allow_bson=False, enum_values=False, recursive_msonable=False) This method cleans an input json-like object, either a list or a dict or some sequence, nested or otherwise, by converting all non-string dictionary keys (such as int and float) to strings, and also recursively encodes all objects using Monty’s as_dict() protocol. * **Parameters** * **obj** – input json-like object. * **strict** (*bool*) – This parameters sets the behavior when jsanitize encounters an object it does not understand. If strict is True, jsanitize will try to get the as_dict() attribute of the object. If no such attribute is found, an attribute error will be thrown. If strict is False, jsanitize will simply call str(object) to convert the object to a string representation. * **allow_bson** (*bool*) – This parameters sets the behavior when jsanitize encounters a bson supported type such as objectid and datetime. If True, such bson types will be ignored, allowing for proper insertion into MongoDB databases. * **enum_values** (*bool*) – Convert Enums to their values. * **recursive_msonable** (*bool*) – If True, uses .as_dict() for MSONables regardless of the value of strict. * **Returns** Sanitized dict that can be json serialized.monty-2026.10.21/docs/monty.logging.md000066400000000000000000000012631526577750300173430ustar00rootroot00000000000000--- layout: default title: monty.logging.md nav_exclude: true --- # monty.logging module Logging tools ## monty.logging.enable_logging(main) This decorator is used to decorate main functions. It adds the initialization of the logger and an argument parser that allows one to select the loglevel. Useful if we are writing simple main functions that call libraries where the logging module is used * **Parameters** **main** – main function. ## monty.logging.logged(level=10) Useful logging decorator. If a method is logged, the beginning and end of the method call will be logged at a pre-specified level. * **Parameters** **level** – Level to log method at. Defaults to DEBUG.monty-2026.10.21/docs/monty.math.md000066400000000000000000000006661526577750300166540ustar00rootroot00000000000000--- layout: default title: monty.math.md nav_exclude: true --- # monty.math module Addition math functions. ## monty.math.nCr(n, r) Calculates nCr. * **Parameters** * **n** (*int*) – total number of items. * **r** (*int*) – items to choose * **Returns** nCr. ## monty.math.nPr(n, r) Calculates nPr. * **Parameters** * **n** (*int*) – total number of items. * **r** (*int*) – items to permute * **Returns** nPr.monty-2026.10.21/docs/monty.md000066400000000000000000000074131526577750300157210ustar00rootroot00000000000000--- layout: default title: API Documentation nav_order: 5 --- # monty package Monty is the missing complement to Python. Monty implements supplementary useful functions for Python that are not part of the standard library. Examples include useful utilities like transparent support for zipped files, useful design patterns such as singleton and cached_class, and many more. ## Subpackages * [monty.os package](monty.os.md) * `cd()` * `makedirs_p()` * [monty.os.path module](monty.os.path.md) * `find_exts()` * `zpath()` * [monty.bisect module](monty.bisect.md) * `find_ge()` * `find_gt()` * `find_le()` * `find_lt()` * `index()` * [monty.collections module](monty.collections.md) * `AttrDict` * `AttrDict.copy()` * `FrozenAttrDict` * `MongoDict` * `Namespace` * `Namespace.update()` * `dict2namedtuple()` * `frozendict` * `frozendict.update()` * `tree()` * [monty.design_patterns module](monty.design_patterns.md) * `NullFile` * `NullStream` * `NullStream.write()` * `cached_class()` * `singleton()` * [monty.dev module](monty.dev.md) * `deprecated()` * `install_excepthook()` * `requires` * [monty.fnmatch module](monty.fnmatch.md) * `WildCard` * `WildCard.filter()` * `WildCard.match()` * [monty.fractions module](monty.fractions.md) * `gcd()` * `gcd_float()` * `lcm()` * [monty.functools module](monty.functools.md) * `TimeoutError` * `lazy_property` * `lazy_property.invalidate()` * `lru_cache()` * `prof_main()` * `return_if_raise()` * `return_none_if_raise()` * `timeout` * `timeout.handle_timeout()` * [monty.inspect module](monty.inspect.md) * `all_subclasses()` * `caller_name()` * `find_top_pyfile()` * [monty.io module](monty.io.md) * `FileLock` * `FileLock.Error` * `FileLock.acquire()` * `FileLock.release()` * `FileLockException` * `get_open_fds()` * `reverse_readfile()` * `reverse_readline()` * `zopen()` * [monty.itertools module](monty.itertools.md) * `chunks()` * `ilotri()` * `iterator_from_slice()` * `iuptri()` * [monty.json module](monty.json.md) * `MSONError` * `MSONable` * `MSONable.REDIRECT` * `MSONable.as_dict()` * `MSONable.from_dict()` * `MSONable.to_json()` * `MSONable.unsafe_hash()` * `MSONable.validate_monty()` * `MontyDecoder` * `MontyDecoder.decode()` * `MontyDecoder.process_decoded()` * `MontyEncoder` * `MontyEncoder.default()` * `jsanitize()` * [monty.logging module](monty.logging.md) * `enable_logging()` * `logged()` * [monty.math module](monty.math.md) * `nCr()` * `nPr()` * [monty.msgpack module](monty.msgpack.md) * `default()` * `object_hook()` * [monty.multiprocessing module](monty.multiprocessing.md) * `imap_tqdm()` * [monty.operator module](monty.operator.md) * `operator_from_str()` * [monty.pprint module](monty.pprint.md) * `DisplayEcoder` * `DisplayEcoder.default()` * `draw_tree()` * `pprint_json()` * `pprint_table()` * [monty.re module](monty.re.md) * `regrep()` * [monty.serialization module](monty.serialization.md) * `dumpfn()` * `loadfn()` * [monty.shutil module](monty.shutil.md) * `compress_dir()` * `compress_file()` * `copy_r()` * `decompress_dir()` * `decompress_file()` * `gzip_dir()` * `remove()` * [monty.string module](monty.string.md) * `boxed()` * `indent()` * `is_string()` * `list_strings()` * `make_banner()` * `marquee()` * `remove_non_ascii()` * `unicode2str()` * [monty.subprocess module](monty.subprocess.md) * `Command` * `Command.retcode` * `Command.killed` * `Command.output` * `Command.error` * `Command.run()` * [monty.tempfile module](monty.tempfile.md) * `ScratchDir` * `ScratchDir.SCR_LINK` * [monty.termcolor module](monty.termcolor.md) * `colored()` * `cprint()`monty-2026.10.21/docs/monty.msgpack.md000066400000000000000000000011311526577750300173340ustar00rootroot00000000000000--- layout: default title: monty.msgpack.md nav_exclude: true --- # monty.msgpack module msgpack serialization and deserialization utilities. Right now, this is a stub using monty.json encoder and decoders. The naming is just for clearer usage with msgpack’s default and object_hook naming. ## monty.msgpack.default(obj) For use with msgpack.packb(obj, default=default). Supports Monty’s as_dict protocol, numpy arrays and datetime. ## monty.msgpack.object_hook(d) For use with msgpack.unpackb(dict, object_hook=object_hook.). Supports Monty’s as_dict protocol, numpy arrays and datetime.monty-2026.10.21/docs/monty.multiprocessing.md000066400000000000000000000011371526577750300211440ustar00rootroot00000000000000--- layout: default title: monty.multiprocessing.md nav_exclude: true --- # monty.multiprocessing module Multiprocessing utilities. ## monty.multiprocessing.imap_tqdm(nprocs: int, func: Callable, iterable: Iterable, \*args, \*\*kwargs) A wrapper around Pool.imap. Creates a Pool with nprocs and then runs a f unction over an iterable with progress bar. * **Parameters** * **nprocs** – Number of processes * **func** – Callable * **iterable** – Iterable of arguments. * **args** – Passthrough to Pool.imap * **kwargs** – Passthrough to Pool.imap * **Returns** Results of Pool.imap.monty-2026.10.21/docs/monty.operator.md000066400000000000000000000004101526577750300175410ustar00rootroot00000000000000--- layout: default title: monty.operator.md nav_exclude: true --- # monty.operator module Useful additional functions for operators ## monty.operator.operator_from_str(op) Return the operator associated to the given string op. * **Raises** **KeyError** –monty-2026.10.21/docs/monty.os.md000066400000000000000000000014601526577750300163350ustar00rootroot00000000000000--- layout: default title: monty.os.md nav_exclude: true --- # monty.os package Os functions, e.g., cd, makedirs_p. ## monty.os.cd(path) A Fabric-inspired cd context that temporarily changes directory for performing some tasks, and returns to the original working directory afterwards. E.g., > with cd(“/my/path/â€�): > ```none > do_something() > ``` * **Parameters** **path** – Path to cd to. ## monty.os.makedirs_p(path, \*\*kwargs) Wrapper for os.makedirs that does not raise an exception if the directory already exists, in the fashion of “mkdir -pâ€� command. The check is performed in a thread-safe way * **Parameters** * **path** – path of the directory to create * **kwargs** – standard kwargs for os.makedirs * [monty.os.path module](monty.os.path.md) * `find_exts()` * `zpath()`monty-2026.10.21/docs/monty.os.path.md000066400000000000000000000033361526577750300172740ustar00rootroot00000000000000--- layout: default title: monty.os.path.md nav_exclude: true --- # monty.os.path module Path based methods, e.g., which, zpath, etc. ## monty.os.path.find_exts(top, exts, exclude_dirs=None, include_dirs=None, match_mode=’basename’) Find all files with the extension listed in exts that are located within the directory tree rooted at top (including top itself, but excluding ‘.’ and ‘..’) * **Parameters** * **top** (*str*) – Root directory * **exts** (*str*\* or **list** of \**strings*) – List of extensions. * **exclude_dirs** (*str*) – Wildcards used to exclude particular directories. Can be concatenated via | * **include_dirs** (*str*) – Wildcards used to select particular directories. include_dirs and exclude_dirs are mutually exclusive * **match_mode** (*str*) – “basenameâ€� if match should be done on the basename. “abspathâ€� for absolute path. * **Returns** Absolute paths of the files. * **Return type** (list of str) Examples: ```default # Find all pdf and ps files starting from the current directory. find_exts(".", ("pdf", "ps")) # Find all pdf files, exclude hidden directories and dirs whose name # starts with `_` find_exts(".", "pdf", exclude_dirs="_*|.*") # Find all ps files, in the directories whose basename starts with # output. find_exts(".", "ps", include_dirs="output*")) ``` ## monty.os.path.zpath(filename) Returns an existing (zipped or unzipped) file path given the unzipped version. If no path exists, returns the filename unmodified. * **Parameters** **filename** – filename without zip extension * **Returns** filename with a zip extension (unless an unzipped version exists). If filename is not found, the same filename is returned unchanged.monty-2026.10.21/docs/monty.pprint.md000066400000000000000000000071541526577750300172360ustar00rootroot00000000000000--- layout: default title: monty.pprint.md nav_exclude: true --- # monty.pprint module Pretty printing functions. ## *class* monty.pprint.DisplayEcoder(\*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None) Bases: `JSONEncoder` Help convert dicts and objects to a format that can be displayed in notebooks Constructor for JSONEncoder, with sensible defaults. If skipkeys is false, then it is a TypeError to attempt encoding of keys that are not str, int, float or None. If skipkeys is True, such items are simply skipped. If ensure_ascii is true, the output is guaranteed to be str objects with all incoming non-ASCII characters escaped. If ensure_ascii is false, the output can contain non-ASCII characters. If check_circular is true, then lists, dicts, and custom encoded objects will be checked for circular references during encoding to prevent an infinite recursion (which would cause an RecursionError). Otherwise, no such check takes place. If allow_nan is true, then NaN, Infinity, and -Infinity will be encoded as such. This behavior is not JSON specification compliant, but is consistent with most JavaScript based encoders and decoders. Otherwise, it will be a ValueError to encode such floats. If sort_keys is true, then the output of dictionaries will be sorted by key; this is useful for regression tests to ensure that JSON serializations can be compared on a day-to-day basis. If indent is a non-negative integer, then JSON array elements and object members will be pretty-printed with that indent level. An indent level of 0 will only insert newlines. None is the most compact representation. If specified, separators should be an (item_separator, key_separator) tuple. The default is (’, ‘, ‘: ‘) if *indent* is `None` and (‘,’, ‘: ‘) otherwise. To get the most compact JSON representation, you should specify (‘,’, ‘:’) to eliminate whitespace. If specified, default is a function that gets called for objects that can’t otherwise be serialized. It should return a JSON encodable version of the object or raise a `TypeError`. ### default(o) Try diffent ways of converting the present object for displaying ## monty.pprint.draw_tree(node, child_iter=>, text_str=>) * **Parameters** * **node** – the root of the tree to be drawn, * **child_iter** – function that when called with a node, returns an iterable over all its children * **text_str** – turns a node into the text to be displayed in the tree. The default implementations of these two arguments retrieve the children by accessing node.children and simply use str(node) to convert a node to a string. The resulting tree is drawn into a buffer and returned as a string. Based on [https://pypi.python.org/pypi/asciitree/](https://pypi.python.org/pypi/asciitree/) ## monty.pprint.pprint_json(data) Display a tree-like object in a jupyter notebook. Allows for collapsible interactive interaction with data. * **Parameters** **data** – a dictionary or object Based on: [https://gist.github.com/jmmshn/d37d5a1be80a6da11f901675f195ca22](https://gist.github.com/jmmshn/d37d5a1be80a6da11f901675f195ca22) ## monty.pprint.pprint_table(table, out=<_io.TextIOWrapper name=’’ mode=’w’ encoding=’utf-8’>, rstrip=False) Prints out a table of data, padded for alignment Each row must have the same number of columns. * **Parameters** * **table** – The table to print. A list of lists. * **out** – Output stream (file-like object) * **rstrip** – if True, trailing withespaces are removed from the entries.monty-2026.10.21/docs/monty.re.md000066400000000000000000000022011526577750300163140ustar00rootroot00000000000000--- layout: default title: monty.re.md nav_exclude: true --- # monty.re module Helpful regex based functions. E.g., grepping. ## monty.re.regrep(filename, patterns, reverse=False, terminate_on_match=False, postprocess=) A powerful regular expression version of grep. * **Parameters** * **filename** (*str*) – Filename to grep. * **patterns** (*dict*) – A dict of patterns, e.g., {“energyâ€�: râ€�energy\\(sigma->0\\)\\s+=\\s+([\\d-.]+)â€�}. * **reverse** (*bool*) – Read files in reverse. Defaults to false. Useful for large files, especially when used with terminate_on_match. * **terminate_on_match** (*bool*) – Whether to terminate when there is at least one match in each key in pattern. * **postprocess** (*callable*) – A post processing function to convert all matches. Defaults to str, i.e., no change. * **Returns** > {key1: [[[matches…], lineno], [[matches…], lineno], > ```none > [[matches…], lineno], …], > ``` > key2: …} For reverse reads, the lineno is given as a -ve number. Please note that 0-based indexing is used. * **Return type** A dict of the following formmonty-2026.10.21/docs/monty.serialization.md000066400000000000000000000036321526577750300205740ustar00rootroot00000000000000--- layout: default title: monty.serialization.md nav_exclude: true --- # monty.serialization module This module implements serialization support for common formats such as json and yaml. ## monty.serialization.dumpfn(obj, fn, \*args, fmt=None, \*\*kwargs) Dump to a json/yaml directly by filename instead of a File-like object. File may also be a BZ2 (“.BZ2â€�) or GZIP (“.GZâ€�, “.Zâ€�) compressed file. For YAML, ruamel.yaml must be installed. The file type is automatically detected from the file extension (case insensitive). YAML is assumed if the filename contains “.yamlâ€� or “.ymlâ€�. Msgpack is assumed if the filename contains “.mpkâ€�. JSON is otherwise assumed. * **Parameters** * **obj** (*object*) – Object to dump. * **fn** (*str/Path*) – filename or pathlib.Path. * **\*args** – Any of the args supported by json/yaml.dump. * **\*\*kwargs** – Any of the kwargs supported by json/yaml.dump. * **Returns** (object) Result of json.load. ## monty.serialization.loadfn(fn, \*args, fmt=None, \*\*kwargs) Loads json/yaml/msgpack directly from a filename instead of a File-like object. File may also be a BZ2 (“.BZ2â€�) or GZIP (“.GZâ€�, “.Zâ€�) compressed file. For YAML, ruamel.yaml must be installed. The file type is automatically detected from the file extension (case insensitive). YAML is assumed if the filename contains “.yamlâ€� or “.ymlâ€�. Msgpack is assumed if the filename contains “.mpkâ€�. JSON is otherwise assumed. * **Parameters** * **fn** (*str/Path*) – filename or pathlib.Path. * **\*args** – Any of the args supported by json/yaml.load. * **fmt** (*string*) – If specified, the fmt specified would be used instead of autodetection from filename. Supported formats right now are “jsonâ€�, “yamlâ€� or “mpkâ€�. * **\*\*kwargs** – Any of the kwargs supported by json/yaml.load. * **Returns** (object) Result of json/yaml/msgpack.load.monty-2026.10.21/docs/monty.shutil.md000066400000000000000000000050771526577750300172340ustar00rootroot00000000000000--- layout: default title: monty.shutil.md nav_exclude: true --- # monty.shutil module Copying and zipping utilities. Works on directories mostly. ## monty.shutil.compress_dir(path, compression=’gz’) Recursively compresses all files in a directory. Note that this compresses all files singly, i.e., it does not create a tar archive. For that, just use Python tarfile class. * **Parameters** * **path** (*str*) – Path to parent directory. * **compression** (*str*) – A compression mode. Valid options are “gzâ€� or “bz2â€�. Defaults to gz. ## monty.shutil.compress_file(filepath, compression=’gz’) Compresses a file with the correct extension. Functions like standard Unix command line gzip and bzip2 in the sense that the original uncompressed files are not retained. * **Parameters** * **filepath** (*str*) – Path to file. * **compression** (*str*) – A compression mode. Valid options are “gzâ€� or “bz2â€�. Defaults to “gzâ€�. ## monty.shutil.copy_r(src, dst) Implements a recursive copy function similar to Unix’s “cp -râ€� command. Surprisingly, python does not have a real equivalent. shutil.copytree only works if the destination directory is not present. * **Parameters** * **src** (*str*) – Source folder to copy. * **dst** (*str*) – Destination folder. ## monty.shutil.decompress_dir(path) Recursively decompresses all files in a directory. * **Parameters** **path** (*str*) – Path to parent directory. ## monty.shutil.decompress_file(filepath) Decompresses a file with the correct extension. Automatically detects gz, bz2 or z extension. * **Parameters** **filepath** (*str*) – Path to file. * **Returns** The decompressed file path. * **Return type** str ## monty.shutil.gzip_dir(path, compresslevel=6) Gzips all files in a directory. Note that this is different from shutil.make_archive, which creates a tar archive. The aim of this method is to create gzipped files that can still be read using common Unix-style commands like zless or zcat. * **Parameters** * **path** (*str*) – Path to directory. * **compresslevel** (*int*) – Level of compression, 1-9. 9 is default for GzipFile, 6 is default for gzip. ## monty.shutil.remove(path, follow_symlink=False) Implements a remove function that will delete files, folder trees and symlink trees. 1.) Remove a file 2.) Remove a symlink and follow into with a recursive rm if follow_symlink 3.) Remove directory with rmtree * **Parameters** * **path** (*str*) – path to remove * **follow_symlink** (*bool*) – follow symlinks and removes whatever is in themmonty-2026.10.21/docs/monty.string.md000066400000000000000000000044431526577750300172260ustar00rootroot00000000000000--- layout: default title: monty.string.md nav_exclude: true --- # monty.string module Useful additional string functions. ## monty.string.boxed(msg, ch=’=’, pad=5) Returns a string in a box * **Parameters** * **msg** – Input string. * **ch** – Character used to form the box. * **pad** – Number of characters ch added before and after msg. ```python >>> print(boxed("hello", ch="*", pad=2)) *********** ** hello ** *********** ``` ## monty.string.indent(lines, amount, ch=’ ‘) Indent the lines in a string by padding each one with proper number of pad characters ## monty.string.is_string(s) True if s behaves like a string (duck typing test). ## monty.string.list_strings(arg) Always return a list of strings, given a string or list of strings as input. * **Examples** ```python >>> list_strings('A single string') ['A single string'] ``` ```python >>> list_strings(['A single string in a list']) ['A single string in a list'] ``` ```python >>> list_strings(['A','list','of','strings']) ['A', 'list', 'of', 'strings'] ``` ## monty.string.make_banner(s, width=78, mark=’\*’) * **Parameters** * **s** – String * **width** – Width of banner. Defaults to 78. * **mark** – The mark used to create the banner. * **Returns** Banner string. ## monty.string.marquee(text=’’, width=78, mark=’\*’) Return the input string centered in a ‘marquee’. * **Parameters** * **text** (*str*) – Input string * **width** (*int*) – Width of final output string. * **mark** (*str*) – Character used to fill string. * **Examples** ```python >>> marquee('A test', width=40) '**************** A test ****************' ``` ```python >>> marquee('A test', width=40, mark='-') '---------------- A test ----------------' ``` marquee(‘A test’,40, ‘ ‘) ‘ A test ‘ ## monty.string.remove_non_ascii(s) Remove non-ascii characters in a file. Needed when support for non-ASCII is not available. * **Parameters** **s** (*str*) – Input string * **Returns** String with all non-ascii characters removed. ## monty.string.unicode2str(s) Forces a unicode to a string in Python 2, but transparently handles Python 3. * **Parameters** **s** (*str/unicode*) – Input string / unicode. * **Returns** str in Python 2. Unchanged otherwise.monty-2026.10.21/docs/monty.subprocess.md000066400000000000000000000021101526577750300200750ustar00rootroot00000000000000--- layout: default title: monty.subprocess.md nav_exclude: true --- # monty.subprocess module Calling shell processes. ## *class* monty.subprocess.Command(command) Bases: `object` Enables to run subprocess commands in a different thread with TIMEOUT option. Based on jcollado’s solution: ```none [http://stackoverflow.com/questions/1191374/subprocess-with-timeout/4825933#4825933](http://stackoverflow.com/questions/1191374/subprocess-with-timeout/4825933#4825933) ``` and ```none [https://gist.github.com/kirpit/1306188](https://gist.github.com/kirpit/1306188) ``` ### retcode() Return code of the subprocess ### killed() True if subprocess has been killed due to the timeout ### output() stdout of the subprocess ### error() stderr of the subprocess ## Example com = Command(“sleep 1â€�).run(timeout=2) print(com.retcode, com.killed, com.output, com.output) * **Parameters** **command** – Command to execute ### run(timeout=None, \*\*kwargs) Run a command in a separated thread and wait timeout seconds. kwargs are keyword arguments passed to Popen. Return: selfmonty-2026.10.21/docs/monty.tempfile.md000066400000000000000000000053631526577750300175270ustar00rootroot00000000000000--- layout: default title: monty.tempfile.md nav_exclude: true --- # monty.tempfile module Temporary directory and file creation utilities. ## *class* monty.tempfile.ScratchDir(rootpath, create_symbolic_link=False, copy_from_current_on_enter=False, copy_to_current_on_exit=False, gzip_on_exit=False, delete_removed_files=True) Bases: `object` **NOTE**: With effect from Python 3.2, tempfile.TemporaryDirectory already implements much of the functionality of ScratchDir. However, it does not provide options for copying of files to and from (though it is possible to do this with other methods provided by shutil). Creates a “withâ€� context manager that automatically handles creation of temporary directories (utilizing Python’s build in temp directory functions) and cleanup when done. This improves on Python’s built in functions by allowing for truly temporary workspace that are deleted when it is done. The way it works is as follows: 1. Create a temp dir in specified root path. 2. Optionally copy input files from current directory to temp dir. 3. Change to temp dir. 4. User performs specified operations. 5. Optionally copy generated output files back to original directory. 6. Change back to original directory. 7. Delete temp dir. Initializes scratch directory given a **root** path. There is no need to try to create unique directory names. The code will generate a temporary sub directory in the rootpath. The way to use this is using a with context manager. Example: ```default with ScratchDir("/scratch"): do_something() ``` If the root path does not exist or is None, this will function as a simple pass through, i.e., nothing happens. * **Parameters** * **rootpath** (*str/Path*) – Path in which to create temp subdirectories. If this is None, no temp directories will be created and this will just be a simple pass through. * **create_symbolic_link** (*bool*) – Whether to create a symbolic link in the current working directory to the scratch directory created. * **copy_from_current_on_enter** (*bool*) – Whether to copy all files from the current directory (recursively) to the temp dir at the start, e.g., if input files are needed for performing some actions. Defaults to False. * **copy_to_current_on_exit** (*bool*) – Whether to copy files from the scratch to the current directory (recursively) at the end. E .g., if output files are generated during the operation. Defaults to False. * **gzip_on_exit** (*bool*) – Whether to gzip the files generated in the ScratchDir before copying them back. Defaults to False. * **delete_removed_files** (*bool*) – Whether to delete files in the cwd that are removed from the tmp dir. Defaults to True ### SCR_LINK(_ = ‘scratch_link_ )monty-2026.10.21/docs/monty.termcolor.md000066400000000000000000000037311526577750300177250ustar00rootroot00000000000000--- layout: default title: monty.termcolor.md nav_exclude: true --- # monty.termcolor module Copyright (c) 2008-2011 Volvox Development Team # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Softwareâ€�), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED “AS ISâ€�, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # Author: Konstantin Lepa <[konstantin.lepa@gmail.com](mailto:konstantin.lepa@gmail.com)> ANSII Color formatting for output in terminal. ## monty.termcolor.colored(text, color=None, on_color=None, attrs=None) Colorize text. Available text colors: ```none red, green, yellow, blue, magenta, cyan, white. ``` Available text highlights: ```none on_red, on_green, on_yellow, on_blue, on_magenta, on_cyan, on_white. ``` Available attributes: ```none bold, dark, underline, blink, reverse, concealed. ``` ## Example colored(‘Hello, World!’, ‘red’, ‘on_grey’, [‘blue’, ‘blink’]) colored(‘Hello, World!’, ‘green’) ## monty.termcolor.cprint(text, color=None, on_color=None, attrs=None, \*\*kwargs) Print colorize text. It accepts arguments of print function.monty-2026.10.21/pylintrc000066400000000000000000000475401526577750300150750ustar00rootroot00000000000000[MASTER] # Analyse import fallback blocks. This can be used to support both Python 2 and # 3 compatible code, which means that the block might have code that exists # only in one or another interpreter, leading to false positives when analysed. analyse-fallback-blocks=no # Load and enable all available extensions. Use --list-extensions to see a list # all available extensions. #enable-all-extensions= # In error mode, checkers without error messages are disabled and for others, # only the ERROR messages are displayed, and no reports are done by default. #errors-only= # Always return a 0 (non-error) status code, even if lint errors are found. # This is primarily useful in continuous integration scripts. #exit-zero= # A comma-separated list of package or module names from where C extensions may # be loaded. Extensions are loading into the active Python interpreter and may # run arbitrary code. extension-pkg-allow-list= # A comma-separated list of package or module names from where C extensions may # be loaded. Extensions are loading into the active Python interpreter and may # run arbitrary code. (This is an alternative name to extension-pkg-allow-list # for backward compatibility.) extension-pkg-whitelist= # Return non-zero exit code if any of these messages/categories are detected, # even if score is above --fail-under value. Syntax same as enable. Messages # specified are enabled, while categories only check already-enabled messages. fail-on= # Specify a score threshold to be exceeded before program exits with error. fail-under=10 # Interpret the stdin as a python script, whose filename needs to be passed as # the module_or_package argument. #from-stdin= # Files or directories to be skipped. They should be base names, not paths. ignore=CVS,tests,chemenv,abinit,defects # Add files or directories matching the regex patterns to the ignore-list. The # regex matches against paths and can be in Posix or Windows format. ignore-paths= # Files or directories matching the regex patterns are skipped. The regex # matches against base names, not paths. The default value ignores Emacs file # locks ignore-patterns=^\.# # List of module names for which member attributes should not be checked # (useful for modules/projects where namespaces are manipulated during runtime # and thus existing member attributes cannot be deduced by static analysis). It # supports qualified module names, as well as Unix pattern matching. ignored-modules= # Python code to execute, usually for sys.path manipulation such as # pygtk.require(). #init-hook= # Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the # number of processors available to use. jobs=1 # Control the amount of potential inferred values when inferring a single # object. This can help the performance when dealing with large functions or # complex, nested conditions. limit-inference-results=100 # List of plugins (as comma separated values of python module names) to load, # usually to register additional checkers. load-plugins= # Pickle collected data for later comparisons. persistent=yes # Minimum Python version to use for version dependent checks. Will default to # the version used to run pylint. py-version=3.9 # Discover python modules and packages in the file system subtree. recursive=no # When enabled, pylint would attempt to guess common misconfiguration and emit # user-friendly hints instead of false-positive error messages. suggestion-mode=yes # Allow loading of arbitrary C extensions. Extensions are imported into the # active Python interpreter and may run arbitrary code. unsafe-load-any-extension=no # In verbose mode, extra non-checker-related info will be displayed. #verbose= [REPORTS] # Python expression which should return a score less than or equal to 10. You # have access to the variables 'fatal', 'error', 'warning', 'refactor', # 'convention', and 'info' which contain the number of messages in each # category, as well as 'statement' which is the total number of statements # analyzed. This score is used by the global evaluation report (RP0004). evaluation=max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)) # Template used to display messages. This is a python new-style format string # used to format the message information. See doc for all details. msg-template= # Set the output format. Available formats are text, parseable, colorized, json # and msvs (visual studio). You can also give a reporter class, e.g. # mypackage.mymodule.MyReporterClass. #output-format= # Tells whether to display a full report or only the messages. reports=no # Activate the evaluation score. score=yes [MESSAGES CONTROL] # Only show warnings with the listed confidence levels. Leave empty to show # all. Valid levels: HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE, # UNDEFINED. confidence=HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE, UNDEFINED # Disable the message, report, category or checker with the given id(s). You # can either give multiple identifiers separated by comma (,) or put this # option multiple times (only on the command line, not in the configuration # file where it should appear only once). You can also use "--disable=all" to # disable everything first and then re-enable specific checks. For example, if # you want to run only the similarities checker, you can use "--disable=all # --enable=similarities". If you want to run only the classes checker, but have # no Warning level messages displayed, use "--disable=all --enable=classes # --disable=W". disable=raw-checker-failed, bad-inline-option, locally-disabled, file-ignored, suppressed-message, useless-suppression, deprecated-pragma, use-symbolic-message-instead, C0103, W, R, E1120, E1123, C0201, E0401, E0611, C0415, C0114, C0115, C0116, C0302, # C0209 # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option # multiple time (only on the command line, not in the configuration file where # it should appear only once). See also the "--disable" option for examples. enable=c-extension-no-member [LOGGING] # The type of string formatting that logging methods do. `old` means using % # formatting, `new` is for `{}` formatting. logging-format-style=old # Logging modules to check that the string format arguments are in logging # function parameter format. logging-modules=logging [SPELLING] # Limits count of emitted suggestions for spelling mistakes. max-spelling-suggestions=4 # Spelling dictionary name. Available dictionaries: none. To make it work, # install the 'python-enchant' package. spelling-dict= # List of comma separated words that should be considered directives if they # appear at the beginning of a comment and should not be checked. spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy: # List of comma separated words that should not be checked. spelling-ignore-words= # A path to a file that contains the private dictionary; one word per line. spelling-private-dict-file= # Tells whether to store unknown words to the private dictionary (see the # --spelling-private-dict-file option) instead of raising a message. spelling-store-unknown-words=no [MISCELLANEOUS] # List of note tags to take in consideration, separated by a comma. notes=FIXME, XXX, TODO # Regular expression of note tags to take in consideration. notes-rgx= [TYPECHECK] # List of decorators that produce context managers, such as # contextlib.contextmanager. Add to this list to register other decorators that # produce valid context managers. contextmanager-decorators=contextlib.contextmanager # List of members which are set dynamically and missed by pylint inference # system, and so shouldn't trigger E1101 when accessed. Python regular # expressions are accepted. generated-members= # Tells whether to warn about missing members when the owner of the attribute # is inferred to be None. ignore-none=yes # This flag controls whether pylint should warn about no-member and similar # checks whenever an opaque object is returned when inferring. The inference # can return multiple potential results while evaluating a Python object, but # some branches might not be evaluated, which results in partial inference. In # that case, it might be useful to still emit no-member and other checks for # the rest of the inferred objects. ignore-on-opaque-inference=yes # List of symbolic message names to ignore for Mixin members. ignored-checks-for-mixins=no-member, not-async-context-manager, not-context-manager, attribute-defined-outside-init # List of class names for which member attributes should not be checked (useful # for classes with dynamically set attributes). This supports the use of # qualified names. ignored-classes=optparse.Values,thread._local,_thread._local,argparse.Namespace # Show a hint with possible names when a member name was not found. The aspect # of finding the hint is based on edit distance. missing-member-hint=yes # The minimum edit distance a name should have in order to be considered a # similar match for a missing member name. missing-member-hint-distance=1 # The total number of similar names that should be taken in consideration when # showing a hint for a missing member. missing-member-max-choices=1 # Regex pattern to define which classes are considered mixins. mixin-class-rgx=.*[Mm]ixin # List of decorators that change the signature of a decorated function. signature-mutators= [CLASSES] # Warn about protected attribute access inside special methods check-protected-access-in-special-methods=no # List of method names used to declare (i.e. assign) instance attributes. defining-attr-methods=__init__, __new__, setUp, __post_init__ # List of member names, which should be excluded from the protected access # warning. exclude-protected=_asdict, _fields, _replace, _source, _make # List of valid names for the first argument in a class method. valid-classmethod-first-arg=cls # List of valid names for the first argument in a metaclass class method. valid-metaclass-classmethod-first-arg=cls [VARIABLES] # List of additional names supposed to be defined in builtins. Remember that # you should avoid defining new builtins when possible. additional-builtins= # Tells whether unused global variables should be treated as a violation. allow-global-unused-variables=yes # List of names allowed to shadow builtins allowed-redefined-builtins= # List of strings which can identify a callback function by name. A callback # name must start or end with one of those strings. callbacks=cb_, _cb # A regular expression matching the name of dummy variables (i.e. expected to # not be used). dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ # Argument names that match this expression will be ignored. Default to name # with leading underscore. ignored-argument-names=_.*|^ignored_|^unused_ # Tells whether we should check for unused import in __init__ files. init-import=no # List of qualified module names which can have objects that can redefine # builtins. redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io [FORMAT] # Expected format of line ending, e.g. empty (any line ending), LF or CRLF. expected-line-ending-format= # Regexp for a line that is allowed to be longer than the limit. ignore-long-lines=^\s*(# )??$ # Number of spaces of indent required inside a hanging or continued line. indent-after-paren=4 # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 # tab). indent-string=' ' # Maximum number of characters on a single line. max-line-length=120 # Maximum number of lines in a module. max-module-lines=1000 # Allow the body of a class to be on the same line as the declaration if body # contains single statement. single-line-class-stmt=no # Allow the body of an if to be on the same line as the test if there is no # else. single-line-if-stmt=no [IMPORTS] # List of modules that can be imported at any level, not just the top level # one. allow-any-import-level= # Allow wildcard imports from modules that define __all__. allow-wildcard-with-all=no # Deprecated modules which should not be used, separated by a comma. deprecated-modules= # Output a graph (.gv or any supported image format) of external dependencies # to the given file (report RP0402 must not be disabled). ext-import-graph= # Output a graph (.gv or any supported image format) of all (i.e. internal and # external) dependencies to the given file (report RP0402 must not be # disabled). import-graph= # Output a graph (.gv or any supported image format) of internal dependencies # to the given file (report RP0402 must not be disabled). int-import-graph= # Force import order to recognize a module as part of the standard # compatibility libraries. known-standard-library= # Force import order to recognize a module as part of a third party library. known-third-party=enchant # Couples of modules and preferred modules, separated by a comma. preferred-modules= [EXCEPTIONS] # Exceptions that will emit a warning when caught. overgeneral-exceptions=BaseException, Exception [REFACTORING] # Maximum number of nested blocks for function / method body max-nested-blocks=5 # Complete name of functions that never returns. When checking for # inconsistent-return-statements if a never returning function is called then # it will be considered as an explicit return statement and no message will be # printed. never-returning-functions=sys.exit,argparse.parse_error [SIMILARITIES] # Comments are removed from the similarity computation ignore-comments=yes # Docstrings are removed from the similarity computation ignore-docstrings=yes # Imports are removed from the similarity computation ignore-imports=yes # Signatures are removed from the similarity computation ignore-signatures=yes # Minimum lines number of a similarity. min-similarity-lines=4 [DESIGN] # List of regular expressions of class ancestor names to ignore when counting # public methods (see R0903) exclude-too-few-public-methods= # List of qualified class names to ignore when counting class parents (see # R0901) ignored-parents= # Maximum number of arguments for function / method. max-args=5 # Maximum number of attributes for a class (see R0902). max-attributes=7 # Maximum number of boolean expressions in an if statement (see R0916). max-bool-expr=5 # Maximum number of branch for function / method body. max-branches=12 # Maximum number of locals for function / method body. max-locals=15 # Maximum number of parents for a class (see R0901). max-parents=7 # Maximum number of public methods for a class (see R0904). max-public-methods=20 # Maximum number of return / yield for function / method body. max-returns=6 # Maximum number of statements in function / method body. max-statements=50 # Minimum number of public methods for a class (see R0903). min-public-methods=2 [STRING] # This flag controls whether inconsistent-quotes generates a warning when the # character used as a quote delimiter is used inconsistently within a module. check-quote-consistency=no # This flag controls whether the implicit-str-concat should generate a warning # on implicit string concatenation in sequences defined over several lines. check-str-concat-over-line-jumps=no [BASIC] # Naming style matching correct argument names. argument-naming-style=snake_case # Regular expression matching correct argument names. Overrides argument- # naming-style. If left empty, argument names will be checked with the set # naming style. #argument-rgx= # Naming style matching correct attribute names. attr-naming-style=snake_case # Regular expression matching correct attribute names. Overrides attr-naming- # style. If left empty, attribute names will be checked with the set naming # style. #attr-rgx= # Bad variable names which should always be refused, separated by a comma. bad-names=foo, bar, baz, toto, tutu, tata # Bad variable names regexes, separated by a comma. If names match any regex, # they will always be refused bad-names-rgxs= # Naming style matching correct class attribute names. class-attribute-naming-style=any # Regular expression matching correct class attribute names. Overrides class- # attribute-naming-style. If left empty, class attribute names will be checked # with the set naming style. #class-attribute-rgx= # Naming style matching correct class constant names. class-const-naming-style=UPPER_CASE # Regular expression matching correct class constant names. Overrides class- # const-naming-style. If left empty, class constant names will be checked with # the set naming style. #class-const-rgx= # Naming style matching correct class names. class-naming-style=PascalCase # Regular expression matching correct class names. Overrides class-naming- # style. If left empty, class names will be checked with the set naming style. #class-rgx= # Naming style matching correct constant names. const-naming-style=UPPER_CASE # Regular expression matching correct constant names. Overrides const-naming- # style. If left empty, constant names will be checked with the set naming # style. #const-rgx= # Minimum line length for functions/classes that require docstrings, shorter # ones are exempt. docstring-min-length=-1 # Naming style matching correct function names. function-naming-style=snake_case # Regular expression matching correct function names. Overrides function- # naming-style. If left empty, function names will be checked with the set # naming style. #function-rgx= # Good variable names which should always be accepted, separated by a comma. good-names=i, j, k, ex, Run, _ # Good variable names regexes, separated by a comma. If names match any regex, # they will always be accepted good-names-rgxs= # Include a hint for the correct naming format with invalid-name. include-naming-hint=no # Naming style matching correct inline iteration names. inlinevar-naming-style=any # Regular expression matching correct inline iteration names. Overrides # inlinevar-naming-style. If left empty, inline iteration names will be checked # with the set naming style. #inlinevar-rgx= # Naming style matching correct method names. method-naming-style=snake_case # Regular expression matching correct method names. Overrides method-naming- # style. If left empty, method names will be checked with the set naming style. #method-rgx= # Naming style matching correct module names. module-naming-style=snake_case # Regular expression matching correct module names. Overrides module-naming- # style. If left empty, module names will be checked with the set naming style. #module-rgx= # Colon-delimited sets of names that determine each other's naming style when # the name regexes allow several styles. name-group= # Regular expression which should only match function or class names that do # not require a docstring. no-docstring-rgx=^_ # List of decorators that produce properties, such as abc.abstractproperty. Add # to this list to register other decorators that produce valid properties. # These decorators are taken in consideration only for invalid-name. property-classes=abc.abstractproperty # Regular expression matching correct type variable names. If left empty, type # variable names will be checked with the set naming style. #typevar-rgx= # Naming style matching correct variable names. variable-naming-style=snake_case # Regular expression matching correct variable names. Overrides variable- # naming-style. If left empty, variable names will be checked with the set # naming style. #variable-rgx= monty-2026.10.21/pyproject.toml000066400000000000000000000073141526577750300162150ustar00rootroot00000000000000[build-system] requires = ["setuptools", "setuptools-scm"] build-backend = "setuptools.build_meta" [project] name = "monty" maintainers = [ { name = "Shyue Ping Ong", email = "shyuep@gmail.com" }, ] description = "Monty is the missing complement to Python." readme = "README.md" requires-python = ">=3.11" classifiers = [ "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Topic :: Software Development :: Libraries :: Python Modules", ] dependencies = [ "ruamel.yaml", "numpy", ] version = "2026.10.21" [project.optional-dependencies] # dev is for "dev" module, not for development dev = ["ipython"] json = [ "pymongo", "orjson>=3.6.1", "pandas", "pydantic", "pint", # Note: need torch>=2.3.0 for numpy 2 # 719 "torch", ] multiprocessing = ["tqdm"] optional = ["monty[dev,json,multiprocessing,serialization]"] serialization = ["msgpack"] [tool.setuptools.packages.find] where = ["src"] include = ["monty", "monty.*"] [tool.black] line-length = 120 target-version = ["py311"] include = '\.pyi?$' exclude = ''' ( /( \.eggs # exclude a few common directories in the | \.git # root of the project | \.hg | \.mypy_cache | \.tox | \.venv | _build | buck-out | build | dist | tests )/ ) ''' [tool.coverage.run] branch = true [tool.coverage.report] exclude_also = [ "@deprecated", "def __repr__", "if self.debug:", "if settings.DEBUG", "pragma: no cover", "raise AssertionError", "raise NotImplementedError", "show_plot", "if TYPE_CHECKING:", "except ImportError:" ] [tool.mypy] ignore_missing_imports = true [tool.ruff.lint] select = [ "B", # flake8-bugbear "C4", # flake8-comprehensions "I", # isort "PERF", # perflint "PL", # pylint "PIE", # flake8-pie "RET", # flake8-return "RUF", # ruff-specific "SIM", # flake8-simplify "TC", # flake8-type-checking "UP", # pyupgrade ] ignore = [ "PLR2004", # magic value comparison (too noisy) "PLR0911", # too many return statements "PLR0912", # too many branches "PLR0913", # too many arguments "PLR0915", # too many statements "PLR0917", # too many positional arguments (keyword-only would break public APIs) "PLW2901", # redefined loop name (idiomatic in places) "PERF203", # try/except inside loop "PLC0415", # imports inside functions for optional deps "SIM105", # contextlib.suppress (occasionally clearer as try/except) "SIM115", # context manager for files (already-yielded fds) "RUF012", # mutable class attribute should be ClassVar "TC006", # quote types in typing.cast() (no real benefit) ] [tool.ruff.lint.per-file-ignores] "src/monty/io.py" = ["PLC0414"] # intentional re-export of EncodingWarning "src/monty/termcolor.py" = ["PLW0603"] # intentional global toggle "tests/**" = ["B", "PL", "PERF", "RET", "RUF043", "SIM"] [tool.ruff.lint.isort] required-imports = ["from __future__ import annotations"] known-first-party = ["monty"] [tool.uv] default-groups = "all" [dependency-groups] dev = [ "coverage>=7.7.1", "pre-commit>=4.2.0", "pytest>=8.3.5", "pytest-benchmark>=5.2.3", "pytest-cov>=6.0.0", ] lint = [ "mypy>=1.15.0", "ruff>=0.11.2", ] maintain = [ "sphinx>=7.4.7", "sphinx-rtd-theme>=3.0.2", "requests", "invoke", "myst-parser", "sphinx-markdown-builder", "roman-numerals", ] monty-2026.10.21/src/000077500000000000000000000000001526577750300140635ustar00rootroot00000000000000monty-2026.10.21/src/monty/000077500000000000000000000000001526577750300152315ustar00rootroot00000000000000monty-2026.10.21/src/monty/__init__.py000066400000000000000000000011621526577750300173420ustar00rootroot00000000000000"""Monty is the missing complement to Python. Monty implements supplementary utilities not in the standard library, such as transparent support for zipped files and design patterns like singleton and cached_class. """ from __future__ import annotations from importlib.metadata import PackageNotFoundError, version __author__ = "Shyue Ping Ong" __copyright__ = "Copyright 2014, The Materials Virtual Lab" __maintainer__ = "Shyue Ping Ong" __email__ = "ongsp@ucsd.edu" __date__ = "Oct 12 2020" try: __version__ = version("monty") except PackageNotFoundError: # pragma: no cover # package is not installed pass monty-2026.10.21/src/monty/bisect.py000066400000000000000000000036641526577750300170650ustar00rootroot00000000000000"""Additional bisect functions for common searching tasks on sorted lists. Adapted from https://docs.python.org/2/library/bisect.html. The stdlib ``bisect()`` functions are useful for finding insertion points but can be awkward for direct lookups; these helpers wrap them as standard searches. """ from __future__ import annotations import bisect as bs from typing import TYPE_CHECKING if TYPE_CHECKING: from typing import Optional __author__ = "Matteo Giantomassi" __copyright__ = "Copyright 2013, The Materials Virtual Lab" __version__ = "0.1" __maintainer__ = "Matteo Giantomass" __email__ = "gmatteo@gmail.com" __date__ = "11/09/14" def index(a: list[float], x: float, atol: float | None = None) -> int: """Locate the leftmost value equal to x. If ``atol`` is given, return the leftmost value within ``atol`` of x (``abs(a[i] - x) < atol``) instead of requiring exact equality. """ if atol is None: i = bs.bisect_left(a, x) if i != len(a) and a[i] == x: return i raise ValueError # Skip values <= x - atol, which can never satisfy the strict tolerance. i = bs.bisect_right(a, x - atol) if i != len(a) and abs(a[i] - x) < atol: return i raise ValueError def find_lt(a: list[float], x: float) -> int: """Find rightmost value less than x.""" if i := bs.bisect_left(a, x): return i - 1 raise ValueError def find_le(a: list[float], x: float) -> int: """Find rightmost value less than or equal to x.""" if i := bs.bisect_right(a, x): return i - 1 raise ValueError def find_gt(a: list[float], x: float) -> int: """Find leftmost value greater than x.""" i = bs.bisect_right(a, x) if i != len(a): return i raise ValueError def find_ge(a: list[float], x: float) -> int: """Find leftmost item greater than or equal to x.""" i = bs.bisect_left(a, x) if i != len(a): return i raise ValueError monty-2026.10.21/src/monty/collections.py000066400000000000000000000261301526577750300201230ustar00rootroot00000000000000"""Useful collection classes. - ``tree``: a recursive ``defaultdict`` for nested dictionaries with default values. - ``ControlledDict``: a base ``dict`` with configurable mutability. - ``frozendict``: an immutable dictionary. - ``Namespace``: a dict that allows adding new keys but not updating or deleting them. - ``AttrDict``: a dict whose values can be accessed as ``dct.key``. - ``FrozenAttrDict``: an immutable version of ``AttrDict``. - ``MongoDict``: a dict-like object whose nested-dict values are accessible as attributes. """ from __future__ import annotations import collections import warnings from abc import ABC from typing import TYPE_CHECKING if TYPE_CHECKING: from collections.abc import Iterable from typing import Any # Cache the set of names exposed by ``dict`` once, so AttrDict.__setitem__ # does not have to call ``dir(dict)`` (which builds a fresh ~50-entry list) # on every assignment. _DICT_METHOD_NAMES: frozenset[str] = frozenset(dir(dict)) def tree() -> collections.defaultdict: """Build a recursive ``defaultdict`` that auto-creates nested trees on access. Examples: >>> x = tree() >>> x["a"]["b"]["c"] = 1 Returns: A tree. """ return collections.defaultdict(tree) class ControlledDict(dict, ABC): """A base dictionary class with configurable mutability. Subclasses ``dict`` directly (rather than ``collections.UserDict``) so the common read paths run at C speed; mutation methods are overridden in pure Python to enforce the ``_allow_*`` flags. ``dict.__init__`` bypasses ``__setitem__`` entirely, so initialization is unaffected by the flags. Attributes: _allow_add (bool): Whether new keys can be added. _allow_del (bool): Whether existing keys can be deleted. _allow_update (bool): Whether existing keys can be updated. Configurable Operations: This class allows controlling the following dict operations (refer to https://docs.python.org/3.13/library/stdtypes.html#mapping-types-dict for details): - Adding or updating items: - setter method: `__setitem__` - `setdefault` - `update` - Deleting items: - `del dict[key]` - `pop(key)` - `popitem` - `clear()` """ _allow_add: bool = True _allow_del: bool = True _allow_update: bool = True # Override add/update operations def __setitem__(self, key, value) -> None: """Forbid adding or updating keys based on _allow_add and _allow_update.""" if key not in self and not self._allow_add: raise TypeError(f"Cannot add new key {key!r}, because add is disabled.") if key in self and not self._allow_update: raise TypeError(f"Cannot update key {key!r}, because update is disabled.") dict.__setitem__(self, key, value) def update(self, *args, **kwargs) -> None: """Forbid adding or updating keys based on _allow_add and _allow_update.""" # Materialize once so iterators are not consumed twice between # validation and the actual update. updates = dict(*args, **kwargs) if not (self._allow_add and self._allow_update): for key in updates: if key not in self and not self._allow_add: raise TypeError( f"Cannot add new key {key!r} using update, because add is disabled." ) if key in self and not self._allow_update: raise TypeError( f"Cannot update key {key!r} using update, because update is disabled." ) dict.update(self, updates) def setdefault(self, key, default=None) -> Any: """Forbid adding or updating keys based on _allow_add and _allow_update. Note: if not _allow_update, this method would NOT check whether the new default value is the same as current value for efficiency. """ if key not in self: if not self._allow_add: raise TypeError( f"Cannot add new key using setdefault: {key!r}, because add is disabled." ) elif not self._allow_update: raise TypeError( f"Cannot update key using setdefault: {key!r}, because update is disabled." ) return dict.setdefault(self, key, default) # Override delete operations def __delitem__(self, key) -> None: """Forbid deleting keys when self._allow_del is False.""" if not self._allow_del: raise TypeError(f"Cannot delete key {key!r}, because delete is disabled.") dict.__delitem__(self, key) def pop(self, key: Any, *args: Any) -> Any: """Forbid popping keys when self._allow_del is False.""" if not self._allow_del: raise TypeError(f"Cannot pop key {key!r}, because delete is disabled.") return dict.pop(self, key, *args) def popitem(self) -> tuple[Any, Any]: """Pop the FIRST item (FIFO). Preserves the previous ``collections.UserDict``-inherited semantics — plain ``dict.popitem`` is LIFO, but monty users have historically relied on FIFO behaviour. """ if not self._allow_del: raise TypeError("Cannot pop item, because delete is disabled.") if not self: raise KeyError("dictionary is empty") key = next(iter(self)) value = dict.pop(self, key) return key, value def clear(self) -> None: """Forbid clearing the dictionary when self._allow_del is False.""" if not self._allow_del: raise TypeError("Cannot clear dictionary, because delete is disabled.") dict.clear(self) class frozendict(ControlledDict): """A dictionary that does not permit changes. The naming violates PEP 8 to be consistent with the built-in ``frozenset``. """ _allow_add: bool = False _allow_del: bool = False _allow_update: bool = False class Namespace(ControlledDict): """A dictionary that does not permit update/delete its values (but allows add).""" _allow_add: bool = True _allow_del: bool = False _allow_update: bool = False class AttrDict(dict): """Allow accessing values as `dct.key` in addition to the traditional way `dct["key"]`. Examples: >>> dct = AttrDict(foo=1, bar=2) >>> assert dct["foo"] is dct.foo >>> dct.bar = "hello" Warnings: When shadowing dict methods, e.g.: >>> dct = AttrDict(update="value") >>> dct.update() # TypeError (the `update` method is overwritten) References: https://stackoverflow.com/a/14620633/24021108 """ def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) self.__dict__ = self def __setitem__(self, key, value) -> None: """Check if the key shadows dict method.""" if key in _DICT_METHOD_NAMES: warnings.warn( f"'{key=}' shadows dict method. This may lead to unexpected behavior.", UserWarning, stacklevel=2, ) super().__setitem__(key, value) class FrozenAttrDict(frozendict): """An immutable dict that also exposes values as attributes. - Does not permit changes (add/update/delete). - Allows accessing values as ``dct.key`` in addition to ``dct["key"]``. """ def __init__(self, *args, **kwargs) -> None: """Allow add during init, as __setattr__ is called unlike frozendict.""" self._allow_add = True super().__init__(*args, **kwargs) self._allow_add = False def __getattribute__(self, name: str) -> Any: try: return object.__getattribute__(self, name) except AttributeError: return self[name] def __setattr__(self, name: str, value: Any) -> None: if not self._allow_add and name != "_allow_add": raise TypeError( f"{self.__class__.__name__} does not support item assignment." ) super().__setattr__(name, value) def __delattr__(self, name: str) -> None: raise TypeError(f"{self.__class__.__name__} does not support item deletion.") class MongoDict: """Read-only view of a nested dict that exposes entries as attributes. Entries cannot be modified. Provides IPython tab completion, which makes it convenient for interactive exploration of nested dicts (e.g. documents extracted from a MongoDB database). >>> m_dct = MongoDict({"a": {"b": 1}, "x": 2}) >>> assert m_dct.a.b == 1 and m_dct.x == 2 >>> assert "a" in m_dct and "b" in m_dct.a >>> m_dct["a"] {"b": 1} Notes: Cannot inherit from ``collections.abc.Mapping`` because ``dict.keys`` and ``dict.items`` would pollute the namespace, e.g. ``MongoDict({"keys": 1}).keys`` would be the ABC method instead of 1. """ def __init__(self, *args, **kwargs) -> None: """Initialize from positional and keyword arguments forwarded to ``dict``. Args: args: Passthrough arguments for standard dict. kwargs: Passthrough keyword arguments for standard dict. """ self.__dict__["_mongo_dict_"] = dict(*args, **kwargs) def __repr__(self) -> str: return str(self) def __str__(self) -> str: return str(self._mongo_dict_) def __setattr__(self, name: str, value: Any) -> None: raise NotImplementedError( f"You cannot modify attribute {name} of {self.__class__.__name__}" ) def __getattribute__(self, name: str) -> Any: try: return super().__getattribute__(name) except AttributeError: try: a = self._mongo_dict_[name] if isinstance(a, collections.abc.Mapping): a = self.__class__(a) return a except Exception as exc: raise AttributeError(str(exc)) from exc def __getitem__(self, slice_) -> Any: return self._mongo_dict_.__getitem__(slice_) def __iter__(self) -> Iterable: return iter(self._mongo_dict_) def __len__(self) -> int: return len(self._mongo_dict_) def __dir__(self) -> list: """Return entries for IPython tab completion. See http://ipython.org/ipython-doc/dev/config/integrating.html. """ return sorted(k for k in self._mongo_dict_ if not callable(k)) def dict2namedtuple(*args, **kwargs) -> tuple: """Helper function to create a `namedtuple` from a dictionary. Examples: >>> tpl = dict2namedtuple(foo=1, bar="hello") >>> assert tpl.foo == 1 and tpl.bar == "hello" >>> tpl = dict2namedtuple([("foo", 1), ("bar", "hello")]) >>> assert tpl[0] is tpl.foo and tpl[1] is tpl.bar Warnings: Don't use this function in code where memory and performance are crucial, since a dict is needed to instantiate the tuple! """ dct = dict(*args) dct.update(**kwargs) return collections.namedtuple( typename="dict2namedtuple", field_names=list(dct.keys()) )(**dct) monty-2026.10.21/src/monty/design_patterns.py000066400000000000000000000071721526577750300210030ustar00rootroot00000000000000"""Some common design patterns such as singleton and cached classes.""" from __future__ import annotations import inspect import os from functools import cache, wraps from typing import TYPE_CHECKING, TypeVar from weakref import WeakValueDictionary if TYPE_CHECKING: from collections.abc import Callable from typing import Any def singleton(cls: type) -> Callable[[], Any]: """Decorate a class so it has at most one instance. Examples: >>> @singleton ... class MySingleton: ... def __init__(self): ... pass """ @cache def getinstance() -> Any: return cls() return getinstance # https://github.com/microsoft/pylance-release/issues/3478 Klass = TypeVar("Klass") def cached_class(cls: type[Klass]) -> type[Klass]: """Decorator to cache class instances by constructor arguments. Results in a class that behaves like a singleton for each set of constructor arguments. Use for *immutable classes only* — caching a mutable class rarely makes sense. Avoid in cases where constructor arguments have many permutations. If any arguments are non-hashable, that set of arguments is not cached. """ orig_new = cls.__new__ orig_init = cls.__init__ cache: WeakValueDictionary = WeakValueDictionary() # ``inspect.signature`` is one of the most expensive stdlib calls (typ. # 10-100µs); hoist it out so we pay this cost once per decoration rather # than once per instantiation. sig = inspect.signature(orig_init) @wraps(orig_new) def new_new(cls, *args: Any, **kwargs: Any) -> Any: # Normalize arguments bound_args = sig.bind(None, *args, **kwargs) bound_args.apply_defaults() # Remove 'self' from the arguments normalized_args = tuple(bound_args.arguments.values())[1:] try: key = (cls, normalized_args) if key in cache: return cache[key] if orig_new is object.__new__: instance = orig_new(cls) else: instance = orig_new(cls, *args, **kwargs) orig_init(instance, *args, **kwargs) instance._initialized = True cache[key] = instance return instance except TypeError: # Can't cache this set of arguments if orig_new is object.__new__: instance = orig_new(cls) else: instance = orig_new(cls, *args, **kwargs) orig_init(instance, *args, **kwargs) instance._initialized = True return instance @wraps(orig_init) def new_init(self: Any, *args: Any, **kwargs: Any) -> None: if not hasattr(self, "_initialized"): orig_init(self, *args, **kwargs) self._initialized = True def reduce(self: Any) -> tuple[type, tuple, dict[str, Any]]: for key, value in cache.items(): if value is self: cls, args = key return (cls, args, {}) raise ValueError("Instance not found in cache") cls.__new__ = new_new # type: ignore[method-assign] cls.__init__ = new_init # type: ignore[method-assign] cls.__reduce__ = reduce # type: ignore[method-assign] return cls class NullFile: """A file object that is associated to /dev/null.""" def __new__(cls): """Pass through.""" return open(os.devnull, "w") # pylint: disable=R1732 def __init__(self): """no-op.""" class NullStream: """A fake stream with a no-op write.""" def write(self, *args: Any) -> None: # pylint: disable=E0211 """Do nothing.""" monty-2026.10.21/src/monty/dev.py000066400000000000000000000160551526577750300163700ustar00rootroot00000000000000"""Developer-facing utilities, e.g. decorators for deprecating methods or classes.""" from __future__ import annotations import functools import inspect import sys import warnings from dataclasses import is_dataclass from datetime import datetime from typing import TYPE_CHECKING, Any, ParamSpec, TypeVar, cast if TYPE_CHECKING: from collections.abc import Callable _P = ParamSpec("_P") _R = TypeVar("_R") _F = TypeVar("_F", bound="Callable[..., Any]") def deprecated( replacement: Callable | str | None = None, message: str = "", deadline: tuple[int, int, int] | None = None, category: type[Warning] = FutureWarning, ) -> Callable[[_F], _F]: """Decorator to mark classes or functions as deprecated, with a possible replacement. Args: replacement (Callable | str): A replacement class or function. message (str): A warning message to be displayed. deadline (Optional[tuple[int, int, int]]): Optional deadline for removal of the old function/class, in format (yyyy, MM, dd). A CI warning would be raised after this date if is running in code owner' repo. category (Warning): Choose the category of the warning to issue. Defaults to FutureWarning. Another choice can be DeprecationWarning. Note that FutureWarning is meant for end users and is always shown unless silenced. DeprecationWarning is meant for developers and is never shown unless python is run in developmental mode or the filter is changed. Make the choice accordingly. Returns: Original function/class, but with a warning to use the replacement. """ def craft_message( old: Callable | type, replacement: Callable | str | None, message: str, deadline: datetime | None, ) -> str: msg = f"{old.__name__} is deprecated" if deadline is not None: msg += f", and will be removed on {_deadline:%Y-%m-%d}\n" if replacement is not None: if deadline is None: msg += "; use " # for better formatting else: msg += "Use " if isinstance(replacement, str): msg += f"{replacement} instead." else: if isinstance(replacement, property): r = replacement.fget elif isinstance(replacement, (classmethod, staticmethod)): r = replacement.__func__ else: r = replacement msg += f"{r.__name__} in {r.__module__} instead." if message: msg += "\n" + message return msg def deprecated_function_decorator(old: Callable[_P, _R]) -> Callable[_P, _R]: # Craft the warning message once at decoration time; the inputs are # all closed over and immutable, so there is no need to rebuild the # string on every call (this used to dominate hot deprecated paths). msg = craft_message(old, replacement, message, _deadline) @functools.wraps(old) def wrapped(*args: _P.args, **kwargs: _P.kwargs) -> _R: warnings.warn(msg, category=category, stacklevel=2) return old(*args, **kwargs) return wrapped def deprecated_class_decorator(cls: type) -> type: # Modify __post_init__ for dataclass if is_dataclass(cls) and hasattr(cls, "__post_init__"): original_init = cls.__post_init__ else: original_init = cls.__init__ # type: ignore[misc] msg = craft_message(cls, replacement, message, _deadline) @functools.wraps(original_init) def new_init(self, *args, **kwargs): warnings.warn(msg, category=category, stacklevel=2) original_init(self, *args, **kwargs) if is_dataclass(cls) and hasattr(cls, "__post_init__"): cls.__post_init__ = new_init else: cls.__init__ = new_init # type: ignore[misc] return cls # Convert deadline to `datetime` type _deadline: datetime | None = datetime(*deadline) if deadline is not None else None def decorator(target: _F) -> _F: if inspect.isfunction(target): # inspect narrows to FunctionType, losing the original callable type. return cast(_F, deprecated_function_decorator(target)) if inspect.isclass(target): return cast(_F, deprecated_class_decorator(target)) raise TypeError( "The @deprecated decorator can only be applied to classes or functions" ) return decorator class requires: """Decorator to mark classes or functions as requiring a specified condition. This can be used to present useful error messages for optional dependencies. For example, decorating the following code will check if scipy is present and if not, a runtime error will be raised if someone attempts to call the use_scipy function: try: import scipy except ImportError: scipy = None @requires(scipy is not None, "scipy is not present.") def use_scipy(): print(scipy.majver) Args: condition: Condition necessary to use the class or function. message: A message to be displayed if the condition is not True. """ def __init__( self, condition: bool, message: str, err_cls: type[Exception] = RuntimeError ) -> None: """Initialize the requires decorator. Args: condition: An expression returning a bool. message: Message to display if condition is False. err_cls: Exception class to raise when condition is False. """ self.condition = condition self.message = message self.err_cls = err_cls def __call__(self, _callable: Callable[_P, _R]) -> Callable[_P, _R]: """Wrap ``_callable`` so it raises when the condition is False. Args: _callable: Callable function. """ @functools.wraps(_callable) def decorated(*args: _P.args, **kwargs: _P.kwargs) -> _R: if not self.condition: raise self.err_cls(self.message) return _callable(*args, **kwargs) return decorated def install_excepthook(hook_type: str = "color", **kwargs) -> int: """Replace the default Python traceback with an improved version from IPython. Use ``color`` for colourful traceback formatting or ``verbose`` for the Ka-Ping Yee ``cgitb.py`` style. ``kwargs`` are forwarded to the hook constructor; see ``IPython.core.ultratb`` for details. Returns: 0 if hook is installed successfully. """ try: from IPython.core import ultratb # pylint: disable=import-outside-toplevel except ImportError as exc: raise ImportError("Cannot install excepthook, IPython not installed") from exc # Select the hook. hook = { "color": ultratb.ColorTB, "verbose": ultratb.VerboseTB, }.get(hook_type.lower()) if hook is None: return 2 sys.excepthook = hook(**kwargs) return 0 monty-2026.10.21/src/monty/fnmatch.py000066400000000000000000000034011526577750300172210ustar00rootroot00000000000000"""Support for Unix shell-style wildcards.""" from __future__ import annotations import fnmatch import re from monty.string import list_strings class WildCard: """Convenience wrapper for filename matching with multiple shell patterns. >>> w = WildCard("*.nc|*.pdf") >>> w.filter(["foo.nc", "bar.pdf", "hello.txt"]) ['foo.nc', 'bar.pdf'] >>> w.filter("foo.nc") ['foo.nc'] """ def __init__(self, wildcard: str, sep: str = "|") -> None: """Initializes a WildCard. Args: wildcard (str): String of tokens separated by sep. Each token represents a pattern. sep (str): Separator for shell patterns. """ self.pats: list[str] = wildcard.split(sep) if wildcard else ["*"] # Pre-compile each pattern once so per-call matching does not pay the # ``fnmatch.translate`` cost (only an internal LRU cache otherwise). self._regexes: list[re.Pattern[str]] = [ re.compile(fnmatch.translate(p)) for p in self.pats ] def __str__(self) -> str: return f"<{self.__class__.__name__}, patterns = {self.pats}>" def filter(self, names: list[str]) -> list[str]: """Return a list with the names matching the pattern. Note: a name that matches multiple patterns is repeated once per match in the result (preserved for backward compatibility). """ regexes = self._regexes return [ filename for filename in list_strings(names) for regex in regexes if regex.match(filename) ] def match(self, name: str) -> bool: """Returns True if name matches one of the patterns.""" return any(regex.match(name) for regex in self._regexes) monty-2026.10.21/src/monty/fractions.py000066400000000000000000000030711526577750300175740ustar00rootroot00000000000000"""Math functions.""" from __future__ import annotations import math from typing import TYPE_CHECKING from monty.dev import deprecated if TYPE_CHECKING: from collections.abc import Sequence @deprecated(replacement="math.gcd", deadline=(2028, 1, 1)) def gcd(*numbers: int) -> int: """Returns the greatest common divisor for a sequence of numbers. Args: *numbers: Sequence of numbers. Returns: int: Greatest common divisor of numbers. """ return math.gcd(*numbers) @deprecated(replacement="math.lcm", deadline=(2028, 1, 1)) def lcm(*numbers: int) -> int: """Return lowest common multiple of a sequence of numbers. Args: *numbers: Sequence of numbers. Returns: int: Lowest common multiple of numbers. """ return math.lcm(*numbers) def gcd_float(numbers: Sequence[float], tol: float = 1e-8) -> float: """Return the greatest common divisor for a sequence of numbers. Uses a numerical tolerance, so can be used on floats. Args: numbers: Sequence of numbers. tol: Numerical tolerance. Returns: float: Greatest common divisor of numbers. """ def pair_gcd_tol(a: float, b: float) -> float: """Calculate the Greatest Common Divisor of a and b. Unless b==0, the result will have the same sign as b (so that when b is divided by it, the result comes out positive). """ while b > tol: a, b = b, a % b return a n = numbers[0] for i in numbers[1:]: n = pair_gcd_tol(n, i) return n monty-2026.10.21/src/monty/functools.py000066400000000000000000000200701526577750300176160ustar00rootroot00000000000000"""functools, especially backported from Python 3.""" from __future__ import annotations import builtins import cProfile import pstats import signal import sys import tempfile from functools import cached_property, partial, update_wrapper, wraps from typing import TYPE_CHECKING if TYPE_CHECKING: from collections.abc import Callable from typing import Any, Union def _mangle(name: str, cls: type) -> str: """Apply Python's private name mangling of ``name`` within class ``cls``.""" if name.startswith("__") and not name.endswith("__"): return f"_{cls.__name__.lstrip('_')}{name}" return name class lazy_property(cached_property): """Descriptor that turns a method into a lazily evaluated attribute. The wrapped function is called once on first access; the returned value is cached on the instance's ``__dict__`` for subsequent lookups. Built on ``functools.cached_property``, with these differences: - The value is cached under the (mangled) name of the wrapped function, so a descriptor may be bound to several names, or set on a class after creation. - Objects without a ``__dict__`` (e.g. ``__slots__`` classes) raise ``AttributeError`` rather than ``TypeError``. - ``__name__``, ``__qualname__``, ``__module__`` and ``__doc__`` are copied from the wrapped function. - Cached values can be cleared with :meth:`invalidate`. """ def __init__(self, func: Callable) -> None: """Initialize the descriptor. Args: func: Function to decorate. """ super().__init__(func) update_wrapper(self, func) # type: ignore[arg-type] def __set_name__(self, owner: type, name: str) -> None: if self.attrname is None: self.attrname = _mangle(self.func.__name__, owner) def __get__(self, inst: Any, owner: type | None = None) -> Any: if inst is None: return self try: inst.__dict__ # noqa: B018 except AttributeError as exc: raise AttributeError( f"'{type(inst).__name__}' object has no attribute '__dict__'" ) from exc if self.attrname is None: self.attrname = _mangle(self.func.__name__, type(inst)) return super().__get__(inst, owner) @classmethod def invalidate(cls, inst: object, name: str) -> None: """Invalidate a lazy attribute. This obviously violates the lazy contract. A subclass of lazy may however have a contract where invalidation is appropriate. """ inst_cls = inst.__class__ if not hasattr(inst, "__dict__"): raise AttributeError( f"'{inst_cls.__name__}' object has no attribute '__dict__'" ) name = _mangle(name, inst_cls) if not isinstance(getattr(inst_cls, name), cls): raise AttributeError( f"'{inst_cls.__name__}.{name}' is not a {cls.__name__} attribute" ) inst.__dict__.pop(name, None) def return_if_raise( exception_tuple: list | tuple, retval_if_exc: Any, disabled: bool = False ) -> Any: """Return ``retval_if_exc`` when the decorated callable raises a listed exception. The callable is invoked inside a ``try`` block; any of the exceptions in ``exception_tuple`` cause ``retval_if_exc`` to be returned instead (see also ``return_node_if_raise``). Setting ``disabled=True`` skips the ``try``/``except`` (useful for debugging). Works on functions, methods, and properties. Examples: @return_if_raise(ValueError, None) def return_none_if_value_error(self): pass @return_if_raise((ValueError, KeyError), "hello") def another_method(self): pass @property @return_if_raise(AttributeError, None) def name(self): "Name of the object, None if not set." return self._name """ # we need a tuple of exceptions. if isinstance(exception_tuple, list): exception_tuple = tuple(exception_tuple) elif isinstance(exception_tuple, type) and issubclass( exception_tuple, BaseException ): exception_tuple = (exception_tuple,) elif not isinstance(exception_tuple, tuple): raise TypeError(f"Wrong exception_tuple {type(exception_tuple)}") def decorator(func): @wraps(func) def wrapper(*args, **kwargs): if disabled: return func(*args, **kwargs) try: return func(*args, **kwargs) except exception_tuple: # pylint: disable=E0712 return retval_if_exc return wrapper return decorator # One could use None as default value in return_if_raise but this one is # explicit and more readable return_none_if_raise = partial(return_if_raise, retval_if_exc=None) """ This decorator returns None if one of the exceptions is raised. @return_none_if_raise(ValueError) def method(self): """ class timeout: """Context manager that aborts a block of code after a time limit. Works only on Unix-based systems since it relies on ``signal.SIGALRM``. Examples: >>> try: ... with timeout(3): ... do_stuff() ... except TimeoutError: ... do_something_else() """ def __init__(self, seconds: int = 1, error_message: str = "Timeout"): """Initialize the timeout context manager. Args: seconds (int): Allowed time for function in seconds. error_message (str): An error message. """ self.seconds = seconds self.error_message = error_message def handle_timeout(self, signum: int, frame: Any) -> None: """Signal handler that raises TimeoutError. Args: signum: Return signal from call. frame: Current stack frame. """ raise TimeoutError(self.error_message) def __enter__(self) -> None: signal.signal(signal.SIGALRM, self.handle_timeout) signal.alarm(self.seconds) def __exit__(self, type: Any, value: Any, traceback: Any) -> None: signal.alarm(0) class TimeoutError(builtins.TimeoutError): """Exception raised by :class:`timeout` when the time limit is exceeded. Subclasses the built-in ``TimeoutError``, so ``except TimeoutError`` catches it without importing it from monty. """ def __init__(self, message: str): """Initialize the exception. Args: message: Error message. """ super().__init__(message) self.message = message def prof_main(main: Callable) -> Callable: """Decorator for profiling main programs. Profiling is activated by prepending the command line options supported by the original main program with the keyword `prof`. Examples: $ script.py arg --foo=1 becomes $ script.py prof arg --foo=1 The decorated main accepts two new arguments: prof_file: Name of the output file with profiling data If not given, a temporary file is created. sortby: Profiling data are sorted according to this value. default is "time". See sort_stats. """ @wraps(main) def wrapper(*args, **kwargs): try: do_prof = sys.argv[1] == "prof" if do_prof: sys.argv.pop(1) except Exception: do_prof = False if not do_prof: sys.exit(main()) else: print("Entering profiling mode...") prof_file = kwargs.get("prof_file") if prof_file is None: _, prof_file = tempfile.mkstemp() print(f"Profiling data stored in {prof_file}") sortby = kwargs.get("sortby", "time") cProfile.runctx("main()", globals(), locals(), prof_file) s = pstats.Stats(prof_file) s.strip_dirs().sort_stats(sortby).print_stats() if "retval" not in kwargs: sys.exit(0) else: return kwargs["retval"] return wrapper monty-2026.10.21/src/monty/inspect.py000066400000000000000000000056411526577750300172560ustar00rootroot00000000000000"""Useful additional functions to help get information about live objects.""" from __future__ import annotations import os import sys from inspect import currentframe, getframeinfo, getmodule from typing import TYPE_CHECKING if TYPE_CHECKING: from typing import Literal def all_subclasses(cls: type) -> list[type]: """Return all subclasses of ``cls``, including transitive ones. Uses an explicit stack with ``set``-based de-duplication so a class that appears under multiple base classes (diamond inheritance) is not reported more than once and recursion depth is bounded. """ seen: set[type] = set() out: list[type] = [] stack: list[type] = list(cls.__subclasses__()) while stack: sub = stack.pop() if sub in seen: continue seen.add(sub) out.append(sub) stack.extend(sub.__subclasses__()) return out def find_top_pyfile() -> str: """Return the absolute path of the top-most script in the call stack.""" frame = currentframe() if frame is None: raise RuntimeError("Could not obtain current frame.") while frame.f_back is not None: frame = frame.f_back finfo = getframeinfo(frame) return os.path.abspath(finfo.filename) def caller_name(skip: Literal[1, 2] = 2) -> str: """Get a name of a caller in the format module.class.method. ``skip`` specifies how many levels of stack to skip while getting caller name. skip=1 means "who calls me", skip=2 "who calls my caller" etc. An empty string is returned if skipped levels exceed stack height. Implementation note: this used to call ``inspect.stack()``, which builds a full ``FrameInfo`` (including source lines) for *every* frame in the call stack — orders of magnitude more work than necessary. We walk the frame chain manually with ``sys._getframe`` and only inspect the one frame we care about. Taken from: https://gist.github.com/techtonik/2151727 Public Domain, i.e. feel free to copy/paste """ # ``sys._getframe(0)`` is this frame (caller_name) — same indexing as # the original ``inspect.stack()[skip]`` implementation. try: parentframe = sys._getframe(skip) except ValueError: return "" name: list[str] = [] # ``modname`` can be None when frame is executed directly in console if module := getmodule(parentframe): name.append(module.__name__) # detect classname if "self" in parentframe.f_locals: # I don't know any way to detect call from the object method # XXX: there seems to be no way to detect static method call - it will # be just a function call name.append(parentframe.f_locals["self"].__class__.__name__) codename = parentframe.f_code.co_name if codename != "": # top level usually name.append(codename) # function or a method del parentframe return ".".join(name) monty-2026.10.21/src/monty/io.py000066400000000000000000000355061526577750300162230ustar00rootroot00000000000000"""Augment Python's I/O functions with transparent support for compressed files.""" from __future__ import annotations import bz2 import errno import gzip import io import lzma import mmap import os import subprocess import time import warnings from builtins import EncodingWarning as EncodingWarning from collections import deque from pathlib import Path from typing import IO, TYPE_CHECKING, Any, Literal, cast, overload if TYPE_CHECKING: from collections.abc import Iterator from typing import TypeAlias from monty.shutil import PathLike # `EncodingWarning` (Python 3.10+) is re-exported above so users can keep # using ``from monty.io import EncodingWarning``. # fmt: off TextModes: TypeAlias = Literal[ "r", "w", "a", "r+", "w+", "a+", "rt", "tr", "wt", "tw", "at", "ta", "rt+", "tr+", "wt+", "tw+", "at+", "ta+", ] BinModes: TypeAlias = Literal[ "rb", "br", "wb", "bw", "ab", "ba", "rb+", "br+", "wb+", "bw+", "ab+", "ba+", ] # fmt: on @overload def zopen(filename: PathLike, mode: TextModes, **kwargs: Any) -> IO[str]: ... @overload def zopen(filename: PathLike, mode: BinModes, **kwargs: Any) -> IO[bytes]: ... @overload # fallback def zopen(filename: PathLike, mode: str, **kwargs: Any) -> IO[Any]: ... def zopen( filename: PathLike, mode: str, **kwargs: Any, ) -> IO[Any]: """Open a file, transparently handling bz2/gzip/lzma compression. Wraps ``[bz2|gzip|lzma].open`` and ``open`` and is usable as a context manager: ``with zopen(filename, mode="rt", ...) as f``. Important: - Always specify binary/text explicitly in ``mode`` (pass ``t`` or ``b``). - Always provide an explicit ``encoding`` in text mode; UTF-8 is used as the default otherwise. Args: filename (PathLike): The file to open. mode (str): The mode in which the file is opened. Must explicitly include ``b`` for binary or ``t`` for text. **kwargs: Additional keyword arguments forwarded to ``open``. Returns: TextIO | BinaryIO | bz2.BZ2File | gzip.GzipFile | lzma.LZMAFile """ # Don't allow implicit text/binary `mode` if not ("b" in mode or "t" in mode): raise RuntimeError( "Implicit text/binary mode is not allowed, please pass t/b explicitly in mode." ) # Warn against default `encoding` in text mode if # `PYTHONWARNDEFAULTENCODING` environment variable is set (PEP 597) if "t" in mode and kwargs.get("encoding") is None: if os.getenv("PYTHONWARNDEFAULTENCODING"): warnings.warn( "We strongly encourage explicit `encoding`, " "and we would use UTF-8 by default as per PEP 686", category=EncodingWarning, stacklevel=2, ) kwargs["encoding"] = "utf-8" _name, ext = os.path.splitext(filename) ext = ext.lower() if ext == ".bz2": return cast(IO[Any], bz2.open(filename, mode, **kwargs)) if ext == ".gz": return cast(IO[Any], gzip.open(filename, mode, **kwargs)) if ext == ".z": # TODO: drop ".z" extension support after 2026-01-01 warnings.warn( "Python gzip is not able to (de)compress LZW-compressed files. " "You should rename it to .gz. Support for the '.z' extension will " "be removed after 2026-01-01.", category=FutureWarning, stacklevel=2, ) return cast(IO[Any], gzip.open(filename, mode, **kwargs)) if ext in {".xz", ".lzma"}: return cast(IO[Any], lzma.open(filename, mode, **kwargs)) return cast(IO[Any], open(filename, mode, **kwargs)) def _get_line_ending( file: str | Path | io.TextIOWrapper | io.BufferedReader | gzip.GzipFile | bz2.BZ2File, ) -> Literal["\r\n", "\n"]: """Helper function to get line ending of a file. This function assumes the file has a single consistent line ending. WARNING: as per the POSIX standard, a line is: "A sequence of zero or more non- characters plus a terminating char.", as such this func might fail if the only line misses a terminating newline character. https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html Returns: "\n": Unix line ending. "\r\n": Windows line ending. Raises: ValueError: If line ending is unknown. Warnings: If file is empty, "\n" would be used as default. """ if isinstance(file, (str, Path)): with zopen(file, mode="rb") as f: first_line = f.readline() elif isinstance(file, io.TextIOWrapper): first_line = file.buffer.readline() # type: ignore[attr-defined] elif isinstance(file, (io.BufferedReader, gzip.GzipFile, bz2.BZ2File)): first_line = file.readline() else: raise TypeError(f"Unknown file type {type(file).__name__}") # Reset pointer to start of file if possible if hasattr(file, "seek"): file.seek(0) # Return Unix "\n" line ending as default if file is empty if not first_line: warnings.warn("File is empty, return Unix line ending \n.", stacklevel=2) return "\n" if first_line.endswith(b"\r\n"): return "\r\n" if first_line.endswith(b"\n"): return "\n" # It's likely the line is missing a line ending for the first line raise ValueError(f"Unknown line ending in line {first_line!r}.") def reverse_readfile( filename: PathLike, ) -> Iterator[str]: """Read a file in reverse using ``mmap`` for performance. Slower than ``reverse_readline`` on very small files, but at least 2x faster on large files — the primary use case. Args: filename (PathLike): File to read. Yields: Lines from the file in reverse order. """ with zopen(filename, mode="rb") as file: # Detect line ending from the already-open handle so compressed files # are not opened twice. l_end = _get_line_ending(file) # type: ignore[arg-type] len_l_end = len(l_end) if isinstance(file, (gzip.GzipFile, bz2.BZ2File)): for line in reversed(file.readlines()): # "readlines" would keep the line end character yield line.decode("utf-8") else: try: filemap = mmap.mmap(file.fileno(), 0, access=mmap.ACCESS_READ) except ValueError: warnings.warn("trying to mmap an empty file.", stacklevel=2) return file_size = len(filemap) while file_size > 0: # Find line segment start and end positions seg_start_pos = filemap.rfind(l_end.encode(), 0, file_size) seg_end_pos = file_size + len_l_end # The first (originally) line doesn't have an ending character at its head if seg_start_pos == -1: yield (filemap[:seg_end_pos].decode("utf-8")) # Skip the first match (the last line ending character) elif file_size != len(filemap): yield ( filemap[seg_start_pos + len_l_end : seg_end_pos].decode("utf-8") ) file_size = seg_start_pos def reverse_readline( m_file: io.BufferedReader | io.TextIOWrapper | gzip.GzipFile | bz2.BZ2File, blk_size: int = 4096, max_mem: int = 4_000_000, ) -> Iterator[str]: """Read a file backwards line-by-line, similar to ``file.readline``. Allows efficient retrieval of data from the end of a file. Supported file stream formats: - TextIOWrapper (text mode) | BufferedReader (binary mode) - gzip/bzip2 file stream Cases where file would be read forwards and reversed in RAM: - If file size is smaller than RAM usage limit (max_mem). - Gzip files, as reverse seeks are not supported. Reference: Based on code by Peter Astrand , using modifications by Raymond Hettinger and Kevin German. http://code.activestate.com/recipes/439045-read-a-text- file-backwards-yet-another-implementat/ Args: m_file: File stream to read (backwards). blk_size (int): The block size to read each time in bytes. Defaults to 4096. max_mem (int): Threshold to determine when to reverse a file in-memory versus reading blocks of a file each time. For bz2 files, this sets the block size. Yields: Lines from the back of the file. Raises: TypeError: If m_file is the name of the file (expect file stream). Warnings: If max_mem is smaller than blk_size. """ # Check for illegal usage if isinstance(m_file, (str, Path)): raise TypeError("expect a file stream, not file name") # Generate line ending l_end: Literal["\r\n", "\n"] = _get_line_ending(m_file) len_l_end: Literal[1, 2] = cast(Literal[1, 2], len(l_end)) # Bz2 files do not have "name" attribute, just set to max_mem for now if hasattr(m_file, "name"): file_size: int = os.path.getsize(m_file.name) else: file_size = max_mem # If the file size is within desired RAM limit, just reverse it in memory. # Gzip files must use this method because there is no way to negative seek. if file_size < max_mem or isinstance(m_file, gzip.GzipFile): for line in reversed(m_file.readlines()): yield line if isinstance(line, str) else cast(bytes, line).decode("utf-8") else: # RAM limit should be greater than block size, # as file is read into RAM one block each time. if max_mem < blk_size: warnings.warn(f"{max_mem=} smaller than {blk_size=}", stacklevel=2) # For bz2 files, seek is expensive. It is therefore in our best # interest to maximize the block size within RAM usage limit. if isinstance(m_file, bz2.BZ2File): blk_size = min(max_mem, file_size) # Check if the file stream is text (instead of binary) is_text: bool = isinstance(m_file, io.TextIOWrapper) # Use a deque of decoded chunks instead of repeated string concatenation # to avoid O(N^2) behavior on large files. Chunks are joined only when # the buffer must be searched/sliced for a line ending. chunks: deque[str] = deque() buffer: str = "" m_file.seek(0, 2) skipped_1st_l_end: bool = False while True: l_end_pos: int = buffer.rfind(l_end) # Pointer position (also size of remaining file) pt_pos: int = m_file.tell() # Line ending found within buffer if l_end_pos != -1: line = buffer[l_end_pos + len_l_end :] buffer = buffer[:l_end_pos] # buffer doesn't include l_end # Skip first match (the last line ending) if skipped_1st_l_end: yield line + l_end else: skipped_1st_l_end = True # Line ending not in current buffer, load next block into the buffer elif pt_pos > 0: to_read: int = min(blk_size, pt_pos) m_file.seek(pt_pos - to_read) if is_text: chunk = cast(str, m_file.read(to_read)) else: chunk = cast(bytes, m_file.read(to_read)).decode("utf-8") chunks.appendleft(buffer) chunks.appendleft(chunk) # Move pointer forward m_file.seek(pt_pos - to_read) # Add a l_end to the start of file if pt_pos == to_read: chunks.appendleft(l_end) buffer = "".join(chunks) chunks.clear() # Start of file else: # l_end_pos == -1 and pt_post == 0 return class FileLockException(Exception): """Exception raised by FileLock.""" class FileLock: """Cross-platform file locking with context-manager support. Does not rely on ``msvcrt`` or ``fcntl`` for locking. Adapted from http://www.evanfosmark.com/2009/01/cross-platform-file-locking-support-in-python/. """ Error = FileLockException def __init__( self, file_name: str, timeout: float = 10, delay: float = 0.05 ) -> None: """Prepare the file locker. Args: file_name (str): Name of file to lock. timeout (float): Maximum timeout in seconds for locking. Defaults to 10. delay (float): Delay in seconds between each attempt to lock. Defaults to 0.05. """ self.file_name = os.path.abspath(file_name) self.lockfile = f"{os.path.abspath(file_name)}.lock" self.timeout = timeout self.delay = delay self.is_locked = False if self.delay > self.timeout or self.delay <= 0 or self.timeout <= 0: raise ValueError("delay and timeout must be positive with delay <= timeout") def __enter__(self): """Acquire the lock on entering the ``with`` block.""" if not self.is_locked: self.acquire() return self def __exit__(self, type_, value, traceback): """Release the lock when exiting the ``with`` block, if held.""" if self.is_locked: self.release() def __del__(self): """Release any held lock so no lockfile is left behind.""" self.release() def acquire(self) -> None: """Acquire the lock, retrying every ``delay`` seconds. Continues until the lock is acquired or ``timeout`` seconds elapse, in which case ``FileLockException`` is raised. """ start_time = time.time() while True: try: self.fd = os.open(self.lockfile, os.O_CREAT | os.O_EXCL | os.O_RDWR) break except OSError as exc: if exc.errno != errno.EEXIST: raise if (time.time() - start_time) >= self.timeout: raise FileLockException( f"{self.lockfile}: Timeout occurred." ) from exc time.sleep(self.delay) self.is_locked = True def release(self) -> None: """Release the lock by deleting the lockfile. Called automatically at the end of a ``with`` statement. """ if self.is_locked: os.close(self.fd) os.unlink(self.lockfile) self.is_locked = False def get_open_fds() -> int: """Get the number of open file descriptors for current process. Warning, this will only work on UNIX-like OS. Returns: int: The number of open file descriptors for current process. """ pid: int = os.getpid() procs: bytes = subprocess.check_output(["lsof", "-w", "-Ff", "-p", str(pid)]) _procs: str = procs.decode("utf-8") return len([s for s in _procs.split("\n") if s and s[0] == "f" and s[1:].isdigit()]) monty-2026.10.21/src/monty/itertools.py000066400000000000000000000060241526577750300176310ustar00rootroot00000000000000"""Additional tools for iteration.""" from __future__ import annotations import itertools import sys from typing import TYPE_CHECKING import numpy as np if TYPE_CHECKING: from collections.abc import Iterable # Use stdlib batched on 3.12+, fall back to local impl otherwise. _HAS_BATCHED = sys.version_info >= (3, 12) def chunks(items: Iterable, n: int) -> Iterable: """Yield successive n-sized chunks from a list-like object. >>> import pprint >>> pprint.pprint(list(chunks(range(1, 25), 10))) [(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), (11, 12, 13, 14, 15, 16, 17, 18, 19, 20), (21, 22, 23, 24)] """ if _HAS_BATCHED: yield from itertools.batched(items, n) # type: ignore[attr-defined] return it = iter(items) chunk = tuple(itertools.islice(it, n)) while chunk: yield chunk chunk = tuple(itertools.islice(it, n)) def iterator_from_slice(s) -> Iterable: """Constructs an iterator given a slice object s. Notes: The function returns an infinite iterator if s.stop is None """ start = s.start if s.start is not None else 0 step = s.step if s.step is not None else 1 if s.stop is None: # Infinite iterator. return itertools.count(start=start, step=step) # xrange-like iterator that supports float. return iter(np.arange(start, s.stop, step)) def iuptri(items: Iterable, diago: bool = True, with_inds: bool = False) -> Iterable: """A generator that yields the upper triangle of the matrix (items x items). Args: items: Iterable object with elements [e0, e1, ...] diago: False if diagonal matrix elements should be excluded with_inds: If True, (i,j) (e_i, e_j) is returned else (e_i, e_j) >>> for (ij, mate) in iuptri([0,1], with_inds=True): ... print("ij:", ij, "mate:", mate) ij: (0, 0) mate: (0, 0) ij: (0, 1) mate: (0, 1) ij: (1, 1) mate: (1, 1) """ pairs = itertools.combinations_with_replacement if diago else itertools.combinations if not with_inds: yield from pairs(items, 2) return for (ii, item1), (jj, item2) in pairs(enumerate(items), 2): yield (ii, jj), (item1, item2) def ilotri(items: Iterable, diago: bool = True, with_inds: bool = False) -> Iterable: """A generator that yields the lower triangle of the matrix (items x items). Args: items: Iterable object with elements [e0, e1, ...] diago: False if diagonal matrix elements should be excluded with_inds: If True, (i,j) (e_i, e_j) is returned else (e_i, e_j) >>> for (ij, mate) in ilotri([0,1], with_inds=True): ... print("ij:", ij, "mate:", mate) ij: (0, 0) mate: (0, 0) ij: (1, 0) mate: (1, 0) ij: (1, 1) mate: (1, 1) """ items = list(items) n = len(items) extra = 1 if diago else 0 for ii in range(n): item1 = items[ii] for jj in range(ii + extra): if with_inds: yield (ii, jj), (item1, items[jj]) else: yield item1, items[jj] monty-2026.10.21/src/monty/json.py000066400000000000000000001603301526577750300165570ustar00rootroot00000000000000"""JSON serialization and deserialization utilities.""" from __future__ import annotations import dataclasses import datetime import functools import json import os import pathlib import pickle import sys import traceback import types from collections import OrderedDict, defaultdict from enum import Enum from hashlib import sha1 from importlib import import_module from inspect import getfullargspec, isclass from pathlib import Path from typing import TYPE_CHECKING from uuid import UUID, uuid4 import numpy as np if TYPE_CHECKING: from typing import Any try: import bson from bson import json_util _BSON_JSON_OPTIONS = json_util.JSONOptions(tz_aware=True) # type: ignore[no-untyped-call] except ImportError: bson = None # type: ignore[assignment] json_util = None # type: ignore[assignment] _BSON_JSON_OPTIONS = None # type: ignore[assignment] __version__ = "3.0.0" # --------------------------------------------------------------------------- # Cached helpers (perf hot paths) # --------------------------------------------------------------------------- @functools.cache def _init_spec(cls: type): """Cache ``getfullargspec(cls.__init__)``. Typically the dominant cost of ``MSONable.as_dict``. """ return getfullargspec(cls.__init__) # type: ignore[misc] @functools.cache def _module_version(modname: str) -> str | None: """Cache the ``__version__`` lookup for a top-level module name. ``MSONable.as_dict`` and ``MontyEncoder.default`` both call this per encoded object; the result is determined entirely by the module name. """ try: return str(import_module(modname).__version__) except (AttributeError, ImportError): return None @functools.cache def _resolve_class(modname: str, classname: str) -> type | None: """Cache ``__import__`` + ``getattr`` of a class by ``(module, name)``. ``ImportError`` is intentionally *not* swallowed — callers (notably the redirect path) rely on it surfacing when a redirect points at a missing module. """ mod = __import__(modname, globals(), locals(), [classname], 0) return getattr(mod, classname, None) _TYPE_STR_CACHE: dict[tuple[type, tuple[str, ...]], bool] = {} def _type_str_match(tp: type, type_strs: tuple[str, ...]) -> bool: """Return whether ``tp.mro()`` contains any qualified name in ``type_strs``. Result is cached per ``(type, type_strs)`` pair — most callers query the same handful of strings against the same type repeatedly (``torch.Tensor``, ``pandas.DataFrame``, etc.). """ key = (tp, type_strs) cached = _TYPE_STR_CACHE.get(key) if cached is not None: return cached result = any( f"{o.__module__}.{o.__qualname__}" == ts for o in tp.mro() for ts in type_strs ) _TYPE_STR_CACHE[key] = result return result class _LazyRedirect: """Class-level descriptor that loads ``~/.monty.yaml`` lazily on first access. Avoids paying the ``ruamel.yaml`` import and filesystem stat cost on every ``import monty.json`` (which is on the import path of pymatgen, matgl, matcalc, etc.). """ def __init__(self) -> None: self._value: dict | None = None def __get__(self, instance, owner) -> dict: if self._value is None: self._value = _load_redirect( os.path.join(os.path.expanduser("~"), ".monty.yaml") ) return self._value def __set__(self, instance, value) -> None: # Allow overriding (e.g. for tests). self._value = value def _load_redirect(redirect_file) -> dict: # Defer the heavy ruamel.yaml import until we actually need to parse a # redirect file. This avoids pulling YAML in on every ``import monty.json``. try: f = open(redirect_file, encoding="utf-8") except OSError: return {} with f: from ruamel.yaml import YAML # local import — cold path d = YAML().load(f) # Convert the full paths to module/class redirect_dict: dict = defaultdict(dict) for old_path, new_path in d.items(): old_class = old_path.split(".")[-1] old_module = ".".join(old_path.split(".")[:-1]) new_class = new_path.split(".")[-1] new_module = ".".join(new_path.split(".")[:-1]) redirect_dict[old_module][old_class] = { "@module": new_module, "@class": new_class, } return dict(redirect_dict) def _check_type(obj: object, type_str: tuple[str, ...] | str) -> bool: """Import-free alternative to ``isinstance`` based on qualified type names. Checks whether ``obj`` is an instance of the type identified by ``type_str`` (a fully qualified name like ``"torch.Tensor"``), which avoids importing the type explicitly. Subclasses are matched, mirroring ``isinstance`` semantics. Note for future developers: the ``type_str`` for a given object is not always obvious. Use ``type(obj).mro()`` to enumerate the qualified names that an object will match (in order of generality, with ``"builtins.object"`` last). """ # This function is intended as an alternative of "isinstance", # therefore wouldn't check class if isclass(obj): return False type_strs = type_str if isinstance(type_str, tuple) else (type_str,) return _type_str_match(type(obj), type_strs) def _recursive_as_dict(obj): """Recursive helper for ``MSONable.as_dict``. Kept at module level so it is not re-created on every ``as_dict`` invocation. """ if isinstance(obj, (list, tuple)): return [_recursive_as_dict(it) for it in obj] if isinstance(obj, dict): return {kk: _recursive_as_dict(vv) for kk, vv in obj.items()} if hasattr(obj, "as_dict"): return obj.as_dict() if dataclasses.is_dataclass(obj): d = dataclasses.asdict(obj) d.update( { "@module": obj.__class__.__module__, "@class": obj.__class__.__name__, } ) return d return obj # --------------------------------------------------------------------------- # Type handler plugin registry # --------------------------------------------------------------------------- class TypeHandler: """Plugin protocol for encoding and decoding a single external type. Subclasses set ``module`` and ``class_name`` class attributes (used for decoder dispatch and for the ``@module``/``@class`` keys of the emitted JSON dict) and implement :meth:`matches`, :meth:`encode`, and :meth:`decode`. ``class_name`` may be a tuple of strings when one handler covers more than one ``@class`` value (e.g. pandas DataFrame + Series); ``encode`` is then responsible for picking the right ``@class`` per object. Register custom handlers via :func:`register`. Built-in handlers for ``datetime``, ``uuid``, ``pathlib.Path``, ``numpy.ndarray``, ``torch.Tensor``, ``pandas.DataFrame``/``Series``, ``pint.Quantity``, and ``bson.ObjectId`` are registered at import time and are always checked first; user handlers run after. Examples: >>> class MyHandler(TypeHandler): ... module = "mypkg" ... class_name = "MyType" ... ... def matches(self, obj): ... return isinstance(obj, MyType) ... ... def encode(self, obj): ... return {"@module": "mypkg", "@class": "MyType", "value": obj.value} ... ... def decode(self, d): ... return MyType(d["value"]) ... >>> register(MyHandler()) """ module: str = "" class_name: str | tuple[str, ...] = "" def decoder_keys(self) -> list[tuple[str, str]]: """Return all ``(@module, @class)`` decoder keys this handler claims. The default derives keys from the ``module`` and ``class_name`` attributes (the latter may be a tuple of names). Override when one handler spans multiple ``@module`` namespaces — e.g. a merged bson handler claiming both ``("bson.objectid", "ObjectId")`` and ``("bson.dbref", "DBRef")``. """ names = self.class_name if isinstance(names, str): names = (names,) return [(self.module, n) for n in names] def matches(self, obj: Any) -> bool: """Return True if this handler should encode ``obj``.""" raise NotImplementedError def encode(self, obj: Any) -> Any: """Return the JSON-compatible representation of ``obj``. Typically a dict carrying ``@module``, ``@class``, and type-specific fields. May also return a JSON-native primitive (int/float/bool/ str/None) for types that collapse to a scalar on the wire (e.g. numpy scalars). Primitives are not reconstructed by the decoder's ``@module``/``@class`` dispatch — the standard JSON parser handles them on the way back. """ raise NotImplementedError def decode(self, d: dict) -> Any: """Reconstruct the live object from its dict representation.""" raise NotImplementedError def sanitize(self, obj: Any, recurse: Any, **opts: Any) -> Any: """Return a JSON-native (flat) representation of ``obj`` for :func:`jsanitize`. Default returns :data:`NotImplemented`, opting this handler out of ``jsanitize`` dispatch — the generic resolver then handles ``obj``. Override when the sanitized form should differ from :meth:`encode`'s round-trippable envelope (e.g. ``PathHandler`` emits ``str(obj)`` here but a ``{@module, @class, string}`` dict in ``encode``). Args: obj: The matched object. recurse: Callable that recursively sanitizes a value with the same options as the parent call. Use this for containers whose elements may themselves be sanitize-eligible. **opts: Forwarded :func:`jsanitize` options — currently ``allow_bson`` and ``enum_values``. """ return NotImplemented # Built-in handlers, checked first to preserve PR #791's hot-path order. _BUILTIN_HANDLERS: list[TypeHandler] = [] # User-registered handlers, checked after the built-ins. _USER_HANDLERS: list[TypeHandler] = [] # (module, class_name) -> handler for O(1) decoder dispatch. _DECODER_HANDLERS: dict[tuple[str, str], TypeHandler] = {} # Pre-bound ``(matches, encode)`` callable pairs for the encoder hot path. # Iterating bound methods directly avoids the attribute-lookup cost of # ``h.matches(obj)`` / ``h.encode(obj)`` per dispatch and recovers most of # the perf delta vs. the legacy inline if/elif chain. Rebuilt whenever the # user handler list changes; built-in pairs come first. _ENCODER_DISPATCH: tuple[tuple[Any, Any], ...] = () # Parallel ``(matches, sanitize)`` pairs for the ``jsanitize`` hot path. # Only handlers that override the base ``sanitize`` participate, so # unsanitized types skip the dispatch loop entirely. _SANITIZE_DISPATCH: tuple[tuple[Any, Any], ...] = () def _rebuild_encoder_dispatch() -> None: global _ENCODER_DISPATCH, _SANITIZE_DISPATCH # noqa: PLW0603 handlers = (*_BUILTIN_HANDLERS, *_USER_HANDLERS) _ENCODER_DISPATCH = tuple((h.matches, h.encode) for h in handlers) _SANITIZE_DISPATCH = tuple( (h.matches, h.sanitize) for h in handlers if type(h).sanitize is not TypeHandler.sanitize ) def _handler_keys(handler: TypeHandler) -> list[tuple[str, str]]: """Return one ``(module, class_name)`` decoder key per name a handler claims.""" return list(handler.decoder_keys()) def register(handler: TypeHandler) -> None: """Register a custom :class:`TypeHandler` with the JSON registry. The handler's ``encode(obj)`` is invoked when ``MontyEncoder`` encounters an instance for which ``handler.matches(obj)`` returns True. The ``decode(d)`` method is dispatched on the ``@module``/``@class`` keys of the incoming dict. A handler may claim multiple ``@class`` names by setting ``class_name`` to a tuple — every entry is registered as its own decoder key. Re-registering for any of those keys replaces the previous registration. """ keys = _handler_keys(handler) for key in keys: existing = _DECODER_HANDLERS.get(key) if existing is not None and existing in _USER_HANDLERS: _USER_HANDLERS.remove(existing) if handler not in _USER_HANDLERS: _USER_HANDLERS.append(handler) for key in keys: _DECODER_HANDLERS[key] = handler _rebuild_encoder_dispatch() def unregister(handler: TypeHandler) -> None: """Remove a previously-registered user handler.""" if handler in _USER_HANDLERS: _USER_HANDLERS.remove(handler) for key in _handler_keys(handler): if _DECODER_HANDLERS.get(key) is handler: del _DECODER_HANDLERS[key] _rebuild_encoder_dispatch() def _register_builtin(handler: TypeHandler) -> None: _BUILTIN_HANDLERS.append(handler) for key in _handler_keys(handler): _DECODER_HANDLERS[key] = handler _rebuild_encoder_dispatch() # --------------------------------------------------------------------------- # Built-in type handlers # --------------------------------------------------------------------------- class DatetimeHandler(TypeHandler): """Encode and decode :class:`datetime.datetime` instances.""" module = "datetime" class_name = "datetime" def matches(self, obj: Any) -> bool: return isinstance(obj, datetime.datetime) def encode(self, obj: Any) -> dict: return { "@module": "datetime", "@class": "datetime", "string": str(obj), } def decode(self, d: dict) -> Any: s = d["string"] try: # ``fromisoformat`` is ~5x faster than ``strptime`` and handles # fractional seconds and ``+HH:MM`` timezone suffixes natively. return datetime.datetime.fromisoformat(s) except ValueError: # Fall back to the legacy parser for non-ISO inputs. s = s.split("+")[0] try: return datetime.datetime.strptime(s, "%Y-%m-%d %H:%M:%S.%f") except ValueError: return datetime.datetime.strptime(s, "%Y-%m-%d %H:%M:%S") def sanitize(self, obj: Any, recurse: Any, **opts: Any) -> Any: # ``allow_bson`` keeps datetime intact so it can be inserted into # MongoDB, which has native BSON datetime support. if opts.get("allow_bson"): return obj return str(obj) class UUIDHandler(TypeHandler): """Encode and decode :class:`uuid.UUID` instances.""" module = "uuid" class_name = "UUID" def matches(self, obj: Any) -> bool: return isinstance(obj, UUID) def encode(self, obj: Any) -> dict: return {"@module": "uuid", "@class": "UUID", "string": str(obj)} def decode(self, d: dict) -> Any: return UUID(d["string"]) def sanitize(self, obj: Any, recurse: Any, **opts: Any) -> Any: return str(obj) class PathHandler(TypeHandler): """Encode and decode :class:`pathlib.Path` instances.""" module = "pathlib" class_name = "Path" def matches(self, obj: Any) -> bool: return isinstance(obj, Path) def encode(self, obj: Any) -> dict: return {"@module": "pathlib", "@class": "Path", "string": str(obj)} def decode(self, d: dict) -> Any: return Path(d["string"]) def sanitize(self, obj: Any, recurse: Any, **opts: Any) -> Any: return str(obj) class TorchTensorHandler(TypeHandler): """Encode and decode ``torch.Tensor`` (lazy ``torch`` import).""" module = "torch" class_name = "Tensor" def matches(self, obj: Any) -> bool: # ``sys.modules`` gate skips the (cached but non-free) MRO scan when # torch hasn't been imported yet — see PR #791. return "torch" in sys.modules and _check_type(obj, "torch.Tensor") def encode(self, obj: Any) -> dict: d: dict[str, Any] = { "@module": "torch", "@class": "Tensor", "dtype": obj.type(), "size": list(obj.size()), } if "Complex" in obj.type(): d["data"] = [obj.real.tolist(), obj.imag.tolist()] else: d["data"] = obj.numpy().tolist() return d def decode(self, d: dict) -> Any: import torch # heavy import deferred until first decode if "Complex" in d["dtype"]: if "size" in d and d["data"] == [[], []]: return torch.empty(d["size"]).type(d["dtype"]) return torch.tensor( [ np.array(r) + np.array(i) * 1j for r, i in zip(*d["data"], strict=True) ], ).type(d["dtype"]) if "size" in d and d["data"] == []: return torch.empty(d["size"]).type(d["dtype"]) return torch.tensor(d["data"]).type(d["dtype"]) class NumpyHandler(TypeHandler): """Encode and decode numpy arrays and scalars. ``np.ndarray`` round-trips through the ``@module``/``@class`` envelope; ``np.generic`` scalars collapse to native Python primitives on the wire (decoded by stdlib ``json``). """ module = "numpy" class_name = "array" def matches(self, obj: Any) -> bool: # Match both ndarray and scalar in one branch so the order of # operations between them lives entirely inside ``encode``. return isinstance(obj, (np.ndarray, np.generic)) def encode(self, obj: Any) -> Any: # Numpy scalars collapse to a JSON-native primitive — no envelope. if isinstance(obj, np.generic): return obj.item() if str(obj.dtype).startswith("complex"): return { "@module": "numpy", "@class": "array", "dtype": str(obj.dtype), "data": [obj.real.tolist(), obj.imag.tolist()], } return { "@module": "numpy", "@class": "array", "dtype": str(obj.dtype), "data": obj.tolist(), } def decode(self, d: dict) -> Any: if d["dtype"].startswith("complex"): return np.array( [ np.array(r) + np.array(i) * 1j for r, i in zip(*d["data"], strict=True) ], dtype=d["dtype"], ) return np.array(d["data"], dtype=d["dtype"]) def sanitize(self, obj: Any, recurse: Any, **opts: Any) -> Any: if isinstance(obj, np.generic): return obj.item() # ndarray: recurse into the python-list form so nested non-JSON-native # values (datetimes, objects) get sanitized too. ``tolist`` can fail # for object-dtype arrays containing unhashable items; in that case # fall back to the raw ``tolist`` output without recursion. try: return [recurse(i) for i in obj.tolist()] except TypeError: return obj.tolist() class PandasHandler(TypeHandler): """Encode and decode ``pandas.DataFrame`` / ``Series`` (lazy ``pandas`` import). A single handler covers both because they share the same encoding shape (``to_json`` payload). The emitted ``@class`` is ``"DataFrame"`` or ``"Series"`` depending on the concrete object so the decoder can pick the right pandas constructor. """ module = "pandas" class_name = ("DataFrame", "Series") # Qualified names matched by ``_check_type``. DataFrame's are listed # first so ``encode`` can discriminate without re-walking the MRO. _DF_QUALNAMES = ("pandas.core.frame.DataFrame", "pandas.DataFrame") _SERIES_QUALNAMES = ("pandas.core.series.Series", "pandas.Series") def matches(self, obj: Any) -> bool: return "pandas" in sys.modules and _check_type( obj, self._DF_QUALNAMES + self._SERIES_QUALNAMES ) def encode(self, obj: Any) -> dict: cls_name = "DataFrame" if _check_type(obj, self._DF_QUALNAMES) else "Series" return { "@module": "pandas", "@class": cls_name, "data": obj.to_json(default_handler=MontyEncoder().encode), } def decode(self, d: dict) -> Any: import pandas as pd pd_cls = pd.DataFrame if d["@class"] == "DataFrame" else pd.Series return pd_cls(MontyDecoder().decode(d["data"])) def sanitize(self, obj: Any, recurse: Any, **opts: Any) -> Any: return obj.to_dict() class PintQuantityHandler(TypeHandler): """Encode and decode ``pint.Quantity`` (lazy ``pint`` import).""" module = "pint" class_name = "Quantity" def matches(self, obj: Any) -> bool: return "pint" in sys.modules and _check_type(obj, "pint.Quantity") def encode(self, obj: Any) -> dict: return { "@module": "pint", "@class": "Quantity", "data": str(obj), "@version": _module_version("pint"), } def decode(self, d: dict) -> Any: from pint import UnitRegistry ureg = UnitRegistry() return ureg.Quantity(d["data"]) class BsonHandler(TypeHandler): """Encode and decode ``bson.objectid.ObjectId`` and ``bson.dbref.DBRef`` (requires ``bson``). The two bson types share the same ``bson is not None`` gate and lazy import strategy, so they live in one handler. Each emits its own ``@module``/``@class`` keys so the decoder routes back to the correct constructor. DBRef is serialized with monty-style field names (``collection`` / ``id`` / optional ``database`` / optional ``extras``) rather than bson's extended-JSON convention (``$ref`` / ``$id`` / ``$db``). The latter is recognised by ``bson.json_util`` and would be eagerly constructed back into a DBRef during ``MontyDecoder.decode`` — before our registry could route the nested ``id`` field through the decoder. """ # ``decoder_keys`` is overridden below because the two types live in # different ``@module`` namespaces; the inherited ``module`` / # ``class_name`` attributes are intentionally left at their defaults. def decoder_keys(self) -> list[tuple[str, str]]: return [ ("bson.objectid", "ObjectId"), ("bson.dbref", "DBRef"), ] def matches(self, obj: Any) -> bool: if bson is None: return False return isinstance(obj, (bson.objectid.ObjectId, bson.dbref.DBRef)) def encode(self, obj: Any) -> dict: if isinstance(obj, bson.objectid.ObjectId): return { "@module": "bson.objectid", "@class": "ObjectId", "oid": str(obj), } # bson.dbref.DBRef. ``id`` may itself be an MSONable / ObjectId / # etc.; we hand it back to the surrounding ``MontyEncoder`` so the # full encode pipeline recurses into it as it walks the result dict. d: dict[str, Any] = { "@module": "bson.dbref", "@class": "DBRef", "collection": obj.collection, "id": obj.id, } if obj.database is not None: d["database"] = obj.database # DBRef supports arbitrary keyword extras; ``as_doc()`` exposes them # under their user-supplied names alongside the bson ``$``-prefixed # canonical fields. Drop the canonical ones to recover just extras. extras = { k: v for k, v in obj.as_doc().items() if k not in {"$ref", "$id", "$db"} } if extras: d["extras"] = extras return d def decode(self, d: dict) -> Any: if d["@class"] == "ObjectId": return bson.objectid.ObjectId(d["oid"]) # DBRef: recurse through the decoder so a nested ObjectId (or any # other handler-managed type) in ``id``/extras reconstructs. decoder = MontyDecoder() extras = {k: decoder.process_decoded(v) for k, v in d.get("extras", {}).items()} return bson.dbref.DBRef( collection=d["collection"], id=decoder.process_decoded(d["id"]), database=d.get("database"), **extras, ) def sanitize(self, obj: Any, recurse: Any, **opts: Any) -> Any: # Keep bson types unmodified when ``allow_bson`` so they go straight # into MongoDB as native types. Otherwise opt out and let # ``jsanitize``'s strict/strict=False fallthrough decide (str() or # AttributeError). if opts.get("allow_bson"): return obj return NotImplemented # Register built-ins in the order the legacy if/elif chain checked them. # Ordering is load-bearing for performance (see PR #791): cheap isinstance # checks first, then ``sys.modules``-gated qualified-name matches. _register_builtin(DatetimeHandler()) _register_builtin(UUIDHandler()) _register_builtin(PathHandler()) _register_builtin(TorchTensorHandler()) _register_builtin(NumpyHandler()) _register_builtin(PandasHandler()) _register_builtin(PintQuantityHandler()) _register_builtin(BsonHandler()) class MSONable: """Mix-in base class specifying an API for msonable objects. MSON is Monty JSON. Essentially, MSONable objects must implement an as_dict method, which must return a json serializable dict and must also support no arguments (though optional arguments to finetune the output is ok), and a from_dict class method that regenerates the object from the dict generated by the as_dict method. The as_dict method should contain the "@module" and "@class" keys which will allow the MontyEncoder to dynamically deserialize the class. E.g.:: d["@module"] = self.__class__.__module__ d["@class"] = self.__class__.__name__ A default implementation is provided in MSONable, which automatically determines if the class already contains self.argname or self._argname attributes for every arg. If so, these will be used for serialization in the dict format. Similarly, the default from_dict will deserialization classes of such form. An example is given below:: class MSONClass(MSONable): def __init__(self, a, b, c, d=1, **kwargs): self.a = a self.b = b self._c = c self._d = d self.kwargs = kwargs For such classes, you merely need to inherit from MSONable and you do not need to implement your own as_dict or from_dict protocol. New to Monty V2.0.6.... Classes can be redirected to moved implementations by putting in the old fully qualified path and new fully qualified path into .monty.yaml in the home folder Example: old_module.old_class: new_module.new_class """ # Backwards-compatible class attribute. The redirect file is loaded the # first time it is accessed via the ``_LazyRedirect`` descriptor. REDIRECT = _LazyRedirect() def as_dict(self) -> dict: """A JSON serializable dict representation of an object.""" cls = self.__class__ d: dict[str, Any] = { "@module": cls.__module__, "@class": cls.__name__, } parent_module = cls.__module__.partition(".")[0] d["@version"] = _module_version(parent_module) spec = _init_spec(cls) # type: ignore[arg-type] for c in spec.args + spec.kwonlyargs: if c != "self": try: a = getattr(self, c) except AttributeError: try: a = getattr(self, "_" + c) except AttributeError as exc: raise NotImplementedError( "Unable to automatically determine as_dict " "format from class. MSONAble requires all " "args to be present as either self.argname or " "self._argname, and kwargs to be present under " "a self.kwargs variable to automatically " "determine the dict format. Alternatively, " "you can implement both as_dict and from_dict." ) from exc d[c] = _recursive_as_dict(a) if hasattr(self, "kwargs"): d.update(**self.kwargs) if spec.varargs is not None and getattr(self, spec.varargs, None) is not None: d.update({spec.varargs: getattr(self, spec.varargs)}) if hasattr(self, "_kwargs"): d.update(**self._kwargs) if isinstance(self, Enum): d.update({"value": self.value}) return d @classmethod def from_dict(cls, d: dict) -> MSONable: """Reconstruct an MSONable object from a dict. Args: d: Dict representation. Returns: MSONable class. """ # Reuse a single module-level decoder rather than allocating a new # ``MontyDecoder`` for every key, which used to dominate this path. decoded = { k: _SHARED_DECODER.process_decoded(v) for k, v in d.items() if not k.startswith("@") } return cls(**decoded) def to_json(self) -> str: """Returns a json string representation of the MSONable object.""" return json.dumps(self, cls=MontyEncoder) def unsafe_hash(self) -> Any: """Return a hash of the current object. This uses a generic but low performance method of converting the object to a dictionary, flattening any nested keys, and then performing a hash on the resulting object. """ def flatten(obj, separator="."): # Flattens a dictionary flat_dict = {} for key, value in obj.items(): if isinstance(value, dict): flat_dict.update( { separator.join([key, _key]): _value for _key, _value in flatten(value).items() } ) elif isinstance(value, list): list_dict = { f"{key}{separator}{num}": item for num, item in enumerate(value) } flat_dict.update(flatten(list_dict)) else: flat_dict[key] = value return flat_dict ordered_keys = sorted( flatten(jsanitize(self.as_dict())).items(), key=lambda x: x[0] ) ordered_keys = [item for item in ordered_keys if "@" not in item[0]] # sha1 is used here as a fingerprint, not for cryptographic security. return sha1( json.dumps(OrderedDict(ordered_keys)).encode("utf-8"), usedforsecurity=False, ) @classmethod def _validate_monty(cls, __input_value): """Pydantic Validator for MSONable pattern.""" if isinstance(__input_value, cls): return __input_value if isinstance(__input_value, dict): # Do not allow generic exceptions to be raised during deserialization # since pydantic may handle them incorrectly. try: new_obj = MontyDecoder().process_decoded(__input_value) if isinstance(new_obj, cls): return new_obj return cls(**__input_value) except Exception as exc: raise ValueError( f"Error while deserializing {cls.__name__} " f"object: {traceback.format_exc()}" ) from exc raise ValueError( f"Must provide {cls.__name__}, the as_dict form, or the proper" ) @classmethod def validate_monty_v1(cls, __input_value): """Pydantic validator with correct signature for pydantic v1.x.""" return cls._validate_monty(__input_value) @classmethod def validate_monty_v2(cls, __input_value, _): """Pydantic validator with correct signature for pydantic v2.x.""" return cls._validate_monty(__input_value) @classmethod def __get_validators__(cls): """Return validators for use in pydantic.""" yield cls.validate_monty_v1 @classmethod def __get_pydantic_core_schema__(cls, source_type, handler): """Pydantic v2 core schema definition.""" try: from pydantic_core import core_schema except ImportError as exc: raise RuntimeError("Pydantic >= 2.0 is required for validation") from exc s = core_schema.with_info_plain_validator_function(cls.validate_monty_v2) return core_schema.json_or_python_schema(json_schema=s, python_schema=s) @classmethod def _generic_json_schema(cls): return { "type": "object", "properties": { "@class": {"enum": [cls.__name__], "type": "string"}, "@module": {"enum": [cls.__module__], "type": "string"}, "@version": {"type": "string"}, }, "required": ["@class", "@module"], } @classmethod def __get_pydantic_json_schema__(cls, core_schema, handler): """JSON schema for MSONable pattern.""" return cls._generic_json_schema() @classmethod def __modify_schema__(cls, field_schema): """JSON schema for MSONable pattern.""" custom_schema = cls._generic_json_schema() field_schema.update(custom_schema) def save( self, json_path: os.PathLike | str, mkdir: bool = True, json_kwargs: dict | None = None, pickle_kwargs: dict | None = None, strict: bool = True, ) -> None: """Serialize the instance to JSON on disk, pickling fields if needed. For a fully MSONable class, only ``{save_dir}/class.json`` is written. For a partially MSONable class, non-serializable attributes are pickled individually into the same directory, keeping the JSON portion readable. Args: json_path: The file to which to save the JSON object. A pickled companion file with the same stem but a different extension may also be written if the class is not entirely MSONable. mkdir: If True, create the target directory (including parents). json_kwargs: Keyword arguments forwarded to the JSON serializer. pickle_kwargs: Keyword arguments forwarded to ``pickle.dump``. strict: If True, refuse to overwrite existing files. """ save( self, json_path, mkdir=mkdir, json_kwargs=json_kwargs, pickle_kwargs=pickle_kwargs, strict=strict, ) @classmethod def load(cls, file_path: os.PathLike | str) -> MSONable: """Load an instance from a JSON file written by :meth:`save`. Args: file_path: The JSON file to load from. Returns: An instance of the class being reloaded. """ d = load2dict(file_path) return cls.from_dict(d) def save( obj: Any, json_path: os.PathLike | str, mkdir: bool = True, json_kwargs: dict | None = None, pickle_kwargs: dict | None = None, strict: bool = True, ) -> None: """Serialize an object to JSON on disk, pickling fields if needed. For a fully MSONable object, only ``{save_dir}/class.json`` is written. For a partially MSONable object, non-serializable attributes are pickled individually into the same directory, keeping the JSON portion readable. Args: obj: The object to save. json_path: The file to which to save the JSON object. A pickled companion file with the same stem but a different extension may also be written if ``obj`` is not entirely MSONable. mkdir: If True, create the target directory (including parents). json_kwargs: Keyword arguments forwarded to the JSON serializer. pickle_kwargs: Keyword arguments forwarded to ``pickle.dump``. strict: If True, refuse to overwrite existing files. """ json_path = Path(json_path) save_dir = json_path.parent json_kwargs = json_kwargs or {} pickle_kwargs = pickle_kwargs or {} encoded, name_object_map = partial_monty_encode(obj, json_kwargs) if mkdir: save_dir.mkdir(exist_ok=True, parents=True) # Define the pickle path pickle_path = save_dir / f"{json_path.stem}.pkl" # Check if the files exist and the strict parameter is True if strict and json_path.exists(): raise FileExistsError(f"strict is true and file {json_path} exists") if strict and pickle_path.exists(): raise FileExistsError(f"strict is true and file {pickle_path} exists") # Save the json file with open(json_path, "w", encoding="utf-8") as outfile: outfile.write(encoded) # Save the pickle file if we have anything to save from the name_object_map if name_object_map is not None: with open(pickle_path, "wb") as f: pickle.dump(name_object_map, f, **pickle_kwargs) def load(path: os.PathLike | str) -> MSONable: """Load an MSONable object from a JSON file written by :func:`save`. Args: path: Path to the JSON file to load. Returns: The reconstructed MSONable instance. """ d = load2dict(path) module = d["@module"] klass = d["@class"] module = import_module(module) klass = getattr(module, klass) return klass.from_dict(d) def load2dict(file_path: os.PathLike | str) -> dict: """Load a JSON file written by :func:`save` into a dictionary. Args: file_path (str): Path to the JSON file. Returns: dict: The dictionary representation of the JSON file. """ json_path = Path(file_path) save_dir = json_path.parent pickle_path = save_dir / f"{json_path.stem}.pkl" with open(json_path, encoding="utf-8") as infile: d = json.loads(infile.read()) if pickle_path.exists(): with open(pickle_path, "rb") as pkl_file: name_object_map = pickle.load(pkl_file) d = _recursive_name_object_map_replacement(d, name_object_map) return d def _recursive_name_object_map_replacement(d, name_object_map): if isinstance(d, dict): if "@object_reference" in d: name = d["@object_reference"] return name_object_map.pop(name) return { k: _recursive_name_object_map_replacement(v, name_object_map) for k, v in d.items() } if isinstance(d, list): return [_recursive_name_object_map_replacement(x, name_object_map) for x in d] return d class MontyEncoder(json.JSONEncoder): """JSON encoder that supports the MSONable API. Adds support for NumPy arrays, ``datetime`` objects, and bson ``ObjectId`` (when ``bson`` is installed). Examples: >>> import json >>> json.dumps(object, cls=MontyEncoder) """ def __init__( self, *args, allow_unserializable_objects: bool = False, **kwargs ) -> None: super().__init__(*args, **kwargs) self._allow_unserializable_objects = allow_unserializable_objects self._name_object_map: dict[str, Any] = {} self._index: int = 0 def _update_name_object_map(self, o): name = f"{self._index:012}-{uuid4()!s}" self._index += 1 self._name_object_map[name] = o return {"@object_reference": name} def default(self, o) -> Any: """Encode an object for JSON serialization. Type-specific handling is delegated to :class:`TypeHandler` plugins registered via :func:`register` (built-in handlers cover datetime, uuid, pathlib, numpy, torch, pandas, pint, bson). The fallback chain dispatches on pydantic / non-MSONable dataclass / MSONable ``as_dict`` / ``Enum`` in that order and injects ``@module``, ``@class``, and ``@version`` keys when they are missing. Args: o: Python object. Returns: A JSON-compatible value — typically a dict with ``@module`` and ``@class`` keys, but may also be a JSON-native primitive (e.g. for numpy scalars). """ # Plugin dispatch (datetime, uuid, pathlib, numpy, torch, pandas, # pint, bson + any user-registered handlers). The tuple holds # pre-bound ``(matches, encode)`` pairs to avoid per-iteration # attribute lookups. for matches, encode in _ENCODER_DISPATCH: if matches(o): return encode(o) if callable(o) and not isinstance(o, MSONable): try: return _serialize_callable(o) except AttributeError as e: # Some callables may not have instance __name__ if self._allow_unserializable_objects: return self._update_name_object_map(o) raise AttributeError(e) from e try: if "pydantic" in sys.modules and _check_type(o, "pydantic.main.BaseModel"): d = o.model_dump() elif ( dataclasses is not None and (not issubclass(o.__class__, MSONable)) and dataclasses.is_dataclass(o) ): # This handles dataclasses that are not subclasses of MSONAble. d = dataclasses.asdict(o) # type: ignore[call-overload, arg-type] elif hasattr(o, "as_dict"): d = o.as_dict() elif isinstance(o, Enum): d = {"value": o.value} elif self._allow_unserializable_objects: # Last resort logic. We keep track of some name of the object # as a reference, and instead of the object, store that # name, which of course is json-serializable d = self._update_name_object_map(o) else: raise TypeError( f"Object of type {o.__class__.__name__} is not JSON serializable" ) if "@module" not in d: d["@module"] = str(o.__class__.__module__) if "@class" not in d: d["@class"] = str(o.__class__.__name__) if "@version" not in d: d["@version"] = _module_version( o.__class__.__module__.partition(".")[0] ) return d except AttributeError: return json.JSONEncoder.default(self, o) class MontyDecoder(json.JSONDecoder): """JSON decoder that supports the MSONable API. Inspects each decoded dict for ``@module``/``@class`` keys and rebuilds the corresponding object when possible, falling back to the raw dict otherwise. Nested lists and dicts of MSONable objects decode correctly. Examples: >>> import json >>> json.loads(json_string, cls=MontyDecoder) """ def process_decoded(self, d: Any) -> Any: """Recursively decode dicts and lists containing MSONable objects.""" if isinstance(d, dict): modname: str | None classname: str | None was_redirected = False if "@module" in d and "@class" in d: modname = d["@module"] classname = d["@class"] if cls_redirect := MSONable.REDIRECT.get(modname, {}).get(classname): classname = cls_redirect["@class"] modname = cls_redirect["@module"] was_redirected = True elif "@module" in d and "@callable" in d: modname = d["@module"] objname = d["@callable"] classname = None if d.get("@bound", None) is not None: # if the function is bound to an instance or class, first # deserialize the bound object and then remove the object name # from the function name. obj = self.process_decoded(d["@bound"]) objname = objname.split(".")[1:] else: # if the function is not bound to an object, import the # function from the module name obj = __import__(modname, globals(), locals(), [objname], 0) objname = objname.split(".") try: # the function could be nested. e.g., MyClass.NestedClass.function # so iteratively access the nesting for attr in objname: obj = getattr(obj, attr) return obj except AttributeError: pass else: modname = None classname = None if classname and modname: # Plugin dispatch: O(1) lookup keyed on ``(@module, @class)``. # Covers datetime, uuid, pathlib, torch, numpy, pandas, pint, # bson, and any user-registered handlers. ``modname`` is only # ever ``None`` when ``classname`` is too (see the branches # above); the joint guard keeps mypy happy. handler = _DECODER_HANDLERS.get((modname, classname)) if handler is not None: try: return handler.decode(d) except ImportError: # Optional decoder dependency missing (e.g. torch). # Fall through to the generic resolver / raw dict. pass else: # Generic class resolution for MSONable / Enum / pydantic / # non-MSONable dataclass classes. try: cls_ = _resolve_class(modname, classname) except ModuleNotFoundError: # A missing module for a non-redirected class means an # optional dependency is absent (e.g. ``emmet`` in a # serialized ComputedEntry). Fall back to the raw dict # rather than crashing the whole decode. A *redirected* # class pointing at a missing module is a genuine error, # so re-raise in that case. if was_redirected: raise cls_ = None if cls_ is not None: data = {k: v for k, v in d.items() if not k.startswith("@")} if hasattr(cls_, "from_dict"): return cls_.from_dict(data) if issubclass(cls_, Enum): return cls_(d["value"]) if "pydantic" in sys.modules: import pydantic if issubclass(cls_, pydantic.BaseModel): d = { k: self.process_decoded(v) for k, v in data.items() } return cls_(**d) if ( not issubclass(cls_, MSONable) ) and dataclasses.is_dataclass(cls_): d = {k: self.process_decoded(v) for k, v in data.items()} return cls_(**d) # type: ignore[operator] return { self.process_decoded(k): self.process_decoded(v) for k, v in d.items() } if isinstance(d, list): return [self.process_decoded(x) for x in d] return d def decode(self, s: str) -> Any: # type: ignore[override] """Override decode from JSONDecoder. Args: s: JSON string. Returns: Decoded object. """ if bson is not None: # ``JSONOptions`` is moved to module scope so we do not allocate # a fresh options object on every decode call. d = json_util.loads(s, json_options=_BSON_JSON_OPTIONS) else: d = json.loads(s) return self.process_decoded(d) # Module-level decoder reused by ``MSONable.from_dict`` so we avoid the # allocation cost of constructing a fresh decoder on every key. _SHARED_DECODER = MontyDecoder() class MSONError(Exception): """Exception class for serialization errors.""" def jsanitize( obj: Any, strict: bool = False, allow_bson: bool = False, enum_values: bool = False, recursive_msonable: bool = False, ) -> Any: """Recursively sanitize a JSON-like object for serialization. Walks lists/dicts (nested or otherwise), converts non-string dict keys to strings, and recursively encodes objects via Monty's ``as_dict`` protocol. Type-specific conversion (datetime, pathlib, numpy, pandas, bson, …) is delegated to :class:`TypeHandler` plugins that override ``sanitize`` — the same registry that drives :class:`MontyEncoder`. Custom handlers registered via :func:`register` automatically participate. Args: obj: input json-like object. strict (bool): This parameter sets the behavior when jsanitize encounters an object it does not understand. If strict is True, jsanitize will try to get the as_dict() attribute of the object. If no such attribute is found, an attribute error will be thrown. If strict is False, jsanitize will simply call str(object) to convert the object to a string representation. If "skip" is provided, jsanitize will skip and return the original object without modification. allow_bson (bool): This parameter sets the behavior when jsanitize encounters a bson supported type such as ObjectId, DBRef, or datetime. If True, such bson types will be ignored, allowing for proper insertion into MongoDB databases. enum_values (bool): Convert Enums to their values. recursive_msonable (bool): If True, uses .as_dict() for MSONables regardless of the value of strict. Returns: Sanitized dict that can be json serialized. """ # Fast path: native JSON-compatible primitives. Pulled to the front # because they dominate leaf counts in MSONable graphs from pymatgen / # matgl / matcalc — bypassing the Enum / handler-dispatch loop here # recovers the per-leaf cost of the plugin registry. Exact-type checks # (not isinstance) so ``np.float64`` / ``IntEnum`` still route to their # registered handlers / the Enum branch below. t = type(obj) if t is int or t is float or t is bool or t is str or obj is None: return obj # Common containers via exact-type check, before Enum / handler dispatch. # ``dict`` / ``list`` / ``tuple`` subclasses (AttrDict, OrderedDict, # frozendict, …) fall through to the isinstance fallbacks below. if t is dict: return { str(k): jsanitize( v, strict=strict, allow_bson=allow_bson, enum_values=enum_values, recursive_msonable=recursive_msonable, ) for k, v in obj.items() } if t is list or t is tuple: return [ jsanitize( i, strict=strict, allow_bson=allow_bson, enum_values=enum_values, recursive_msonable=recursive_msonable, ) for i in obj ] if isinstance(obj, Enum): if enum_values: return obj.value if hasattr(obj, "as_dict"): return obj.as_dict() return MontyEncoder().default(obj) # ``bytes`` is the only allow_bson short-circuit that isn't already a # registered handler (datetime / ObjectId / DBRef are). if allow_bson and isinstance(obj, bytes): return obj # Plugin dispatch — datetime, pathlib, numpy, pandas, uuid, bson + any # user-registered handlers that override ``sanitize``. The ``recurse`` # closure threads the current options through nested calls. if _SANITIZE_DISPATCH: def recurse(v: Any) -> Any: return jsanitize( v, strict=strict, allow_bson=allow_bson, enum_values=enum_values, recursive_msonable=recursive_msonable, ) for matches, sanitize in _SANITIZE_DISPATCH: if matches(obj): result = sanitize( obj, recurse, allow_bson=allow_bson, enum_values=enum_values ) if result is not NotImplemented: return result # Container-subclass fallbacks for the exact-type fast paths above. if isinstance(obj, dict): return { str(k): jsanitize( v, strict=strict, allow_bson=allow_bson, enum_values=enum_values, recursive_msonable=recursive_msonable, ) for k, v in obj.items() } if isinstance(obj, (list, tuple)): return [ jsanitize( i, strict=strict, allow_bson=allow_bson, enum_values=enum_values, recursive_msonable=recursive_msonable, ) for i in obj ] # Numeric subclasses not picked up by a handler. if isinstance(obj, (int, float)): return obj if callable(obj) and not isinstance(obj, MSONable): try: return _serialize_callable(obj) except TypeError: pass if recursive_msonable: try: return jsanitize( obj.as_dict(), strict=strict, allow_bson=allow_bson, enum_values=enum_values, recursive_msonable=recursive_msonable, ) except AttributeError: pass if strict is False: return str(obj) if isinstance(obj, str): return obj if "pydantic" in sys.modules and _check_type(obj, "pydantic.main.BaseModel"): return jsanitize( MontyEncoder().default(obj), strict=strict, allow_bson=allow_bson, enum_values=enum_values, recursive_msonable=recursive_msonable, ) try: return jsanitize( obj.as_dict(), strict=strict, allow_bson=allow_bson, enum_values=enum_values, recursive_msonable=recursive_msonable, ) except Exception: if strict == "skip": return obj raise def _serialize_callable(o): if isinstance(o, types.BuiltinFunctionType): # don't care about what builtin functions (sum, open, etc) are bound to bound = None else: # bound methods (i.e., instance methods) have a __self__ attribute # that points to the class/module/instance bound = getattr(o, "__self__", None) # we are only able to serialize bound methods if the object the method is # bound to is itself serializable if bound is not None: try: bound = MontyEncoder().default(bound) except TypeError as exc: raise TypeError( "Only bound methods of classes or MSONable instances are supported." ) from exc return { "@module": o.__module__, "@callable": getattr(o, "__qualname__", o.__name__), "@bound": bound, } def _get_partial_json(obj, json_kwargs): """Return the JSON representation of an object with unserializable parts substituted. Unserializable components are replaced with hash references that :func:`partial_monty_encode` can map back to pickled companions. """ json_kwargs = json_kwargs or {} encoder = MontyEncoder(allow_unserializable_objects=True, **json_kwargs) encoded = encoder.encode(obj) return encoder, encoded def partial_monty_encode( obj: object, json_kwargs: dict | None = None ) -> tuple[str, dict | None]: """Encode an object that may contain unhashable parts. Args: obj: The object to encode. json_kwargs: Keyword arguments forwarded to the JSON serializer. Returns: A ``(json_string, name_object_map)`` pair. The map is ``None`` when no unserializable parts were encountered — previously an empty dict was returned, which caused ``save()`` to always write an empty ``.pkl`` companion file. """ encoder, encoded = _get_partial_json( obj=obj, json_kwargs=json_kwargs, ) name_object_map = encoder._name_object_map return encoded, (name_object_map or None) monty-2026.10.21/src/monty/logging.py000066400000000000000000000041171526577750300172340ustar00rootroot00000000000000"""Logging tools.""" from __future__ import annotations import argparse import datetime import functools import logging from typing import TYPE_CHECKING if TYPE_CHECKING: from collections.abc import Callable def logged(level: int = logging.DEBUG) -> Callable: """Decorator that logs the start and end of a method call. Args: level: Level to log method at. Defaults to ``DEBUG``. """ def wrap(f): _logger = logging.getLogger(f"{f.__module__}.{f.__name__}") def wrapped_f(*args, **kwargs): _logger.log( level, f"Called at {datetime.datetime.now()} with args = {args} and kwargs = {kwargs}", ) data = f(*args, **kwargs) _logger.log( level, f"Done at {datetime.datetime.now()} with args = {args} and kwargs = {kwargs}", ) return data return wrapped_f return wrap def enable_logging(main: Callable) -> Callable: """Decorator that initializes logging with a ``--loglevel`` CLI option. Useful for simple main functions calling libraries that use the standard ``logging`` module. Args: main: The main function. """ @functools.wraps(main) def wrapper(*args, **kwargs): parser = argparse.ArgumentParser() parser.add_argument( "--loglevel", default="ERROR", type=str, help="Set the loglevel. Possible values: CRITICAL, ERROR (default)," "WARNING, INFO, DEBUG", ) options = parser.parse_args() # loglevel is bound to the string value obtained from the command line # argument. # Convert to upper case to allow the user to specify --loglevel=DEBUG # or --loglevel=debug numeric_level = getattr(logging, options.loglevel.upper(), None) if not isinstance(numeric_level, int): raise ValueError(f"Invalid log level: {options.loglevel}") logging.basicConfig(level=numeric_level) return main(*args, **kwargs) return wrapper monty-2026.10.21/src/monty/math.py000066400000000000000000000012521526577750300165340ustar00rootroot00000000000000"""Addition math functions.""" from __future__ import annotations import math from monty.dev import deprecated @deprecated(replacement="math.comb", deadline=(2028, 1, 1)) def nCr(n: int, r: int) -> int: """Calculates nCr (binomial coefficient or "n choose r"). Args: n (int): total number of items. r (int): items to choose Returns: nCr. """ return math.comb(n, r) @deprecated(replacement="math.perm", deadline=(2028, 1, 1)) def nPr(n: int, r: int) -> int: """Calculates nPr. Args: n (int): total number of items. r (int): items to permute Returns: nPr. """ return math.perm(n, r) monty-2026.10.21/src/monty/msgpack.py000066400000000000000000000013501526577750300172270ustar00rootroot00000000000000"""msgpack serialization and deserialization utilities. A thin shim over ``monty.json``'s encoder/decoder. The naming matches msgpack's ``default`` and ``object_hook`` parameters. """ from __future__ import annotations from monty.json import MontyDecoder, MontyEncoder def default(obj: object) -> dict: """Encode an object for ``msgpack.packb(obj, default=default)``. Supports Monty's ``as_dict`` protocol, numpy arrays, and ``datetime``. """ return MontyEncoder().default(obj) def object_hook(d: dict) -> object: """Decode a dict from ``msgpack.unpackb(..., object_hook=object_hook)``. Supports Monty's ``as_dict`` protocol, numpy arrays, and ``datetime``. """ return MontyDecoder().process_decoded(d) monty-2026.10.21/src/monty/multiprocessing.py000066400000000000000000000022241526577750300210320ustar00rootroot00000000000000"""Multiprocessing utilities.""" from __future__ import annotations from multiprocessing import Pool from typing import TYPE_CHECKING if TYPE_CHECKING: from collections.abc import Callable, Iterable try: from tqdm.autonotebook import tqdm except ImportError as exc: raise ImportError("tqdm must be installed for this function.") from exc def imap_tqdm(nprocs: int, func: Callable, iterable: Iterable, *args, **kwargs) -> list: """Run ``Pool.imap`` over ``iterable`` with a ``tqdm`` progress bar. Args: nprocs: Number of processes. func: Callable applied to each item. iterable: Iterable of arguments. args: Passthrough to ``Pool.imap``. kwargs: Passthrough to ``Pool.imap``. Returns: Results of ``Pool.imap``. """ data = [] with Pool(nprocs) as pool: try: n = len(iterable) # type: ignore[arg-type] except TypeError: n = None # type: ignore[arg-type] with tqdm(total=n) as prog_bar: for d in pool.imap(func, iterable, *args, **kwargs): prog_bar.update() data.append(d) return data monty-2026.10.21/src/monty/operator.py000066400000000000000000000013241526577750300174360ustar00rootroot00000000000000"""Useful additional functions for operators.""" from __future__ import annotations import operator from typing import TYPE_CHECKING if TYPE_CHECKING: from collections.abc import Callable def operator_from_str(op: str) -> Callable: """Return the operator associated to the given string `op`. Raises: `KeyError` if invalid string. """ d = { "==": operator.eq, "!=": operator.ne, ">": operator.gt, ">=": operator.ge, "<": operator.lt, "<=": operator.le, "+": operator.add, "-": operator.sub, "*": operator.mul, "%": operator.mod, "^": operator.xor, "/": operator.truediv, } return d[op] monty-2026.10.21/src/monty/os/000077500000000000000000000000001526577750300156525ustar00rootroot00000000000000monty-2026.10.21/src/monty/os/__init__.py000066400000000000000000000024701526577750300177660ustar00rootroot00000000000000"""Os functions, e.g., cd, makedirs_p.""" from __future__ import annotations import contextlib import os from typing import TYPE_CHECKING from monty.dev import deprecated if TYPE_CHECKING: from monty.shutil import PathLike __author__ = "Shyue Ping Ong" __copyright__ = "Copyright 2013, The Materials Project" __version__ = "0.1" __maintainer__ = "Shyue Ping Ong" __email__ = "ongsp@ucsd.edu" __date__ = "1/24/14" @deprecated(replacement="contextlib.chdir", deadline=(2028, 1, 1)) def cd(path: PathLike) -> contextlib.chdir: """Context manager that temporarily changes the working directory. The working directory is restored on exit. Equivalent to ``contextlib.chdir``. Examples: >>> with cd("/my/path/"): ... do_something() Args: path: Path to ``cd`` to. """ return contextlib.chdir(path) @deprecated(replacement="os.makedirs(path, exist_ok=True)", deadline=(2028, 1, 1)) def makedirs_p(path: PathLike, **kwargs) -> None: """Thread-safe ``os.makedirs`` that tolerates an existing directory. Mirrors the behaviour of ``mkdir -p``. Equivalent to ``os.makedirs(path, exist_ok=True)``. Args: path: Path of the directory to create. kwargs: Standard kwargs for ``os.makedirs``. """ os.makedirs(path, exist_ok=True, **kwargs) monty-2026.10.21/src/monty/os/path.py000066400000000000000000000074431526577750300171700ustar00rootroot00000000000000"""Path based methods, e.g., which, zpath, etc.""" from __future__ import annotations import os from typing import TYPE_CHECKING from monty.fnmatch import WildCard from monty.string import list_strings if TYPE_CHECKING: from collections.abc import Callable from typing import Literal, Optional, Union from monty.shutil import PathLike def zpath(filename: PathLike) -> str: """Return an existing (zipped or unzipped) path for ``filename``. Probes for ``filename`` and the common compressed variants. If none exist, the input is returned unchanged. Args: filename: Filename without a zip extension. Returns: str: Filename with a zip extension if such a file exists, otherwise the unzipped name (returned unchanged if no variant is found). """ filename = str(filename) # ensure we work with strings # First entry is empty so we probe the unzipped form below; skip it when # stripping suffixes since ``removesuffix("")`` is a no-op. exts = ("", ".gz", ".GZ", ".bz2", ".BZ2", ".z", ".Z") for ext in exts[1:]: filename = filename.removesuffix(ext) for ext in exts: zfilename = f"{filename}{ext}" if os.path.exists(zfilename): return zfilename return filename def find_exts( top: str, exts: str | list[str], exclude_dirs: str | None = None, include_dirs: str | None = None, match_mode: Literal["basename", "abspath"] = "basename", ) -> list[str]: """Find all files matching ``exts`` under the directory tree rooted at ``top``. Includes ``top`` itself but excludes ``.`` and ``..``. Args: top (str): Root directory exts (str or list of strings): List of extensions. exclude_dirs (str): Wildcards used to exclude particular directories. Can be concatenated via `|` include_dirs (str): Wildcards used to select particular directories. `include_dirs` and `exclude_dirs` are mutually exclusive match_mode (str): "basename" if match should be done on the basename. "abspath" for absolute path. Returns: list[str]: Absolute paths of the files. Examples: # Find all pdf and ps files starting from the current directory. find_exts(".", ("pdf", "ps")) # Find all pdf files, exclude hidden directories and dirs whose name # starts with `_` find_exts(".", "pdf", exclude_dirs="_*|.*") # Find all ps files, in the directories whose basename starts with # output. find_exts(".", "ps", include_dirs="output*")) """ # ``str.endswith`` accepts a tuple at the C level, which is several times # faster than the equivalent ``any(... for ext in exts)`` comprehension. _exts: tuple[str, ...] = tuple(list_strings(exts)) # Handle file! if os.path.isfile(top): return [os.path.abspath(top)] if top.endswith(_exts) else [] # Build shell-style wildcards. if exclude_dirs is not None: _exclude_dirs: WildCard = WildCard(exclude_dirs) if include_dirs is not None: _include_dirs: WildCard = WildCard(include_dirs) mangle_functions: dict[str, Callable[..., str]] = { "basename": os.path.basename, "abspath": os.path.abspath, } mangle: Callable[..., str] = mangle_functions[match_mode] # Assume directory paths: list[str] = [] for dirpath, _dirnames, filenames in os.walk(top): dirpath = os.path.abspath(dirpath) if exclude_dirs and _exclude_dirs.match(mangle(dirpath)): continue if include_dirs and not _include_dirs.match(mangle(dirpath)): continue paths.extend( os.path.join(dirpath, filename) for filename in filenames if filename.endswith(_exts) ) return paths monty-2026.10.21/src/monty/pprint.py000066400000000000000000000070731526577750300171260ustar00rootroot00000000000000"""Pretty printing functions.""" from __future__ import annotations import sys from io import StringIO from json import JSONEncoder, loads from typing import TYPE_CHECKING if TYPE_CHECKING: from collections.abc import Callable from typing import Any, TextIO def pprint_table( table: list[list], out: TextIO = sys.stdout, rstrip: bool = False ) -> None: """Print out a table of data, padded for alignment. Each row must have the same number of columns. Args: table: The table to print. A list of lists. out: Output stream (file-like object) rstrip: if True, trailing whitespace is removed from the entries. """ def max_width_col(table: list[list], col_idx: int) -> int: """Get the maximum width of the given column index.""" return max(len(row[col_idx]) for row in table) if rstrip: for row_idx, row in enumerate(table): table[row_idx] = [c.rstrip() for c in row] ncols = len(table[0]) col_paddings = [max_width_col(table, i) for i in range(ncols)] for row in table: # left col out.write(row[0].ljust(col_paddings[0] + 1)) # rest of the cols for i in range(1, len(row)): col = row[i].rjust(col_paddings[i] + 2) out.write(col) out.write("\n") def draw_tree( node: Any, child_iter: Callable[[Any], Any] = lambda n: n.children, text_str: Callable[[Any], str] = str, ) -> str: """Draw a tree from a root node as a string. Args: node: the root of the tree to be drawn. child_iter: function that when called with a node, returns an iterable over all its children. text_str: turns a node into the text to be displayed in the tree. The default implementations of these two arguments retrieve the children by accessing node.children and simply use str(node) to convert a node to a string. The resulting tree is drawn into a buffer and returned as a string. Based on https://pypi.python.org/pypi/asciitree/ """ return _draw_tree(node, "", child_iter, text_str) def _draw_tree( node: Any, prefix: str, child_iter: Callable[[Any], Any], text_str: Callable[[Any], str], ) -> str: buf = StringIO() children = list(child_iter(node)) # check if root node if prefix: buf.write(prefix[:-3]) buf.write(" +--") buf.write(text_str(node)) buf.write("\n") for index, child in enumerate(children): sub_prefix = prefix + " " if index + 1 == len(children) else prefix + " |" buf.write(_draw_tree(child, sub_prefix, child_iter, text_str)) return buf.getvalue() class DisplayEcoder(JSONEncoder): """Help convert dicts and objects to a format that can be displayed in notebooks.""" def default(self, o: Any) -> Any: """Try different ways of converting the present object for displaying.""" try: return o.as_dict() except Exception: pass try: return o.__dict__ except Exception: pass try: return str(o) except Exception: pass return None def pprint_json(data: Any) -> None: """Display a tree-like object in a jupyter notebook. Allows for collapsible interactive interaction with data. Args: data: a dictionary or object Based on: https://gist.github.com/jmmshn/d37d5a1be80a6da11f901675f195ca22 """ from IPython.display import JSON, display # pylint: disable=C0415 display(JSON(loads(DisplayEcoder().encode(data)))) monty-2026.10.21/src/monty/py.typed000066400000000000000000000000001526577750300167160ustar00rootroot00000000000000monty-2026.10.21/src/monty/re.py000066400000000000000000000045661526577750300162240ustar00rootroot00000000000000"""Helpful regex based functions. E.g., grepping.""" from __future__ import annotations import collections import contextlib import re from typing import TYPE_CHECKING from monty.io import reverse_readfile, zopen if TYPE_CHECKING: from collections.abc import Callable def regrep( filename: str, patterns: dict, reverse: bool = False, terminate_on_match: bool = False, postprocess: Callable = str, ) -> dict: r"""A powerful regular expression version of grep. Args: filename (str): Filename to grep. patterns (dict): A dict of patterns, e.g., {"energy": r"energy\\(sigma->0\\)\\s+=\\s+([\\d\\-\\.]+)"}. reverse (bool): Read files in reverse. Defaults to false. Useful for large files, especially when used with terminate_on_match. terminate_on_match (bool): Whether to terminate when there is at least one match in each key in pattern. postprocess (callable): A post processing function to convert all matches. Defaults to str, i.e., no change. Returns: A dict of the following form: {key1: [[[matches...], lineno], [[matches...], lineno], [[matches...], lineno], ...], key2: ...} For reverse reads, the lineno is given as a -ve number. Please note that 0-based indexing is used. """ compiled = [(k, re.compile(v)) for k, v in patterns.items()] matches: dict[str, list] = collections.defaultdict(list) # ``pending`` lets ``terminate_on_match`` short-circuit in O(1) per line # instead of re-scanning every key in ``compiled``. pending: set[str] | None = {k for k, _ in compiled} if terminate_on_match else None gen = ( reverse_readfile(filename) if reverse else zopen(filename, mode="rt", encoding="utf-8") ) for i, line in enumerate(gen): lineno = -i if reverse else i for k, p in compiled: if m := p.search(line): matches[k].append([[postprocess(g) for g in m.groups()], lineno]) if pending is not None: pending.discard(k) if pending is not None and not pending: break with contextlib.suppress(Exception): # Try to close open file handle. Pass if it is a generator. gen.close() # type: ignore[attr-defined, union-attr] return matches monty-2026.10.21/src/monty/serialization.py000066400000000000000000000220021526577750300204540ustar00rootroot00000000000000"""Serialization helpers for common formats (JSON, JSONL, YAML, msgpack).""" from __future__ import annotations import json import os import pathlib import threading from typing import TYPE_CHECKING, Literal, TextIO, cast from ruamel.yaml import YAML from monty.io import zopen from monty.json import MontyDecoder, MontyEncoder, MSONable from monty.msgpack import default, object_hook try: import msgpack except ImportError: msgpack = None if TYPE_CHECKING: from pathlib import Path from typing import Any from monty.shutil import PathLike _FILE_TYPE = Literal["json", "jsonl", "yaml", "mpk"] # Bridge the JSON ``TypeHandler`` plugin registry into ruamel.yaml so MSONable # subclasses and every registered handler type (numpy, pandas, pint, torch, # uuid, bson, user-registered) round-trip through ``dumpfn`` / ``loadfn`` the # same way they do via JSON. ruamel.yaml retains its native rendering for # types it already supports (datetime, set, OrderedDict, bytes, primitives). _MONTY_ENCODER = MontyEncoder() def _represent_via_monty(representer: Any, data: Any) -> Any: """Encode ``data`` via :class:`MontyEncoder` and represent the result. Used as a ruamel.yaml multi-representer for ``MSONable`` / ``PurePath`` and as the fallback for the ``None``-keyed dispatch slot (replacing ``represent_undefined``). The encoder returns a JSON-compatible value — typically a dict with ``@module``/``@class`` — which ruamel.yaml then represents recursively, so nested non-native types route through the same hook. """ return representer.represent_data(_MONTY_ENCODER.default(data)) # ruamel.yaml's ``YAML`` instance holds mutable per-call state (parser, # composer, constructor, emitter, serializer, representer caches) bound to the # instance during ``load``/``dump``. Sharing a single instance across threads # races on that state — see issue #795. We instead keep one instance per # thread via ``threading.local``, which amortizes construction within a thread # while keeping concurrent threads independent. _yaml_local = threading.local() def _build_yaml() -> YAML: """Construct a YAML instance with monty's MSONable/PurePath representers.""" yaml = YAML() yaml.representer.add_multi_representer(MSONable, _represent_via_monty) # Paths would otherwise hit ruamel.yaml's default ``str(obj)`` fallback, # which is lossy on load. Route them through the PathHandler envelope. yaml.representer.add_multi_representer(pathlib.PurePath, _represent_via_monty) # Replace the ``None`` slot — invoked when neither yaml_representers nor # yaml_multi_representers match — with a hook that tries MontyEncoder first, # falling back to the original ``represent_undefined`` (which raises # ``RepresenterError``) if MontyEncoder cannot serialize the object either. orig_represent_undefined = yaml.representer.yaml_representers[None] def _represent_undefined(representer: Any, data: Any) -> Any: try: return _represent_via_monty(representer, data) except TypeError: return orig_represent_undefined(representer, data) yaml.representer.yaml_representers[None] = _represent_undefined return yaml def _get_yaml() -> YAML: """Return the calling thread's YAML instance, constructing it on first use.""" yaml = getattr(_yaml_local, "yaml", None) if yaml is None: yaml = _build_yaml() _yaml_local.yaml = yaml return yaml def _identify_format(file_name: str | Path) -> _FILE_TYPE: """Identify the format of a file with name ``file_name``. Detection is based on extension (suffix) rather than substring match so a file called ``"myjsonlist.json"`` is not mis-classified as JSON-lines and ``"data.mpkfoo"`` is not classified as msgpack. """ # ``os.path.basename`` is fast and avoids a ``Path`` allocation. We strip # one layer of common compression suffixes so e.g. ``foo.json.gz`` is # detected as JSON. basename = os.path.basename(str(file_name)).lower() for compressed_ext in (".gz", ".bz2", ".xz", ".lzma", ".z"): if basename.endswith(compressed_ext): basename = basename[: -len(compressed_ext)] break if basename.endswith(".mpk"): return "mpk" if basename.endswith((".yaml", ".yml")): return "yaml" if basename.endswith(".jsonl"): return "jsonl" return "json" def loadfn( fn: PathLike, *args, fmt: _FILE_TYPE | None = None, **kwargs, ) -> Any: """Load JSON/JSONL/YAML/msgpack from a filename. Supports BZ2 (``.bz2``), GZIP (``.gz``, ``.z``), XZ (``.xz``, ``.lzma``) compressed inputs transparently. YAML support requires ``ruamel.yaml``. Format is auto-detected from the (case-insensitive) extension: ``.yaml`` / ``.yml`` → YAML; ``.mpk`` → msgpack; ``.jsonl`` → JSON lines; otherwise JSON. Args: fn (str | Path): Filename or ``pathlib.Path``. *args: Any of the args supported by ``json``/``yaml``/``msgpack.load``. fmt ("json" | "jsonl" | "yaml" | "mpk"): If provided, overrides the auto-detected format. **kwargs: Any of the kwargs supported by ``json``/``yaml``/``msgpack.load``. Returns: object: Result of ``json``/``yaml``/``msgpack.load``. """ fmt = fmt or _identify_format(fn) if fmt == "mpk": if msgpack is None: raise RuntimeError( "Loading of message pack files is not possible as msgpack-python is not installed." ) if "object_hook" not in kwargs: kwargs["object_hook"] = object_hook with zopen(fn, mode="rb") as fp: return msgpack.load(fp, *args, **kwargs) # pylint: disable=E1101 else: with zopen(fn, mode="rt", encoding="utf-8") as fp: if fmt == "yaml": if YAML is None: raise RuntimeError("Loading of YAML files requires ruamel.yaml.") # ``cls`` is a monty-level kwarg (not ruamel.yaml's) — pop it # before forwarding so ``YAML.load`` doesn't choke. Passing # ``cls=None`` opts out of MSONable reconstruction, matching # the JSON path's escape hatch. cls = kwargs.pop("cls", MontyDecoder) loaded = _get_yaml().load(fp, *args, **kwargs) if cls is not None: loaded = cls().process_decoded(loaded) return loaded if fmt in {"json", "jsonl"}: if "cls" not in kwargs: kwargs["cls"] = MontyDecoder if fmt == "jsonl": return [json.loads(jline, *args, **kwargs) for jline in fp] return json.load(fp, *args, **kwargs) raise TypeError(f"Invalid format: {fmt}") def dumpfn( obj: object, fn: PathLike, *args, fmt: _FILE_TYPE | None = None, **kwargs, ) -> None: """Dump an object to a JSON/JSONL/YAML/msgpack file by filename. Supports BZ2 (``.bz2``), GZIP (``.gz``, ``.z``), XZ (``.xz``, ``.lzma``) compressed outputs transparently. YAML support requires ``ruamel.yaml``. Format is auto-detected from the (case-insensitive) extension: ``.yaml`` / ``.yml`` → YAML; ``.mpk`` → msgpack; ``.jsonl`` → JSON lines; otherwise JSON. Args: obj (object): Object to dump. fn (str | Path): Filename or ``pathlib.Path``. fmt ("json" | "jsonl" | "yaml" | "mpk"): If provided, overrides the auto-detected format. *args: Any of the args supported by ``json``/``yaml``/``msgpack.dump``. **kwargs: Any of the kwargs supported by ``json``/``yaml``/``msgpack.dump``. """ fmt = fmt or _identify_format(fn) if fmt == "mpk": if msgpack is None: raise RuntimeError( "Dumping to message pack files is not possible as msgpack-python is not installed." ) if "default" not in kwargs: kwargs["default"] = default with zopen(fn, mode="wb") as fp: msgpack.dump(obj, fp, *args, **kwargs) # pylint: disable=E1101 else: with zopen(fn, mode="wt", encoding="utf-8") as fp: fp = cast(TextIO, fp) if fmt == "yaml": if YAML is None: raise RuntimeError("Dumping to YAML files requires ruamel.yaml.") _get_yaml().dump(obj, fp, *args, **kwargs) elif fmt in {"json", "jsonl"}: if "cls" not in kwargs: kwargs["cls"] = MontyEncoder if fmt == "jsonl": write = fp.write for jobj in obj: # type: ignore[var-annotated,attr-defined] # Two writes avoid creating an intermediate ``str + "\n"`` # for every record. write(json.dumps(jobj, *args, **kwargs)) write("\n") else: fp.write(json.dumps(obj, *args, **kwargs)) else: raise TypeError(f"Invalid format: {fmt}") monty-2026.10.21/src/monty/shutil.py000066400000000000000000000143511526577750300171170ustar00rootroot00000000000000"""Copying and zipping utilities. Works on directories mostly.""" from __future__ import annotations import os import shutil import warnings from gzip import GzipFile from pathlib import Path from typing import TYPE_CHECKING, Union from monty.io import zopen if TYPE_CHECKING: from typing import Literal, Optional, TypeAlias PathLike: TypeAlias = str | Path def copy_r(src: PathLike, dst: PathLike) -> None: """Recursively copy ``src`` into ``dst`` (``cp -r`` semantics). Deprecated: prefer ``shutil.copytree(src, dst, dirs_exist_ok=True)``; use its ``symlinks`` argument to control symlink dereferencing. Args: src (PathLike): Source folder to copy. dst (PathLike): Destination folder. """ # TODO: remove after 2027-01-01 warnings.warn( "please use `shutil.copytree(src, dst, dirs_exist_ok=True)`", DeprecationWarning, stacklevel=2, ) shutil.copytree(src, dst, dirs_exist_ok=True) def gzip_dir(path: PathLike, compresslevel: int = 6) -> None: """Gzip each file in a directory individually. Unlike ``shutil.make_archive`` (which creates a tar archive), this produces ``.gz`` files that remain readable with common Unix-style commands like ``zless`` or ``zcat``. Args: path (PathLike): Path to directory. compresslevel (int): Level of compression, 1-9. 9 is the default for ``GzipFile``; 6 is the default for ``gzip``. """ for root, _, files in os.walk(Path(path)): for f in files: full_f = Path(root, f).resolve() if Path(f).suffix.lower() != ".gz" and not full_f.is_dir(): if os.path.exists(f"{full_f}.gz"): warnings.warn(f"Both {f} and {f}.gz exist.", stacklevel=2) continue with ( open(full_f, "rb") as f_in, GzipFile( f"{full_f}.gz", "wb", compresslevel=compresslevel ) as f_out, ): shutil.copyfileobj(f_in, f_out) shutil.copystat(full_f, f"{full_f}.gz") os.remove(full_f) def compress_file( filepath: PathLike, compression: Literal["gz", "bz2"] = "gz", target_dir: PathLike | None = None, ) -> None: """Compress a file in place, mirroring Unix ``gzip``/``bzip2`` behaviour. The original uncompressed file is removed after compression. Args: filepath (PathLike): Path to file. compression (str): A compression mode. Valid options are ``"gz"`` or ``"bz2"``. Defaults to ``"gz"``. target_dir (PathLike): Optional target directory for the compressed file. Defaults to ``None`` for in-place compression. """ filepath = Path(filepath) target_dir = Path(target_dir) if target_dir is not None else None if compression not in {"gz", "bz2"}: raise ValueError("Supported compression formats are 'gz' and 'bz2'.") if filepath.suffix.lower() != f".{compression}" and not filepath.is_symlink(): if target_dir is not None: os.makedirs(target_dir, exist_ok=True) compressed_file: PathLike = target_dir / f"{filepath.name}.{compression}" else: compressed_file = f"{filepath!s}.{compression}" with open(filepath, "rb") as f_in, zopen(compressed_file, mode="wb") as f_out: f_out.writelines(f_in) os.remove(filepath) def compress_dir(path: PathLike, compression: Literal["gz", "bz2"] = "gz") -> None: """Recursively compress each file in a directory. Compresses files individually rather than producing a single tar archive — use ``tarfile`` for the latter. Args: path (PathLike): Path to parent directory. compression (str): A compression mode. Valid options are ``"gz"`` or ``"bz2"``. Defaults to ``"gz"``. """ path = Path(path) for parent, _, files in os.walk(path): for f in files: compress_file(Path(parent, f), compression=compression) def decompress_file( filepath: PathLike, target_dir: PathLike | None = None ) -> str | None: """Decompress a file. Auto-detects ``gz``, ``bz2``, or ``z`` extensions. Args: filepath (PathLike): Path to file. target_dir (PathLike): Optional target directory for the decompressed file. Defaults to ``None`` for in-place decompression. Returns: str | None: The decompressed file path, or ``None`` if no operation was performed. """ filepath = Path(filepath) target_dir = Path(target_dir) if target_dir is not None else None file_ext = filepath.suffix if file_ext.lower() in {".bz2", ".gz", ".z"} and filepath.is_file(): if target_dir is not None: os.makedirs(target_dir, exist_ok=True) decompressed_file: PathLike = target_dir / filepath.name.removesuffix( file_ext ) else: decompressed_file = str(filepath).removesuffix(file_ext) with zopen(filepath, mode="rb") as f_in, open(decompressed_file, "wb") as f_out: f_out.writelines(f_in) os.remove(filepath) return str(decompressed_file) return None def decompress_dir(path: PathLike) -> None: """Recursively decompresses all files in a directory. Args: path (PathLike): Path to parent directory. """ path = Path(path) for parent, _, files in os.walk(path): for f in files: decompress_file(Path(parent, f)) def remove(path: PathLike, follow_symlink: bool = False) -> None: """Remove a file, folder tree, or symlink (optionally following symlinks). Behaviour by kind: 1. File → ``os.remove``. 2. Symlink → recursively remove the target if ``follow_symlink``, then unlink the symlink itself. 3. Directory → ``shutil.rmtree``. Args: path (PathLike): Path to remove. follow_symlink (bool): If True, follow symlinks and remove their targets as well. """ path = Path(path) if path.is_file(): os.remove(path) elif path.is_symlink(): if follow_symlink: remove(os.readlink(path)) Path.unlink(path) else: shutil.rmtree(path) monty-2026.10.21/src/monty/string.py000066400000000000000000000071211526577750300171120ustar00rootroot00000000000000"""Useful additional string functions.""" from __future__ import annotations from typing import TYPE_CHECKING, cast from monty.dev import deprecated if TYPE_CHECKING: from collections.abc import Iterable from typing import Any, Union def remove_non_ascii(s: str) -> str: """Remove non-ASCII characters from a string. Args: s (str): Input string. Returns: String with all non-ASCII characters removed. """ return s.encode("ascii", "ignore").decode("ascii") @deprecated(replacement="isinstance(s, str)", deadline=(2028, 1, 1)) def is_string(s: Any) -> bool: """Return True if ``s`` is a string. Historically this used a duck-typing ``s + " "`` probe, but every caller in monty (and downstream libraries) treats this as ``isinstance(s, str)``, so the C-level check is used directly — roughly 50x faster for the common "not a string" path because no exception is raised. """ return isinstance(s, str) def list_strings(arg: str | Iterable[str]) -> list[str]: """Always return a list of strings, given a string or iterable of strings. Examples: >>> list_strings('A single string') ['A single string'] >>> list_strings(['A single string in a list']) ['A single string in a list'] >>> list_strings(['A','list','of','strings']) ['A', 'list', 'of', 'strings'] >>> list_strings(('A','list','of','strings')) ['A', 'list', 'of', 'strings'] >>> list_strings({"a": 1, "b": 2}.keys()) ['a', 'b'] """ if isinstance(arg, str): return [arg] return [cast(str, s) for s in arg] def marquee(text: str = "", width: int = 78, mark: str = "*") -> str: """Return the input string centered in a 'marquee'. Args: text (str): Input string width (int): Width of final output string. mark (str): Character used to fill string. Examples: >>> marquee('A test', width=40) '**************** A test ****************' >>> marquee('A test', width=40, mark='-') '---------------- A test ----------------' marquee('A test',40, ' ') ' A test ' """ if not text: return (mark * width)[:width] nmark = (width - len(text) - 2) // len(mark) // 2 nmark = max(nmark, 0) marks = mark * nmark return f"{marks} {text} {marks}" def boxed(msg: str, ch: str = "=", pad: int = 5) -> str: """Returns a string in a box. Args: msg: Input string. ch: Character used to form the box. pad: Number of characters ch added before and after msg. Examples: >>> print(boxed("hello", ch="*", pad=2)) *********** ** hello ** *********** """ if pad > 0: msg = pad * ch + " " + msg.strip() + " " + pad * ch return "\n".join( [ len(msg) * ch, msg, len(msg) * ch, ] ) def make_banner(s: str, width: int = 78, mark: str = "*") -> str: """Build a banner string with full-width top and bottom rules. Args: s: String. width: Width of banner. Defaults to 78. mark: The mark used to create the banner. Returns: Banner string. """ banner = marquee(s, width=width, mark=mark) return "\n" + len(banner) * mark + "\n" + banner + "\n" + len(banner) * mark def indent(lines: str, amount: int, ch: str = " ") -> str: """Indent each line in ``lines`` by ``amount`` ``ch`` characters.""" padding = amount * ch return padding + ("\n" + padding).join(lines.split("\n")) monty-2026.10.21/src/monty/subprocess.py000066400000000000000000000051001526577750300177670ustar00rootroot00000000000000"""Calling shell processes.""" from __future__ import annotations import shlex import traceback from subprocess import PIPE, Popen, TimeoutExpired from typing import TYPE_CHECKING if TYPE_CHECKING: from collections.abc import Sequence from typing import Optional, Self __author__ = "Matteo Giantomass" __copyright__ = "Copyright 2014, The Materials Virtual Lab" __version__ = "0.1" __maintainer__ = "Matteo Giantomassi" __email__ = "gmatteo@gmail.com" __date__ = "10/26/14" class Command: """Run a subprocess command in a separate thread with a timeout. The subprocess is terminated if it does not finish within the timeout. Attributes: retcode: Return code of the subprocess. killed: True if the subprocess was killed due to the timeout. output: ``stdout`` of the subprocess. error: ``stderr`` of the subprocess. Examples: >>> com = Command("sleep 1").run(timeout=2) >>> print(com.retcode, com.killed, com.output, com.output) """ def __init__(self, command: str | Sequence[str]): """Initialize the command. Args: command: Command to execute, either as a shell-like string (split with ``shlex``) or as a sequence of arguments. """ self.command: list[str] = ( shlex.split(command) if isinstance(command, str) else list(command) ) self.process: Popen | None = None self.retcode: int | None = None self.output, self.error = "", "" self.killed = False def __str__(self): return f"command: {self.command}, retcode: {self.retcode}" def run(self, timeout: float | None = None, **kwargs) -> Self: """Run the command, waiting up to ``timeout`` seconds. Args: timeout: Maximum seconds to wait before killing the subprocess. **kwargs: Keyword arguments passed to ``Popen``. Returns: ``self``. """ kwargs.setdefault("stdout", PIPE) kwargs.setdefault("stderr", PIPE) try: with Popen(self.command, **kwargs) as proc: self.process = proc try: self.output, self.error = proc.communicate(timeout=timeout) except TimeoutExpired: proc.terminate() self.output, self.error = proc.communicate() self.killed = True self.retcode = proc.returncode except Exception: self.error = traceback.format_exc() self.retcode = -1 return self monty-2026.10.21/src/monty/tempfile.py000066400000000000000000000166501526577750300174200ustar00rootroot00000000000000"""Temporary directory and file creation utilities.""" from __future__ import annotations import contextlib import os import shutil import tempfile import warnings from typing import TYPE_CHECKING from monty.shutil import gzip_dir, remove if TYPE_CHECKING: from typing import ClassVar, Union from monty.shutil import PathLike class ScratchDir: """Context manager that creates and cleans up a temporary working directory. Creates a "with" context manager that automatically handles creation of temporary directories (utilizing Python's built-in temp directory functions) and cleanup when done. This improves on Python's built-in functions by allowing for truly temporary workspaces that are deleted when it is done. The way it works is as follows: 1. Create a temp dir in specified root path. 2. Optionally copy input files from current directory to temp dir. 3. Change to temp dir. 4. User performs specified operations. 5. Optionally copy generated output files back to original directory. 6. Change back to original directory. 7. Delete temp dir. Note: From Python 3.2 on, ``tempfile.TemporaryDirectory`` implements much of the functionality of ScratchDir. However, it does not provide options for copying of files to and from (though it is possible to do this with other methods provided by shutil). """ SCR_LINK: ClassVar[str] = "scratch_link" def __init__( self, rootpath: PathLike | None, create_symbolic_link: bool = False, copy_from_current_on_enter: bool = False, copy_to_current_on_exit: bool = False, gzip_on_exit: bool = False, delete_removed_files: bool | None = None, ) -> None: """Initialize scratch directory given a **root** path. There is no need to try to create unique directory names. The code will generate a temporary sub directory in the rootpath. The way to use this is using a with context manager. Example:: with ScratchDir("/scratch"): do_something() If the root path does not exist or is None, this will function as a simple pass through, i.e., nothing happens. Args: rootpath (str/Path): Path in which to create temp subdirectories. If this is None or not a directory, no temp directories will be created and this will just be a simple pass through. create_symbolic_link (bool): Whether to create a symbolic link in the current working directory to the scratch directory created. copy_from_current_on_enter (bool): Whether to copy all files from the current directory (recursively) to the temp dir at the start, e.g., if input files are needed for performing some actions. Defaults to False. copy_to_current_on_exit (bool): Whether to copy files from the scratch to the current directory (recursively) at the end. E .g., if output files are generated during the operation. Defaults to False. gzip_on_exit (bool): Whether to gzip the files generated in the ScratchDir before copying them back. Defaults to False. delete_removed_files (DEPRECATED): It now has no effect and will be removed in 2027-01-01. """ if delete_removed_files is not None: warnings.warn( "The 'delete_removed_files' argument is deprecated and has no effect. " "It will be removed in 2027-01-01.", DeprecationWarning, stacklevel=2, ) self.cwd: str = os.getcwd() self.rootpath: str | None = ( None if rootpath is None else os.path.abspath(rootpath) ) self.pass_through: bool = self.rootpath is None or not os.path.isdir( self.rootpath ) if self.rootpath is not None and not os.path.isdir(self.rootpath): warnings.warn( f"rootpath {self.rootpath} doesn't exist and is not directory, would just pass through", RuntimeWarning, stacklevel=2, ) self.create_symbolic_link: bool = create_symbolic_link self.enter_copy: bool = copy_from_current_on_enter self.exit_copy: bool = copy_to_current_on_exit self.gzip_on_exit: bool = gzip_on_exit def __enter__(self) -> str: tempdir: str = self.cwd if not self.pass_through: tempdir = tempfile.mkdtemp(dir=self.rootpath) self.tempdir = os.path.abspath(tempdir) if self.enter_copy: shutil.copytree(self.cwd, tempdir, dirs_exist_ok=True) if self.create_symbolic_link: os.symlink(tempdir, ScratchDir.SCR_LINK) os.chdir(tempdir) return tempdir def __exit__(self, exc_type, exc_val, exc_tb) -> None: if not self.pass_through: if self.exit_copy: # gzip files if self.gzip_on_exit: gzip_dir(self.tempdir) def walk_with_mtimes(root: PathLike) -> dict[str, float]: """Single-pass scandir walk: build {relpath -> mtime}. ``DirEntry.stat()`` reuses the ``stat`` info collected by the directory iterator on most platforms, avoiding the extra syscall pair that ``os.walk`` + ``os.path.getmtime`` would incur. """ out: dict[str, float] = {} root_str = os.fspath(root) stack: list[str] = [root_str] while stack: d = stack.pop() try: with os.scandir(d) as it: for entry in it: if entry.is_dir(follow_symlinks=False): stack.append(entry.path) else: with contextlib.suppress(FileNotFoundError): out[ os.path.relpath(entry.path, root_str) ] = entry.stat().st_mtime except FileNotFoundError: continue return out temp_mtimes = walk_with_mtimes(self.tempdir) cwd_mtimes = walk_with_mtimes(self.cwd) newer_in_cwd = [ rel for rel, t in cwd_mtimes.items() if rel in temp_mtimes and t > temp_mtimes[rel] ] if newer_in_cwd: warnings.warn( "ScratchDir: Detected files newer in CWD than tempdir; " f"copy-back would overwrite: {', '.join(newer_in_cwd)}", RuntimeWarning, stacklevel=2, ) # copy files over shutil.copytree(self.tempdir, self.cwd, dirs_exist_ok=True) os.chdir(self.cwd) remove(self.tempdir) if self.create_symbolic_link and os.path.islink(ScratchDir.SCR_LINK): os.remove(ScratchDir.SCR_LINK) monty-2026.10.21/src/monty/termcolor.py000066400000000000000000000116521526577750300176160ustar00rootroot00000000000000"""Copyright (c) 2008-2011 Volvox Development Team. # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # Author: Konstantin Lepa ANSII Color formatting for output in terminal. """ from __future__ import annotations import contextlib import os import shutil with contextlib.suppress(Exception): import curses __all__ = ["colored", "cprint"] VERSION = (1, 1, 0) ATTRIBUTES = { "bold": 1, "dark": 2, "underline": 4, "blink": 5, "reverse": 7, "concealed": 8, } HIGHLIGHTS = { "on_grey": 40, "on_red": 41, "on_green": 42, "on_yellow": 43, "on_blue": 44, "on_magenta": 45, "on_cyan": 46, "on_white": 47, } COLORS = { "grey": 30, "red": 31, "green": 32, "yellow": 33, "blue": 34, "magenta": 35, "cyan": 36, "white": 37, } RESET = "\033[0m" __ISON = True def enable(true_false: bool) -> None: """Enable/Disable ANSII Color formatting.""" global __ISON __ISON = true_false def ison() -> bool: """True if ANSII Color formatting is activated.""" return __ISON def stream_has_colours(stream: object) -> bool: """True if stream supports colours. Python cookbook, #475186.""" if not hasattr(stream, "isatty"): return False if not stream.isatty(): return False # auto color only on TTYs try: curses.setupterm() return curses.tigetnum("colors") > 2 except Exception: return False # guess false in case of error def colored( text: str, color: str = "", on_color: str = "", attrs: list[str] | None = None, ) -> str: """Colorize text. Available text colors: red, green, yellow, blue, magenta, cyan, white. Available text highlights: on_red, on_green, on_yellow, on_blue, on_magenta, on_cyan, on_white. Available attributes: bold, dark, underline, blink, reverse, concealed. Examples: colored('Hello, World!', 'red', 'on_grey', ['blue', 'blink']) colored('Hello, World!', 'green') """ if __ISON and os.getenv("ANSI_COLORS_DISABLED") is None: fmt_str = "\033[%dm%s" if color: text = fmt_str % (COLORS[color], text) if on_color: text = fmt_str % (HIGHLIGHTS[on_color], text) if attrs: for attr in attrs: text = fmt_str % (ATTRIBUTES[attr], text) text += RESET return text def cprint( text: str, color: str = "", on_color: str = "", attrs: list[str] | None = None, **kwargs, ) -> None: """Print colorize text. It accepts arguments of print function. """ print((colored(text, color, on_color, attrs)), **kwargs) def colored_map(text: str, cmap: dict) -> str: """Return colorized text. cmap is a dict mapping tokens to color options. colored_key("foo bar", {bar: "green"}) colored_key("foo bar", {bar: {"color": "green", "on_color": "on_red"}}) """ if not __ISON: return text for key, v in cmap.items(): if isinstance(v, dict): text = text.replace(key, colored(key, **v)) else: text = text.replace(key, colored(key, color=v)) return text def cprint_map(text: str, cmap: dict, **kwargs) -> None: """Print colorized text using a key→color mapping. Args: text: Text to print. cmap: Mapping of substrings to color options. **kwargs: Forwarded to ``print``. Examples: >>> cprint_map("Hello world", {"Hello": "red"}) """ print(colored_map(text, cmap), **kwargs) def get_terminal_size() -> tuple[int, int]: """Return the size of the terminal as (nrows, ncols). Thin wrapper around ``shutil.get_terminal_size``, which honors the ``LINES``/``COLUMNS`` environment variables, then queries the terminal attached to ``sys.__stdout__``, and falls back to (25, 80). """ size = shutil.get_terminal_size(fallback=(80, 25)) return size.lines, size.columns monty-2026.10.21/tasks.py000077500000000000000000000106231526577750300150000ustar00rootroot00000000000000"""Deployment file to facilitate releases of monty.""" from __future__ import annotations import datetime import glob import json import os import re from typing import TYPE_CHECKING import requests from invoke import task from monty import __version__ as ver from monty.os import cd if TYPE_CHECKING: from invoke import Context __author__ = "Shyue Ping Ong" __copyright__ = "Copyright 2012, The Materials Project" __version__ = "0.1" __maintainer__ = "Shyue Ping Ong" __email__ = "shyue@mit.edu" __date__ = "Apr 29, 2012" NEW_VER = datetime.datetime.today().strftime("%Y.%-m.%-d") @task def make_doc(ctx: Context) -> None: with cd("docs"): ctx.run("rm monty.*.rst", warn=True) ctx.run("sphinx-apidoc --separate -P -M -d 6 -o . -f ../src/monty") # ctx.run("rm monty*.html", warn=True) # ctx.run("sphinx-build -b html . ../docs") # HTML building. ctx.run("sphinx-build -M markdown . .") ctx.run("rm *.rst", warn=True) ctx.run("cp markdown/monty*.md .") for fn in glob.glob("monty*.md"): with open(fn, encoding="utf-8") as f: lines = [line.rstrip() for line in f if "Submodules" not in line] if fn == "monty.md": preamble = [ "---", "layout: default", "title: API Documentation", "nav_order: 5", "---", "", ] else: preamble = [ "---", "layout: default", f"title: {fn}", "nav_exclude: true", "---", "", ] with open(fn, "w", encoding="utf-8") as f: f.write("\n".join(preamble + lines)) ctx.run("rm -r markdown", warn=True) ctx.run("cp ../*.md .") ctx.run("mv README.md index.md") ctx.run("rm -rf *.orig doctrees", warn=True) with open("index.md", encoding="utf-8") as f: contents = f.read() with open("index.md", "w", encoding="utf-8") as f: contents = re.sub( r"\n## Official Documentation[^#]*", "{: .no_toc }\n\n## Table of contents\n{: .no_toc .text-delta }\n* TOC\n{:toc}\n\n", contents, ) contents = ( "---\nlayout: default\ntitle: Home\nnav_order: 1\n---\n\n" + contents ) f.write(contents) @task def update_doc(ctx: Context) -> None: ctx.run("git pull", warn=True) make_doc(ctx) ctx.run("git add .", warn=True) ctx.run('git commit -a -m "Update dev docs"', warn=True) ctx.run("git push", warn=True) @task def test(ctx: Context) -> None: ctx.run("pytest") @task def setver(ctx: Context) -> None: ctx.run(f'sed s/version=.*,/version=\\"{ver}\\",/ setup.py > newsetup') ctx.run("mv newsetup setup.py") @task def release_github(ctx: Context, version: str = NEW_VER) -> None: with open("docs/changelog.md", encoding="utf-8") as f: contents = f.read() toks = re.split("##", contents) desc = toks[1].strip() payload = { "tag_name": f"v{version}", "target_commitish": "main", "name": f"v{version}", "body": desc, "draft": False, "prerelease": False, } response = requests.post( "https://api.github.com/repos/materialyzeai/monty/releases", data=json.dumps(payload), headers={"Authorization": "token " + os.environ["GITHUB_RELEASES_TOKEN"]}, ) print(response.text) @task def commit(ctx: Context) -> None: ctx.run(f'git commit -a -m "v{NEW_VER} release"', warn=True) ctx.run("git push", warn=True) @task def set_ver(ctx: Context, version: str = NEW_VER) -> None: with open("pyproject.toml", encoding="utf-8") as f: contents = f.read() contents = re.sub(r"version = ([\.\d\"]+)", f'version = "{version}"', contents) with open("pyproject.toml", "w", encoding="utf-8") as f: f.write(contents) @task def release(ctx: Context, notest: bool = False, version: str = NEW_VER) -> None: set_ver(ctx, version) if not notest: test(ctx) # update_doc(ctx) print(f"Release Version: {version}") commit(ctx) release_github(ctx, version=version) ctx.run("python -m build", warn=True) ctx.run("python -m build --wheel", warn=True) monty-2026.10.21/tests/000077500000000000000000000000001526577750300144365ustar00rootroot00000000000000monty-2026.10.21/tests/__init__.py000066400000000000000000000004221526577750300165450ustar00rootroot00000000000000""" Unit tests and test files for Monty. """ from __future__ import annotations __author__ = "Shyue Ping Ong" __copyright__ = "Copyright 2012, The Materials Project" __version__ = "0.1" __maintainer__ = "Shyue Ping Ong" __email__ = "shyuep@gmail.com" __date__ = "1/24/14" monty-2026.10.21/tests/conftest.py000066400000000000000000000004751526577750300166430ustar00rootroot00000000000000from __future__ import annotations import os import shutil import tempfile import pytest @pytest.fixture() def tmp_dir(): """Run test in isolated test directory.""" old_cwd = os.getcwd() new_path = tempfile.mkdtemp() os.chdir(new_path) yield os.chdir(old_cwd) shutil.rmtree(new_path) monty-2026.10.21/tests/test_benchmarks.py000066400000000000000000000212111526577750300201610ustar00rootroot00000000000000"""Microbenchmarks for hot paths in monty. Run with ``pytest tests/test_benchmarks.py --benchmark-only`` (skipped from the default test run via ``-m "not benchmark"`` if you want to filter). The benchmarks target call sites that appear in tight loops in downstream libraries (pymatgen, matgl, matcalc). Numbers should only be compared on the same machine across commits. """ from __future__ import annotations import importlib import json from typing import TYPE_CHECKING import numpy as np import pytest if TYPE_CHECKING: from pathlib import Path from monty.collections import AttrDict, frozendict from monty.design_patterns import cached_class from monty.dev import deprecated from monty.fnmatch import WildCard from monty.fractions import gcd, lcm from monty.inspect import caller_name from monty.io import reverse_readline, zopen from monty.itertools import iuptri from monty.json import MontyDecoder, MontyEncoder, MSONable, jsanitize from monty.math import nCr, nPr from monty.os.path import find_exts, zpath from monty.re import regrep from monty.serialization import dumpfn, loadfn from monty.string import is_string, list_strings # ------------------------------------------------------------------------- # Fixtures # ------------------------------------------------------------------------- class _Sample(MSONable): def __init__(self, a: int, b: str, c: list) -> None: self.a = a self.b = b self.c = c @pytest.fixture def sample_obj() -> _Sample: return _Sample(a=1, b="hello", c=[1, 2, 3, 4, 5]) @pytest.fixture def sample_dict() -> dict: return { "a": 1, "b": "string", "c": [1, 2, 3, 4, 5], "d": {"nested": [{"x": i, "y": i * 2} for i in range(20)]}, "e": [{"k": v} for v in range(20)], } @pytest.fixture def large_array() -> np.ndarray: return np.arange(10_000, dtype=np.float64) @pytest.fixture def big_dir(tmp_path: Path) -> Path: for i in range(50): sub = tmp_path / f"sub{i}" sub.mkdir() for j in range(20): (sub / f"file{j}.txt").write_text("x") (sub / f"file{j}.log").write_text("x") return tmp_path @pytest.fixture def big_log(tmp_path: Path) -> Path: p = tmp_path / "big.log" with p.open("w") as f: for i in range(20_000): f.write(f"line {i} energy = {i * 0.001}\n") return p # ------------------------------------------------------------------------- # Import cost # ------------------------------------------------------------------------- def test_bench_import_monty_json(benchmark): def _reimport(): # Drop from sys.modules so the import body re-runs. import sys for k in list(sys.modules): if k == "monty.json" or k.startswith("monty.json."): del sys.modules[k] importlib.import_module("monty.json") benchmark(_reimport) # ------------------------------------------------------------------------- # json / MSONable hot paths # ------------------------------------------------------------------------- def test_bench_as_dict(benchmark, sample_obj): benchmark(sample_obj.as_dict) def test_bench_to_json(benchmark, sample_obj): benchmark(sample_obj.to_json) def test_bench_from_dict(benchmark, sample_obj): d = sample_obj.as_dict() benchmark(_Sample.from_dict, d) def test_bench_montyencoder_default_ndarray(benchmark, large_array): encoder = MontyEncoder() benchmark(encoder.default, large_array) def test_bench_montydecoder_process(benchmark, sample_dict): decoder = MontyDecoder() benchmark(decoder.process_decoded, sample_dict) def test_bench_jsanitize_plain(benchmark, sample_dict): benchmark(jsanitize, sample_dict) def test_bench_jsanitize_strict_ndarray(benchmark, large_array): benchmark(jsanitize, large_array) # ------------------------------------------------------------------------- # math / fractions # ------------------------------------------------------------------------- def test_bench_nCr_large(benchmark): benchmark(nCr, 200, 100) def test_bench_nPr_large(benchmark): benchmark(nPr, 200, 100) def test_bench_gcd_many(benchmark): nums = list(range(2, 50)) benchmark(gcd, *nums) def test_bench_lcm_many(benchmark): nums = list(range(2, 30)) benchmark(lcm, *nums) # ------------------------------------------------------------------------- # string # ------------------------------------------------------------------------- def test_bench_is_string_true(benchmark): benchmark(is_string, "hello world") def test_bench_is_string_false(benchmark): benchmark(is_string, 12345) def test_bench_list_strings_list(benchmark): args = [f"item{i}" for i in range(50)] benchmark(list_strings, args) # ------------------------------------------------------------------------- # itertools # ------------------------------------------------------------------------- def test_bench_iuptri(benchmark): items = list(range(40)) benchmark(lambda: list(iuptri(items))) # ------------------------------------------------------------------------- # collections # ------------------------------------------------------------------------- def test_bench_attrdict_set(benchmark): d = AttrDict() def _set(): for i in range(100): d[f"k{i}"] = i benchmark(_set) def test_bench_frozendict_init(benchmark): items = {f"k{i}": i for i in range(100)} benchmark(frozendict, items) # ------------------------------------------------------------------------- # design_patterns # ------------------------------------------------------------------------- def test_bench_cached_class_init(benchmark): @cached_class class C: def __init__(self, a, b=2, c=3): self.a, self.b, self.c = a, b, c counter = [0] def _make(): counter[0] += 1 return C(counter[0]) benchmark(_make) # ------------------------------------------------------------------------- # dev # ------------------------------------------------------------------------- def test_bench_deprecated_call(benchmark, recwarn): @deprecated(message="use new_func instead") def old_func(x, y): return x + y benchmark(old_func, 1, 2) # ------------------------------------------------------------------------- # fnmatch # ------------------------------------------------------------------------- def test_bench_wildcard_match(benchmark): w = WildCard("*.nc|*.pdf|*.txt|*.log") names = [f"file{i}.{ext}" for i in range(50) for ext in ("nc", "pdf", "tmp", "log")] benchmark(w.filter, names) # ------------------------------------------------------------------------- # os.path # ------------------------------------------------------------------------- def test_bench_find_exts(benchmark, big_dir): benchmark(find_exts, str(big_dir), ["txt"]) def test_bench_zpath(benchmark, tmp_path): f = tmp_path / "data.json" f.write_text("{}") target = str(f) benchmark(zpath, target) # ------------------------------------------------------------------------- # re # ------------------------------------------------------------------------- def test_bench_regrep(benchmark, big_log): patterns = {"energy": r"energy = ([\d\.]+)"} benchmark(regrep, str(big_log), patterns) def test_bench_regrep_terminate(benchmark, big_log): patterns = {"energy": r"energy = ([\d\.]+)"} benchmark(regrep, str(big_log), patterns, terminate_on_match=True) # ------------------------------------------------------------------------- # inspect # ------------------------------------------------------------------------- def test_bench_caller_name(benchmark): def caller(): return caller_name(skip=2) benchmark(caller) # ------------------------------------------------------------------------- # serialization # ------------------------------------------------------------------------- def test_bench_dumpfn_jsonl(benchmark, tmp_path): objs = [{"i": i, "x": list(range(10))} for i in range(200)] p = tmp_path / "out.jsonl" def _dump(): if p.exists(): p.unlink() dumpfn(objs, p) benchmark(_dump) def test_bench_loadfn_yaml(benchmark, tmp_path): p = tmp_path / "data.yaml" p.write_text("a: 1\nb: 2\nc:\n - 1\n - 2\n - 3\n") benchmark(loadfn, p) # ------------------------------------------------------------------------- # io # ------------------------------------------------------------------------- def test_bench_reverse_readline(benchmark, big_log): def _read(): with zopen(big_log, mode="rt", encoding="utf-8") as f: for _ in reverse_readline(f, max_mem=4096): pass benchmark(_read) monty-2026.10.21/tests/test_bisect.py000066400000000000000000000023211526577750300173160ustar00rootroot00000000000000from __future__ import annotations import pytest from monty.bisect import find_ge, find_gt, find_le, find_lt, index def test_funcs(): line = [0, 1, 2, 3, 4] assert index(line, 1) == 1 assert find_lt(line, 1) == 0 assert find_gt(line, 1) == 2 assert find_le(line, 1) == 1 assert find_ge(line, 2) == 2 @pytest.mark.parametrize( ("x", "atol", "expected"), [ (1.501, 0.1, 2), (1.499, 0.1, 2), (2.0001, 1e-3, 3), # Just above an element. (1.9999, 1e-3, 3), # Just below an element. (1.2, 0.5, 1), # Leftmost of several values within tolerance. ], ) def test_index_atol(x, atol, expected): assert index([0, 1, 1.5, 2], x, atol=atol) == expected @pytest.mark.parametrize( ("func", "x"), [ (index, 1.5), (index, 5), (find_lt, 0), (find_le, -1), (find_gt, 4), (find_ge, 5), ], ) def test_not_found(func, x): with pytest.raises(ValueError): func([0, 1, 2, 3, 4], x) def test_index_atol_not_found(): with pytest.raises(ValueError): index([0, 1, 2], 2.5, atol=0.1) # Tolerance is strict. with pytest.raises(ValueError): index([0, 1, 2], 2.5, atol=0.5) monty-2026.10.21/tests/test_collections.py000066400000000000000000000156031526577750300203720ustar00rootroot00000000000000from __future__ import annotations import pytest from monty.collections import ( AttrDict, ControlledDict, FrozenAttrDict, MongoDict, Namespace, dict2namedtuple, frozendict, tree, ) def test_tree(): x = tree() x["a"]["b"]["c"]["d"] = 1 assert "b" in x["a"] assert "c" not in x["a"] assert "c" in x["a"]["b"] assert x["a"]["b"]["c"]["d"] == 1 class TestControlledDict: def test_add_allowed(self): dct = ControlledDict(a=1) dct._allow_add = True dct["b"] = 2 assert dct["b"] == 2 dct.update(d=3) assert dct["d"] == 3 dct.setdefault("e", 4) assert dct["e"] == 4 def test_add_disabled(self): dct = ControlledDict(a=1) dct._allow_add = False with pytest.raises(TypeError, match="add is disabled"): dct["b"] = 2 with pytest.raises(TypeError, match="add is disabled"): dct.update(b=2) with pytest.raises(TypeError, match="add is disabled"): dct.setdefault("c", 2) def test_update_allowed(self): dct = ControlledDict(a=1) dct._allow_update = True dct["a"] = 2 assert dct["a"] == 2 dct.update({"a": 3}) assert dct["a"] == 3 # Test Iterator handling dct.update(zip(["c", "d"], [11, 12])) assert dct["c"] == 11 dct.setdefault("a", 4) # existing key assert dct["a"] == 3 def test_update_disabled(self): dct = ControlledDict(a=1) dct._allow_update = False with pytest.raises(TypeError, match="update is disabled"): dct["a"] = 2 with pytest.raises(TypeError, match="update is disabled"): dct.update({"a": 3}) with pytest.raises(TypeError, match="update is disabled"): dct.setdefault("a", 4) def test_del_allowed(self): dct = ControlledDict(a=1, b=2, c=3, d=4) dct._allow_del = True del dct["a"] assert "a" not in dct val = dct.pop("b") assert val == 2 and "b" not in dct val = dct.popitem() assert val == ("c", 3) and "c" not in dct dct.clear() assert dct == {} def test_del_disabled(self): dct = ControlledDict(a=1) dct._allow_del = False with pytest.raises(TypeError, match="delete is disabled"): del dct["a"] with pytest.raises(TypeError, match="delete is disabled"): dct.pop("a") with pytest.raises(TypeError, match="delete is disabled"): dct.popitem() with pytest.raises(TypeError, match="delete is disabled"): dct.clear() def test_frozen_like(self): """Make sure add and update are allowed at init time.""" ControlledDict._allow_add = False ControlledDict._allow_update = False dct = ControlledDict({"hello": "world"}) assert isinstance(dct, dict) assert dct["hello"] == "world" assert not dct._allow_add assert not dct._allow_update def test_iterator_handling(self): """Make sure iterators are handling correctly.""" c_dict = ControlledDict(zip(["c", "d"], [11, 12])) assert c_dict["c"] == 11 def test_frozendict(): dct = frozendict({"hello": "world"}) assert isinstance(dct, dict) assert dct["hello"] == "world" assert not dct._allow_add assert not dct._allow_update assert not dct._allow_del # Test setter with pytest.raises(TypeError, match="add is disabled"): dct["key"] = "val" # Test update with pytest.raises(TypeError, match="add is disabled"): dct.update(key="val") # Test pop with pytest.raises(TypeError, match="delete is disabled"): dct.pop("key") # Test delete with pytest.raises(TypeError, match="delete is disabled"): del dct["key"] def test_namespace_dict(): dct = Namespace(key="val") assert isinstance(dct, dict) # Test setter dct["hello"] = "world" assert dct["key"] == "val" # Test use `update` to add new values dct.update({"new_key": "new_value"}) assert dct["new_key"] == "new_value" # Test add (not allowed) with pytest.raises(TypeError, match="update is disabled"): dct["key"] = "val" with pytest.raises(TypeError, match="update is disabled"): dct.update({"key": "val"}) # Test delete (not allowed) with pytest.raises(TypeError, match="delete is disabled"): del dct["key"] def test_attr_dict(): dct = AttrDict(foo=1, bar=2) # Test get attribute assert dct.bar == 2 assert dct["foo"] is dct.foo # Test key not found error with pytest.raises(KeyError, match="no-such-key"): dct["no-such-key"] # Test setter dct.bar = "hello" assert dct["bar"] == "hello" # Test delete del dct.bar assert "bar" not in dct # Test builtin dict method shadowing with pytest.warns(UserWarning, match="shadows dict method"): dct["update"] = "value" def test_frozen_attrdict(): dct = FrozenAttrDict({"hello": "world", 1: 2}) assert isinstance(dct, dict) # Test attribute-like operations with pytest.raises(TypeError, match="does not support item assignment"): dct.foo = "bar" with pytest.raises(TypeError, match="does not support item assignment"): dct.hello = "new" with pytest.raises(TypeError, match="does not support item deletion"): del dct.hello # Test get value assert dct["hello"] == "world" assert dct.hello == "world" assert dct["hello"] is dct.hello # identity check # Test adding item with pytest.raises(TypeError, match="add is disabled"): dct["foo"] = "bar" # Test modifying existing item with pytest.raises(TypeError, match="update is disabled"): dct["hello"] = "new" # Test update with pytest.raises(TypeError, match="update is disabled"): dct.update({"hello": "world"}) # Test pop with pytest.raises(TypeError, match="delete is disabled"): dct.pop("hello") with pytest.raises(TypeError, match="delete is disabled"): dct.popitem() # Test delete with pytest.raises(TypeError, match="delete is disabled"): del dct["hello"] with pytest.raises(TypeError, match="delete is disabled"): dct.clear() def test_mongo_dict(): m_dct = MongoDict({"a": {"b": 1}, "x": 2}) assert m_dct.a.b == 1 assert m_dct.x == 2 assert "a" in m_dct assert "b" in m_dct.a assert m_dct["a"] == {"b": 1} def test_dict2namedtuple(): # Init from dict tpl = dict2namedtuple(foo=1, bar="hello") assert isinstance(tpl, tuple) assert tpl.foo == 1 and tpl.bar == "hello" # Init from list of tuples tpl = dict2namedtuple([("foo", 1), ("bar", "hello")]) assert isinstance(tpl, tuple) assert tpl[0] == 1 assert tpl[1] == "hello" assert tpl[0] is tpl.foo and tpl[1] is tpl.bar monty-2026.10.21/tests/test_design_patterns.py000066400000000000000000000144261526577750300212470ustar00rootroot00000000000000from __future__ import annotations import gc import pickle import weakref from typing import TYPE_CHECKING import pytest from monty.design_patterns import cached_class, singleton if TYPE_CHECKING: from typing import Any class TestSingleton: def test_singleton(self): @singleton class A: pass @singleton class B: pass a1 = A() a2 = A() assert a1 is a2 assert B() is B() assert B() is not a1 @cached_class class A: def __init__(self, val): self.val = val def __eq__(self, other): return self.val == other.val def __getinitargs__(self): return (self.val,) def __getnewargs__(self): return (self.val,) class TestCachedClass: def test_cached_class(self): a1a = A(1) a1b = A(1) a2 = A(2) assert id(a1a) == id(a1b) assert id(a1a) != id(a2) def test_pickle(self): a = A(2) o = pickle.dumps(a) assert a == pickle.loads(o) @cached_class class ClassForTest: def __init__(self, value: Any) -> None: self.value = value def test_caching(): # Test that instances are cached inst1 = ClassForTest(1) inst2 = ClassForTest(1) assert inst1 is inst2 inst3 = ClassForTest(2) assert inst1 is not inst3 def test_picklability(): # Test that instances can be pickled and unpickled original = ClassForTest(42) pickled = pickle.dumps(original) unpickled = pickle.loads(pickled) # Check that the unpickled instance has the same value assert original.value == unpickled.value # Check that the unpickled instance is the same as a newly created instance new_instance = ClassForTest(42) assert unpickled is new_instance def test_initialization(): init_count = 0 @cached_class class TestInitClass: def __init__(self): nonlocal init_count init_count += 1 inst1 = TestInitClass() inst2 = TestInitClass() assert init_count == 1 def test_class_identity(): # Ensure the decorated class is still recognized as the original class assert isinstance(ClassForTest(1), ClassForTest) assert type(ClassForTest(1)) is ClassForTest def test_multiple_arguments(): @cached_class class MultiArgClass: def __init__(self, a, b, c=3): self.args = (a, b, c) inst1 = MultiArgClass(1, 2) inst2 = MultiArgClass(1, 2) inst3 = MultiArgClass(1, 2, 4) assert inst1 is inst2 assert inst1 is not inst3 assert inst1.args == (1, 2, 3) assert inst3.args == (1, 2, 4) def test_different_argument_types(): @cached_class class MultiTypeClass: def __init__(self, a, b, c): self.a, self.b, self.c = a, b, c inst1 = MultiTypeClass(1, "string", (1, 2)) inst2 = MultiTypeClass(1, "string", (1, 2)) assert inst1 is inst2 inst3 = MultiTypeClass(1, "string", [1, 2]) # Unhashable argument assert inst1 is not inst3 def test_keyword_arguments(): @cached_class class KeywordClass: def __init__(self, a, b, c=3): self.a, self.b, self.c = a, b, c inst1 = KeywordClass(1, 2) inst2 = KeywordClass(a=1, b=2) assert inst1 is inst2 inst3 = KeywordClass(1, 2, 4) assert inst1 is not inst3 def test_inheritance_chain(): @cached_class class GrandParent: def __init__(self, value): self.value = value class Parent(GrandParent): pass @cached_class class Child(Parent): pass gp1 = GrandParent(1) gp2 = GrandParent(1) assert gp1 is gp2 p1 = Parent(1) p2 = Parent(1) assert p1 is p2 assert p1 is not gp1 c1 = Child(1) c2 = Child(1) assert c1 is c2 assert c1 is not p1 def test_memory_management(): @cached_class class WeakRefClass: def __init__(self, value): self.value = value inst = WeakRefClass(1) weak_ref = weakref.ref(inst) del inst gc.collect() assert weak_ref() is None # Creating a new instance should work new_inst = WeakRefClass(1) assert new_inst.value == 1 def test_exception_in_init(): init_count = 0 @cached_class class ExceptionClass: def __init__(self, value): nonlocal init_count init_count += 1 if init_count == 1: raise ValueError("First init failed") self.value = value with pytest.raises(ValueError): ExceptionClass(1) assert init_count == 1 # Second attempt should work and use cache inst1 = ExceptionClass(1) inst2 = ExceptionClass(1) assert inst1 is inst2 assert init_count == 2 def test_property_and_method_behavior(): @cached_class class PropertyClass: def __init__(self, value): self._value = value @property def value(self): return self._value def get_value(self): return self._value inst1 = PropertyClass(1) inst2 = PropertyClass(1) assert inst1 is inst2 assert inst1.value == 1 assert inst1.get_value() == 1 def test_class_method_and_static_method(): @cached_class class MethodClass: def __init__(self, value): self.value = value @classmethod def create(cls, value): return cls(value) @staticmethod def static_method(value): return value * 2 inst1 = MethodClass(1) inst2 = MethodClass.create(1) assert inst1 is inst2 assert MethodClass.static_method(5) == 10 def test_nested_cached_classes(): @cached_class class OuterClass: def __init__(self, value): self.value = value @cached_class class InnerClass: def __init__(self, inner_value): self.inner_value = inner_value outer1 = OuterClass(1) outer2 = OuterClass(1) assert outer1 is outer2 inner1 = outer1.InnerClass(2) inner2 = outer2.InnerClass(2) assert inner1 is inner2 def test_large_number_of_instances(): @cached_class class LargeNumberClass: def __init__(self, value): self.value = value instances = [LargeNumberClass(i) for i in range(1000)] for i, inst in enumerate(instances): assert inst is LargeNumberClass(i) monty-2026.10.21/tests/test_dev.py000066400000000000000000000132501526577750300166260ustar00rootroot00000000000000from __future__ import annotations import unittest import warnings from dataclasses import dataclass import pytest from monty.dev import deprecated, install_excepthook, requires try: from IPython.core import ultratb except ImportError: ultratb = None # Set all warnings to always be triggered. warnings.simplefilter("always") class TestDeprecated: def test_basic_usage(self): def func_replace(): pass @deprecated(func_replace, "Use func_replace instead", deadline=(2025, 1, 1)) def func_old(): """This is the old function.""" with warnings.catch_warnings(record=True) as w: # Trigger a warning. func_old() assert issubclass(w[0].category, FutureWarning) assert "Use func_replace instead" in str(w[0].message) assert "will be removed on 2025-01-01" in str(w[0].message) # Check metadata preservation assert func_old.__name__ == "func_old" assert func_old.__doc__ == "This is the old function." def test_str_replacement(self): @deprecated("func_replace") def func_old(): pass with warnings.catch_warnings(record=True) as w: # Trigger a warning. func_old() # Verify Warning and message assert issubclass(w[0].category, FutureWarning) assert "use func_replace instead" in str(w[0].message) def test_property(self): class TestClass: """A dummy class for tests.""" @property def property_a(self): pass @property @deprecated(property_a) def property_b(self): return "b" @deprecated(property_a) def func_a(self): return "a" with warnings.catch_warnings(record=True) as w: # Trigger a warning. assert TestClass().property_b == "b" # Verify warning type assert issubclass(w[-1].category, FutureWarning) with warnings.catch_warnings(record=True) as w: # Trigger a warning. assert TestClass().func_a() == "a" # Verify some things assert issubclass(w[-1].category, FutureWarning) def test_classmethod(self): class TestClass: """A dummy class for tests.""" @classmethod def classmethod_a(cls): pass @classmethod @deprecated(classmethod_a) def classmethod_b(cls): return "b" with warnings.catch_warnings(record=True) as w: # Trigger a warning. assert TestClass().classmethod_b() == "b" # Verify some things assert issubclass(w[-1].category, FutureWarning) class TestClass_deprecationwarning: """A dummy class for tests.""" @classmethod def classmethod_a(cls): pass @classmethod @deprecated(classmethod_a, category=DeprecationWarning) def classmethod_b(cls): return "b" with pytest.warns(DeprecationWarning): assert TestClass_deprecationwarning().classmethod_b() == "b" def test_class(self): class TestClassNew: """A dummy class for tests.""" def method_a(self): pass @deprecated(replacement=TestClassNew) class TestClassOld: """A dummy old class for tests.""" class_attrib_old = "OLD_ATTRIB" def method_b(self): """This is method_b.""" with pytest.warns(FutureWarning, match="TestClassOld is deprecated"): old_class = TestClassOld() # Check metadata preservation assert old_class.__doc__ == "A dummy old class for tests." assert old_class.class_attrib_old == "OLD_ATTRIB" assert old_class.__module__ == __name__ assert old_class.method_b.__doc__ == "This is method_b." def test_dataclass(self): @dataclass class TestClassNew: """A dummy class for tests.""" def __post_init__(self): pass def method_a(self): pass @deprecated(replacement=TestClassNew) @dataclass class TestClassOld: """A dummy old class for tests.""" class_attrib_old = "OLD_ATTRIB" def __post_init__(self): pass def method_b(self): """This is method_b.""" with pytest.warns(FutureWarning, match="TestClassOld is deprecated"): old_class = TestClassOld() # Check metadata preservation assert old_class.__doc__ == "A dummy old class for tests." assert old_class.class_attrib_old == "OLD_ATTRIB" def test_requires(): try: import fictitious_mod except ImportError: fictitious_mod = None err_msg = "fictitious_mod is not present." @requires(fictitious_mod is not None, err_msg) def use_fictitious_mod(): pass with pytest.raises(RuntimeError, match=err_msg): use_fictitious_mod() @requires(unittest is not None, "unittest is not present.") def use_unittest(): return "success" assert use_unittest() == "success" # test with custom error class @requires(False, "expect ImportError", err_cls=ImportError) def use_import_error(): return "success" with pytest.raises(ImportError, match="expect ImportError"): use_import_error() @pytest.mark.skipif(ultratb is None, reason="ipython is not installed") def test_install_except_hook(): install_excepthook() monty-2026.10.21/tests/test_files/000077500000000000000000000000001526577750300165775ustar00rootroot00000000000000monty-2026.10.21/tests/test_files/3000_lines.txt000066400000000000000000000331051526577750300211160ustar00rootroot000000000000001 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 monty-2026.10.21/tests/test_files/3000_lines.txt.bz2000066400000000000000000000067511526577750300216210ustar00rootroot00000000000000BZh91AY&SYVÚã8 È@à`¼¾€j05R¨ÿõT÷½UA@Ð hSò'�Õ*‚� f©ÿú©FýTÿ*¨ï½ýú;Ú¼oö ÉC |�ðt ÈÇ r1wd�ðxÁÐ(H -Ä€ÄY (tƒÀð>�B@YàNd€¡Ð>Àø: dc€Îd€¡Ð>Àø: dc€œƒd€¡Ð>Àø: dc€\ @’‡@ø<àè$�Žàb,�:Áàx@¡ ,€ p‡cd€¡Ð>Àø: dc€b,�:Áàx@¡ ,€ p·ä€ÄY (tƒÀð>�B@YàŽ@ ÉC |�ðt ÈÇ q 1N�»»Ð>Àø: dc€8t @’‡@ø<àè$�Ž8< @’‡@ø<àè$�Žp> @’‡@ø<àè$�Žp1H àð<ƒ P�@8K€Yˆ²@Pè�à|„€²1ÀŒ@’‡@ø<àè$�Žpˆ²@Pè�à|„€²1ÀŸŽ�ˆ²@Pè�à|„€²1Àç�ˆ²@Pè�à|„€²1ÀÎÁˆ²@Pè�à|„€²1À®† ÉC |�ðt ÈÇ p 1H àð<ƒ P�@8C€1ˆ²@Pè�à|„€²1ÀŽ1H àð<ƒ P�@8gìÌÌÌÆ#€ @’‡@ø<àè$�Ž,ä€b,�:Áàx@¡ ,€ Y (tƒÀð>�B@Y〠@ ªªª¬Èˆˆˆˆˆˆˆˆ„òzªªª³"""""""""ÉĪªª¬Èˆˆˆˆˆˆˆˆ„ò@1*ªª«2""""""""!<� @ ªªªÌˆˆˆˆˆˆˆˆˆO$ªªª³"""""""""ÉĪªª¬Èˆˆˆˆˆˆˆˆ„ò@1*ªª«2""""""""!<� @ ªªªÌˆˆˆˆˆˆˆˆˆO$ªªª³"""""""""! 0ˆpˆ²@Pè�à|„€¿íØÝÝÝÝÇ,ž1H àð<ƒ P�b,�:Áàx@¡ -»ÍÝÝÝ·ï_{Þ÷½ÝÝÝÛÞd�VAYdðsžsÁÎx9Ïœñ¿�Ûm¶×Ëo½ïwwwv÷’ i´ƒZA­ Ö�kH5¤Ò i ñ÷Ûm¶Û÷½ï{»»»¿oR i´ƒZA­ Ö�kH5¤Ò i ñöÿ¶Ûm±½ï{ÞîîîïÛÔƒZA­ Ö�kH5¤Ò i´ƒZC|}·ÿ¶Ûlmï{ÞîîîïÛÔƒZA­ Ö�kH5¤Ò i´ƒZC|}¶í¶Ûo{ÞîîîïÛÔƒZA­ Ö�kH5¤Ò i´ƒZC|}¶ßͶØÛo{ÝÝÝÝûz�kH5¤Ò i´ƒZA­ Ö�kHo�¶Û~Ûlm¶÷»»»»öõ Ö�kH5¤Ò i´ƒZA­ Ö�ßm¶ÞÛcm¶÷www~Þ¤Ò i´ƒZA­ Ö�kH5¤Òãí¶Ûm±¶Ûnîîîý½H5¤Ò i´ƒZA­ Ö�kH5¤.ùvÛmü÷¯½àc€1€ $�ðxÁÐ(H ,—€ $�ðxÁÐ+wwy»»º1H àð<ƒ QÀîówvÛ»»»¿{ÔƒZA­ Ö�kH5¤Ò i´ƒZC|}¶Ûo{cm¶ÝÝÝÝïz�kH5¤Ò i´ƒZA­ Ö�kH]óvÛmïÞÛm¶îîîï~õ Ö�«!VAYdœðsžsÁÎy»ßí¶Û_×˶Ûiï¾÷w½éd�VAYd�VO9àç<ÝïöÛm¯ëå»m´žûï¾ÛyÏ9àç<烜ðsžsÁÎx9Ï9æï¶Ûm_-»m¤žûï¶ÞsÁÎx9Ï9àç<烜ðsžsÁÎy»ßí¶Û_×ËmÛi$÷ßm¼çƒœðsžsÁÎx9Ï9àç<烜ów¿Ûm¶¿¯–ÛvÒI=öÛÎx9Ï9àç<烜ðsžsÁÎx9Ï7{ý¶Ûkúùm¶í$’{mç<烜ðsžsÁÎx9Ï9àç<盽þÛmµý|¶Ûn’I%·œðsžsÁÎx9Ï9àç<烜ð~ýÍïw»»»´$�Žˆb,�:Áàx@¡ ,€ p $àd€¡Ð>Àø8îîï7wt1H àð<„c€6îîîÇ&fffffd Þÿm¶Úþ¾[m·I$’Ú7{ý¶Ûkúùm¶Ý$’KhÝîm¶Ö[ým¶Í$’[øn÷6Ûk-þ¶Ûf’I-ü7{›mµ–ÿ[m³I$–þ½Í¶ÚË­¶Ù¤’K ÞæÛme¿ÖÛlÒI%¿€ïsm¶²ßëm¶i$’ßÀw¹¶ÛYoõ¶Û4’Ioà3;Þîûww~�B@Yà1À ÉC |�ðt ÈÇdŽ1H àð îîîówt€ $�ðx$�íÝÝÙ“333332ïsm¶²ßëm¶i$’ßÀw¹¶ÛYoõ¶Û4’Ioà»ÜÛm¬·úÛmšI$·ðÝîÝÛm}¶­¶É¤’[ïvîÛkíµm¶M$’Ø7{·vÛ_m«m²i$–À»Ý»¶Úûm[m“I$¶ Þíݶ×ÛjÛlšI%°n÷ní¶¾ÛVÛdÒI-€&fw½Ýß·w|àè$�Ž b,�:Áàx@¡ ,€ p,�àd€¡Ð$�Žîîîï7t @’‡AÐ(H.öîîË™™™™™™�7{·vÛ_m«m²i$–À»Ý»¶Úûm[m“I$¶ Þíݶ×ÛjÛlšI%°n÷ní¶¾ÛVÛdÒI-€w»o›m~Ûom¶I¤’ß@ïvß6Úý¶ÞÛl“I%¾€ Þí¾mµûm½¶Ù&’K}½Û|ÛköÛ{m²M$–ú7{¶ù¶×í¶öÛdšI-ôÌÎ÷»»µ»½àð<ƒ P�@81pˆ²@Pè�à|„€²1Ádƒ€ @’ P�@87wwww› 1HÁл½»»*ffffff@ÝîÛæÛ_¶ÛÛm’i$·Ð»Ý·Í¶¿m·¶Û$ÒIo w»o›m~Ûom¶I¤’ß@ïvß6Úý¶ÞÛl“I%¾€ Þí¾mµûm½¶Ù&’K}½Ûo»kòÛoËl’i%¿@ïvÛîÚü¶ÛòÛ$šIoлݶû¶¿-¶ü¶É&’[ôn÷m¾í¯Ëm¿-²I¤–ý33½îîîÞ쀡Ð>Àø: dc† € $�ðxÁÐ(H ,�8Äx@¡ ,€ pÝÝÝÝÝæ€b|…ÝÞÝÙôÌÌÌÌÌÌ€»Ý¶û¶¿-¶ü¶É&’[ôn÷m¾í¯Ëm¿-²I¤–ý½Ûo»kòÛoËl’i%¿@ïvÛîÚü¶ÛòÛ$šIoлݶû¶¿-¶ü¶É&’[ôn÷m¾í¯Ëm¿-²I¤–ý½Ûmî×¶ÛoÛd’i-ø7{¶Ûݯm¶ß¶É$Ò[ðn÷m·»^Ûm¿m’I¤·à ™�ïwwws`ÉC |�ðt ÈÇ€1H àð<ƒ P�@8²@pðxÁÐ(H nîîîîï(t‹»»Û³Ó333332ïvÛ{µí¶ÛöÙ$šK~ Þí¶÷kÛm·í²I4–ü½Ûmî×¶ÛoÛd’i-ø7{¶Ûݯm¶ß¶É$Ò[ðn÷m·»^Ûm¿m’I¤·àÝîÛov½¶Û~Û$“IoÀ»Ý¶Þí{m¶ý¶I&’߀w»m´Õm¶ßl’I¥½½Ûm¦«m¶ûd’M-è ™žw›ïnîîâ,�:Áàx@¡ ,€ p·d€¡Ð>Àø: dc€8tƒÀð>�B@Yà™™™™–H ]ÝÝí�™™™™™™�7{¶ÛMVÛmöÉ$š[лݶÚj¶Ûo¶I$ÒÞ€ Þí¶ÓU¶Û}²I&–ôn÷m¶š­¶Ûí’I4· w»m´Õm¶ßl’I¥½½Ûm¦«m¶ûd’M-èÝîÛm5[m·Û$’io@ïvÛiªÛm¾Ù$“Kz<îùóm¶–­¶Ûí’I?~Àñw$S… m®3€monty-2026.10.21/tests/test_files/3000_lines.txt.bz2.gz000066400000000000000000000034621526577750300222340ustar00rootroot00000000000000‹Ì}gÿ3000_lines.txt.bz2µV{LSW?—Ò6C„ncÎ Ôº\Ô91>PÀt¤nÉÂ#š©K°K0™‡’AZgy™{³KÒ t¶)JØ@Î�©¥IaC„ãímæs3m™L*2dçÞ‚B¹‹f�ïh¾û;ßûõâöÝI«7¦/Ù’~eaX,P×¥½¦Ô½cÑ)pŸÚ¬`¾fX¥¡( ™ö<±îµ#··úÛ6*ô=ÚÝÏ(·ÜZúYßòýª²º¬£w�¾<¾ubùŸÓYìê»\ú=˜—¶@áÒE–×m®œ§W%‚�•TEO´]»¬0²¼}(9¢ìE}:˜ï¦òh•6¤‹z©®h¡ºl¨0ì‰�NðË¿1ß:‡VF” í]¨>ݳ,eŽV’ó÷ʱuî"9ö÷²7ÁŠÊ¨ êÓÔúÃÚÖð|ðhÑP™ÖÃ=É‘Šö;”�Q™`§54Q!'#Ñ­�+�²V‡¿ V˸nø€ªÍ…sy×LÙÏ�©“³oô´[Ž=\6$Ǿi=L„ë7ßX¤.s-y×Ú V·‡¼Ò­W²!ïëïè"îQ´²’úhÜár2.[ÃeÀQʱ%êäØ ó“åØ ò£äB’jM—³:†úXFFL>%V$UWWÙ!ûMy¨r¶1%7‚$kyCñµ±ú v“¾@ÒÐÐÐòì=Ù:áïœU¼{Kx¸f ³XGÔ…P÷¦b­ø¿-~\»Šª˜å7§!¡J×�àw€ôéMg{Çn·£ñ›>‹ËO~Ù-Ýû›Ã:Ÿ×¯�(8}~oÒ�ê$÷pm°¢ÁQèwx ¹nmlÔ^¨ÌIYWÿLïÜlÕ‰òí·%�A„wºüŸ™�ç7y�0‚!Jpø,<¡±}Aé…ñ34APŸ< Äuð!<Šp4לÆ×f| Àçþ>‚�Drù‰Õ%®`"*ú²aœ ‘‹xïÃ?‰Ñ/#âØz ‰5wt–Õ‰ÂJ �µ·ý§ÂóUZ™I²CÉqó¼¾³ùåÃ%ð®o¿¿ùBÉ&$î‘Ú,ŸªáP0)Â5Yé®$XÂVÛ„¶0´ížl‡M¨ ij©;$ãy ‹Q#êªg @ €É‹s<­¥ÑìEIgÂðlΦmí¢ÿ¼ ŽA¬")–bèáQ?Þƒsk˜Øïí>Of߈×7mgtÈfYÉÆLf9TBñR–˳—4±ÒÅókEZóF‡a†ÔÏnHÞãk8ƒL#ÈfÓ\�$„;‡œ�C˜îeŒubØ�a 6BÄÔ³‚TW&aýà8ráÜ*&–Üu ºšŒ;gžq±¨´rËŠÊÀv™B‰+`¸PÌ»8£ž6sæ]¯JÝ)&«çŒ` lN£mw%ŸÑ(ê÷ œYÃÄýñ/|‚~Xb€£�M£¹ÉWÅ8ÆK ™ULܤ.ÁÔ ¶º7µÄ*”ã[G!w1ñ¬@-É2;xóÁWO�;í°j0ßú ÿÑâŠ<Õ®»ÀnÇöäj‰*I÷æ„(È1HfêX.›ë 4¶´’q22@פ–j ùs0ä<ÍL¼�´µv­´½sgµñe Õ.sÀÎK‰Óƒñ‰Xí¼›œM¿›ÍÓ¾M��&Â%˜®bŒ�ºF.�¢qÄ,aë?4X¬&èíGd=g²ÙqwÁÁ|Dê¢{ C�jB5�{X&ž› ͉>‚Èe™¯’×燋=<I攜÷‹^îþ6èê—Ú¹‹J%Û´¥åAsãì ÛèªÔ}“¦¥½ŽáH]cÔ0ÜCŒG Ýë ¤ý´ áâff‰í�G0]òÿ›c�e²iq“Õ× ‡i6ÛHúZý•� QoŸ$t©�ÌÅ™{+¯|˜xq§.ê•¿g—wå monty-2026.10.21/tests/test_files/3000_lines.txt.gz000066400000000000000000000145411526577750300215400ustar00rootroot00000000000000‹ï®Þf3000_lines.txt%ÛIbã°Ñ=Oà pï1e”öÐn‹õXÎÁ±Žë¸�çx�}|GÎ#9‘uä:ry޼Gö‘ïà<Èëà:¸žƒ÷`|Ç:�•cõ?rë:Ö}¬çXï±ö±¾ã:�+ÇÅqõ¿ñ:®û¸žãz�k×wÜçqç¸9îuÜýt÷sÜïqïãþŽç<ždzŽç:žþï}Žç=ž}<ßñžÇ›ãåx×ñ^Ç{oÿï¼Ç»�÷;öyì›c¯c_Ǿ�ý»ÿo÷±¿ã;�/ÇÇñ­ã»Žï>¾çøÞãëex½Ž³÷qöBÎÞÈÙ+9{'g/åì­œ½–³çæÚz΋óæ¼:ïÎËóö¼¾Þ_z�Áûí¹Þaz‰é-¦×˜Þcz‘éM¦W™Þe–!z®×™Þgz¡é�¦WšÞiz©é­¦×šËb=×›M¯6½ÛôrÓÛM¯7½ßô‚ÓÎmÚžë%§·œ^szÏéE§7�^uz×éeçñg çzßé…§7ž^yzç饧·ž^{zïyýaé¹^}z÷éå§·Ÿ^zÿi€´@š ÛŸªžk…4CÚ! ‘–HS¤-Òi�|þøùó×Àö =hÚƒö =hÚƒö þ ö\{дíA{дþ<û=?Ñ=çÏ´?ÔþTûcíϵ?ØíA{Ð,ô{®=hÚƒö =hÚƒö =¸ü7ÒsíA{дíA{дíÁí?¦žkÚƒö =hÚƒö =hÿÕõ\{дíA{дíA{ðúϳçÚƒö =hÚƒö =hÚƒí¿ãžkÚƒö =hÚƒö =h>ÿÁû/¾ÿäÛcµÇj�Õ«=V{¬öXí±ÚcÅ_ =׫=V{¬öXí±ÚcµÇj�Õ ‡ô\{¬öXí±ÚcµÇj�åoÕø»f~Ùôœ¿nü}ã/ãø+§=V{¬öXí±.+õ\{¬öXí±ÚcµÇj�Õ«=V{¬Û__=׫=V{¬öXí±ÚcµÇj�Õëñ÷\ϵÇj�Õ«=V{¬öXí±ÚcµÇzý…Øsí±ÚcµÇj�Õ«=V{¬öXí±¶¿9{®=V{¬öXí±ÚcµÇj�Õ«=Öç¯XÇö—l{\íqµÇÕW{\íqµÇÕW{\ñ—qϵÇÕW{\íqµÇÕW{\íqµÇ…¿µ{®=®ö¸Úãj�«=®ö¸Úãj�«=®å¯÷žk�«=®ö¸Úãj�Ëï¿üðk`¾zÎo¿ ü.ðË =®ö¸Úãj�«=®Û/Œžk�«=®ö¸Úãj�«=®ö¸Úãj�ëñ›¥çÚãj�«=®ö¸Úãj�«=®ö¸Úãzý ê¹ö¸Úãj�«=®ö¸Úãj�«=®ö¸¶ßU=×W{\íqµÇÕW{\íqµÇÕ×ç—šßjýZk�»=îö¸Ûãn�»=îö¸Ûãn�;~ýõ\{Üíq·ÇÝw{Üíq·ÇÝw{Üø=Ùsíq·ÇÝw{Üíq·ÇÝw{Üíq/¿P{®=îö¸Ûãn�»=îö¸Ûãn�»=îËoÞžk�»=îö¸ÛãöÛÙ¯g¿Ÿý‚öz¾¢{Î/i¿¥ýšn�»=îö¸Ûãn�»=îÇïòžk�»=îö¸Ûãn�»=îö¸Ûãn�ûõK¿çÚãn�»=îö¸Ûãn�»=îö¸ÛãÞ>ô\{Üíq·ÇÝw{Üíq·ÇÝw{ÜŸ�>GôA¢=žöxÚãi�§=žöxÚãi�§=žøÀÑsíñ´ÇÓO{<íñ´ÇÓO{<íñà“IϵÇÓO{<íñ´ÇÓO{<íñ´Ç³|„é¹öxÚãi�§=žöxÚãi�§=žöx.Ÿuz®=žöxÚãi�§=žöxÚãi�§=žÛ‡¢žk�§=žöx|nòÁÉ''�|vòáižžzÎç' Úãi�§=žöxÚãi�§=ž×Ǭžk�§=žöxÚãi�§=žöxÚãi�gû<Ösíñ´ÇÓO{<íñ´ÇÓO{<íñ|>¸ùäÖG·öxÛãm�·=ÞöxÛãm�·=Þöxã#^ϵÇÛo{¼íñ¶ÇÛo{¼íñ¶Ç‹Ï‚=×o{¼íñ¶ÇÛo{¼íñ¶ÇÛïò¡±çÚãm�·=ÞöxÛãm�·=ÞöxÛã½|ºì¹öxÛãm�·=ÞöxÛãm�·=ÞöxoC{®=ÞöxÛãm�·=ÞöxÛãm�·=ÞÇçÕžk�·=^Ÿh}¤õ™Ö‡ZŸj}¬õ¹vl{ÎGÛöxÛãm�·=ÞöxÛãm�·=ÞípϵÇÛo{¼íñ¶ÇÛo{¼íñ¶Çûù¨ì³r–Ûc·Çn�Ý»=v{ìöØí±ÛcLJêžk�Ý»=v{ìöØí±Ûc·Çn��Oß=×»=v{ìöØí±Ûc·Çn�Ý{ù˜Þsí±Ûc·Çn�Ý»=v{ìöØí±/Ÿç{®=v{ìöØí±Ûc·Çn�Ý»=öíƒϵÇn�Ý»=v{ìöØí±Ûc·Ç~œz®=v{ìöØí±Ûc·Çn�Ý»=öë(Ñsí±�56œ67œ78œ89fæè¹öØí±Ûc·Çn�Ý»=v{ìö؟ÉÓIÇ“öøÚãk�¯=¾öøÚãk�¯=¾öøâÓsíñµÇ×_{|íñµÇ×_{|íñá¼ÓsíñµÇ×_{|íñµÇ×_{|íñ-£žk�¯=¾öøÚãk�¯=¾öøÚãk�ïr‚ê¹öøÚãk�¯=¾öøÚãk�¯=¾öønG­žk�¯=¾öøÚãk�¯=¾öøÚãk�ïq&ë¹öøÚãk�¯=¾öøÚãk�¯=¾öø^‡·žk�¯=¾öøÚãk�¯=¾öøÚãk�o;åõœS c s ƒ “ £ ³ Ã ÓàŒƒ3:ÎD8#áÌ„3ÎT8cáÌ…3:ž™ÒO8žN‡§ãáé|x: žNˆ§#âéŒx:$žÌÔé'œOÅÓIñtT<�O‡ÅÓiñt\<�Ï5ƒªŸpd<�O‡ÆÓ©ñtl<�OÇÓÉñtt<¯™mý„Óãéøx:?ž�§äéy:Cž‘§SäyÏ8ì'$O'ÉÓQòt–<&O§ÉÓqòtž<(Ïg&h?áLy:TžN•§cåé\y:XžN–§£åély¾3tû ÇËÓùòtÀ<�0OGÌÓótÈ<�2OÇÌsÏœî'œ4OGÍÓYótØ<�6OÇÍÓyótà<�8ÏoFû™íîm> 000000ð×€?ø‰��!�1�A�Q�a› Œ Œ Œ Œ Œ Œ Œ Œ Œ Œ Œ Œ Œ Œ Œ Œ Œ Œ Œ Œ Œ !Œ! "Œ" #Œ# $Œ$ %Œ% &Œ& 'Œ' (Œ( )Œ) *Œ* +Œ+ ,Œ, -Œ- .Œ. /Œ/ 0Œ0 1Œ1 2Œ2 3è ¢4DjˆÖ±!jCä†è ¢8Drcg6W";Dwˆðå!ÒC  úk�Ÿ²¹ "BD”ˆHÑ""FD�ˆ="‚D‰HÑ$"JD•ˆ,]"ÂD”‰HÑ&"ND�ˆ<}"EŠHÑ("RD¥ˆL�"BE”ŠHÑ*"VD­ˆ\½"‚E‹HÑ,"ZDµˆlÝ"ÂE”‹HÑ."^D½ˆ|ý"FŒHÑ0"bDňŒ#BF”ŒHÑ2"fD͈œ=#‚F�HÑ4"jDÕˆ¬]#kÄÔæÒF´�ˆQ7"oD߈À…#G4ŽˆQ9"sDçˆÐ‘588øÇ@?188 8"8$hsÑ#ªGd�è>¢|Dúˆöñ#êGä�è@¢€D‰$*Hd�è B¢„D ‰1$jHä�è!D¢ˆD‰&Q$ªHd‘è"F¢ŒD‰6q$êHä‘è#H¢�D"‰F‘$*Id’è$J¢”D*‰V±$jIä’è%L¢˜D2‰fÑ$ªId“è&N¢œD:‰vñ$×8¹Íõ“(QP"¡DC‰ˆ%2Jt”)QR"¥DK‰˜5%rJô”*QT"©DS‰¨U%²J®qà�à‘à¡à¿û‰Ñàáàñàa›K,ÑX"²De‰Ì�%BK”–H-ÑZ"¶Dm‰Ü½%‚K—H.Ñ\"ºDu‰ìÝ%ÂK”—H/Ñ^"¾D}‰üý%L˜H0Ñ`"ÂD…‰ &BL”˜H1Ñb"ÆD�‰=&‚L™H2Ñd"ÊD•‰,]&ÂL”™H3Ñf"ÎD�‰<}&MšÜóvÄæ"MTšÈ4Ñi"ÔD©‰T­&bMÔšÈ5Ñk"ØD±‰dÍ&¢MT›È6Ñm"ÜD¹‰tí&âMÔ›È7Ño"àDÁ‰„ '"Nîy 0¯æ=À¼˜7ÿW~b^ÌÛ€y`sA'ŠN$�h:u¢êDÖ‰®a'ÊN¤�h;w¢îDÞ‰¾�' O$žh<y¢òDæ‰Î¡'JO¤žh={¢öDî‰ÞÁ'ŠO$Ÿh>}¢úDö‰îá'ÊO¤Ÿh?¢þDþ‰þ( P$ h@�¢EÊ3ïÄl®E Š1(jPä èA„¢EŠ&Q(ªPd¡èB†¢ EŠ6q(êPä¡èCˆ¢E"ŠF‘(*Qd¢èDŠ¢E*ŠV±(jQä¢èEŒ¢E2Ê3ï€æ%мš×@óh^ýßù‰y4/ƒl.E?Š€)R4¤ˆHQ‘"#EGŠ�%)RR´¤ˆIQ“"'EOŠ E)’R4¥ˆJQ•"+EWаe)ÒR´¥ˆKQ—"/E_ŠÀ…)S4¦ˆLQ™"3EgŠÐ¥)RS´¦¼ó&ÔærSô¦NQœ"9EsŠèÕ)²St§OQž"=E{Šøõ)òSô§PQ "AEƒŠ*2Tt¨QQ¢"EE‹Š5*rTô¨RQ¤"IE“Š(U*²Tt©SQ¦"ME›Š8u*òTô©Tyç ༜w€ópÞÎkÀyøè'æU ÍŪ¨U‘«¢WE°ŠbÉ*šUD«¨V‘­¢[E¸Šré*ÚUÄ«¨W‘¯¢_EÀŠ‚ +VD¬¨X‘±¢cEÈŠ’)+ZVĬ¨Y‘³¢gEÐÊž÷ß6×´"jEÕŠ¬]+ÂV”­H[Ѷ"nEÝŠ¼}+W®H\Ѹ"rEåŠÌ�+BW”®H]Ѻ"vEíŠÜ½+‚W¯H^Ѽ"zEõŠìÝ+ÂW”¯H_Ѿ"~EýŠüý+X°H`ÑÀ"‚E‹ ,BX”°HaÑÂ"†E ‹–=ïçð¼žWÀóx^Ï[ày üì'l.�E‹8u,òXô±dQÈ"‘E#‹H•,2Yt²eQÊ"•E+‹Xµ,rYô²fQÌ"™E3‹hÕ,ßl=Ø\8‹ré,ÚYij¨g‘Ï¢ŸE@‹‚ -ZD´¨h‘Ñ¢£EH‹’)-ZZÄ´¨i‘Ó¢§EP‹¢I-šZDµ¨j‘Õ¢«EX‹²i-ÚZĵ¨k‘×¢¯E`‹Â‰-[D¶¨l‘Ù¢³Eh‹Ò©-Z[͍m‘Û¢·Ep‹âÉ-š[D·¨n‘Ý¢»Ex‹òé-Ú[Ä·|óö^ÿÏûÿY˜ €Y˜€Y˜-€ÿÀì¸0›³ 0»³ 0Û³0û³àF€‡‡‡‡‡‡‡‡Ç9»..èpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpèpd¶@þk ~bAfdVAfd–AfdÖAlžÙpb6Gü„Íu8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8fßg~fãgV~fçg–~fëgÖ~fïgfógVf÷g–fûgÖfÿg€fhV€þ;@³ôßò³4‹@³ 4«@³ 4Ë@6Ÿu Ùš… Ùš• Ù š¥ Ù šµ Ù šÅ Ù šÕ Ù šå Ùšõ Ùš¡Ùš¡Ùš%¡Ùš5¡ÙšE¡ÙšU¡Ùše¡Ùšu¡Ùš…¡Ùš•¡Ùš¥¡Ùšµ¡ÙšÅ¡ÙšÕ¡Ùšå¡Ùšõ¡Ùš¢Ù š¢Ù!š%¢Ù"š5¢Ù#šE¢Ù$šU¢Ù%še¢Ù&šu¢Ù'š…¢Ù(š•"Ž5ÛŒ6×áÐáÐáÐáÐáX³6+`³ö_ó³6{`³6›`³ fsŽkvXm®Ã¡Ã¡Ã¡Ã¡Ã¡Ã¡Ã¡Ã¡Ã¡Ã¡Ã¡Ã¡Ã¡ÃqÍþß,Îà¬þwýÄlÎàìÎ" Íu8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8t8îÙ\¶¹‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡Ç=ÛŸ³þ9ûŸ³: ÿP?1K ³:k 6×áÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáxf_Ýæ::::::::::::::::::::::::::::::::ÏìþÎòïlÿÎúïìÿÎðØOÌð,Û\‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡C‡ã�¿R°¹‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡Ç;›ß³ú=»ß³ü=Ûß³þ=ûßÿp?1+à6×áÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáØó·)6×áÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáÐáØ³÷?‹ÿ³ù?«ÿ³û?Ëÿ³ý?ëÿÿý?asŽoþ"Éæ:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::ßüÕÇüÙÇüÝÇüáÇüåÇüéÇüíÇüñÇüõÇÿÏ?æï?ÎããO-E6monty-2026.10.21/tests/test_files/empty_file.txt000066400000000000000000000000001526577750300214630ustar00rootroot00000000000000monty-2026.10.21/tests/test_files/empty_file.txt.gz000066400000000000000000000000431526577750300221110ustar00rootroot00000000000000‹Ì}gÿempty_file.txtmonty-2026.10.21/tests/test_files/myfile_bz2.bz2000066400000000000000000000000701526577750300212550ustar00rootroot00000000000000BZh91AY&SY¦…c ×€@€� 1LA 2CjM¨¼]ÉáBBšŽ€monty-2026.10.21/tests/test_files/pre_scratch_text.gz000066400000000000000000000000521526577750300224770ustar00rootroot00000000000000‹Ì}gÿpre_scratch_text+/Ê,I_zk}monty-2026.10.21/tests/test_files/real_lzw_file.txt.Z000066400000000000000000000000131526577750300223600ustar00rootroot00000000000000��hʰaóF�monty-2026.10.21/tests/test_files/scratch_text.gz000066400000000000000000000000461526577750300216340ustar00rootroot00000000000000‹Ì}gÿscratch_text+/Ê,I_zk}monty-2026.10.21/tests/test_files/settings_for_test.yaml000066400000000000000000000000541526577750300232270ustar00rootroot00000000000000old_module.old_class : new_module.new_class monty-2026.10.21/tests/test_fnmatch.py000066400000000000000000000002641526577750300174710ustar00rootroot00000000000000from __future__ import annotations from monty.fnmatch import WildCard def test_match(): wc = WildCard("*.pdf") assert wc.match("A.pdf") assert not wc.match("A.pdg") monty-2026.10.21/tests/test_fractions.py000066400000000000000000000004631526577750300200420ustar00rootroot00000000000000from __future__ import annotations import pytest from monty.fractions import gcd, gcd_float, lcm def test_gcd(): assert gcd(7, 14, 63) == 7 def test_lcm(): assert lcm(2, 3, 4) == 12 def test_gcd_float(): vs = [6.2, 12.4, 15.5 + 5e-9] assert gcd_float(vs, 1e-8) == pytest.approx(3.1) monty-2026.10.21/tests/test_functools.py000066400000000000000000000454411526577750300200730ustar00rootroot00000000000000from __future__ import annotations import platform import time import pytest from monty.functools import ( TimeoutError, lazy_property, prof_main, return_if_raise, return_none_if_raise, timeout, ) class TestLazy: def test_evaluate(self): # Lazy attributes should be evaluated when accessed. called = [] class Foo: @lazy_property def foo(self): called.append("foo") return 1 f = Foo() assert f.foo == 1 assert len(called) == 1 def test_evaluate_once(self): # lazy_property attributes should be evaluated only once. called = [] class Foo: @lazy_property def foo(self): called.append("foo") return 1 f = Foo() assert f.foo == 1 assert f.foo == 1 assert f.foo == 1 assert len(called) == 1 def test_private_attribute(self): # It should be possible to create private, name-mangled # lazy_property attributes. called = [] class Foo: @lazy_property def __foo(self): called.append("foo") return 1 def get_foo(self): return self.__foo f = Foo() assert f.get_foo() == 1 assert f.get_foo() == 1 assert f.get_foo() == 1 assert len(called) == 1 def test_reserved_attribute(self): # It should be possible to create reserved lazy_property attributes. called = [] class Foo: @lazy_property def __foo__(self): called.append("foo") return 1 f = Foo() assert f.__foo__ == 1 assert f.__foo__ == 1 assert f.__foo__ == 1 assert len(called) == 1 def test_result_shadows_descriptor(self): # The result of the function call should be stored in # the object __dict__, shadowing the descriptor. called = [] class Foo: @lazy_property def foo(self): called.append("foo") return 1 f = Foo() assert isinstance(Foo.foo, lazy_property) assert f.foo is f.foo assert f.foo is f.__dict__["foo"] # ! assert len(called) == 1 assert f.foo == 1 assert f.foo == 1 assert len(called) == 1 lazy_property.invalidate(f, "foo") assert f.foo == 1 assert len(called) == 2 assert f.foo == 1 assert f.foo == 1 assert len(called) == 2 def test_readonly_object(self): # The descriptor should raise an AttributeError when lazy_property is # used on a read-only object (an object with __slots__). called = [] class Foo: __slots__ = () @lazy_property def foo(self): called.append("foo") return 1 f = Foo() assert len(called) == 0 with pytest.raises( AttributeError, match="'Foo' object has no attribute '__dict__'" ): f.foo # The function was not called assert len(called) == 0 def test_introspection(self): # The lazy_property decorator should support basic introspection. class Foo: def foo(self): """foo func doc""" @lazy_property def bar(self): """bar func doc""" assert Foo.foo.__name__ == "foo" assert Foo.foo.__doc__ == "foo func doc" assert "test_functools" in Foo.foo.__module__ assert Foo.bar.__name__ == "bar" assert Foo.bar.__doc__ == "bar func doc" assert "test_functools" in Foo.bar.__module__ def test_is_cached_property(self): import functools class Foo: @lazy_property def foo(self): return 1 assert isinstance(Foo.foo, functools.cached_property) assert Foo.foo.__qualname__.endswith("Foo.foo") def test_alias_and_late_binding(self): # Binding one descriptor to several names, or setting it on a class # after creation, works and caches under the function name. called = [] def foo(self): called.append("foo") return 1 class Foo: bar = lazy_property(foo) baz = bar Foo.qux = lazy_property(foo) f = Foo() assert f.bar == f.baz == 1 assert f.__dict__ == {"foo": 1} assert len(called) == 1 assert Foo().qux == 1 def test_private_attribute_in_subclass(self): # The value is cached under the defining class's mangled name, so a # subclass instance hits the cache. called = [] class _Foo: @lazy_property def __foo(self): called.append("foo") return 1 def get_foo(self): return self.__foo class Bar(_Foo): pass b = Bar() assert b.get_foo() == b.get_foo() == 1 assert len(called) == 1 assert "_Foo__foo" in b.__dict__ class TestInvalidate: def test_invalidate_attribute(self): # It should be possible to invalidate a lazy_property attribute. called = [] class Foo: @lazy_property def foo(self): called.append("foo") return 1 f = Foo() assert f.foo == 1 assert len(called) == 1 lazy_property.invalidate(f, "foo") assert f.foo == 1 assert len(called) == 2 def test_invalidate_attribute_twice(self): # It should be possible to invalidate a lazy_property attribute # twice without causing harm. called = [] class Foo: @lazy_property def foo(self): called.append("foo") return 1 f = Foo() assert f.foo == 1 assert len(called) == 1 lazy_property.invalidate(f, "foo") lazy_property.invalidate(f, "foo") # Nothing happens assert f.foo == 1 assert len(called) == 2 def test_invalidate_uncalled_attribute(self): # It should be possible to invalidate an empty attribute # cache without causing harm. called = [] class Foo: @lazy_property def foo(self): called.append("foo") return 1 f = Foo() assert len(called) == 0 lazy_property.invalidate(f, "foo") # Nothing happens def test_invalidate_private_attribute(self): # It should be possible to invalidate a private lazy_property attribute. called = [] class Foo: @lazy_property def __foo(self): called.append("foo") return 1 def get_foo(self): return self.__foo f = Foo() assert f.get_foo() == 1 assert len(called) == 1 lazy_property.invalidate(f, "__foo") assert f.get_foo() == 1 assert len(called) == 2 def test_invalidate_mangled_attribute(self): # It should be possible to invalidate a private lazy_property attribute # by its mangled name. called = [] class Foo: @lazy_property def __foo(self): called.append("foo") return 1 def get_foo(self): return self.__foo f = Foo() assert f.get_foo() == 1 assert len(called) == 1 lazy_property.invalidate(f, "_Foo__foo") assert f.get_foo() == 1 assert len(called) == 2 def test_invalidate_reserved_attribute(self): # It should be possible to invalidate a reserved lazy_property attribute. called = [] class Foo: @lazy_property def __foo__(self): called.append("foo") return 1 f = Foo() assert f.__foo__ == 1 assert len(called) == 1 lazy_property.invalidate(f, "__foo__") assert f.__foo__ == 1 assert len(called) == 2 def test_invalidate_nonlazy_attribute(self): # Invalidating an attribute that is not lazy_property should # raise an AttributeError. called = [] class Foo: def foo(self): called.append("foo") return 1 f = Foo() with pytest.raises( AttributeError, match="'Foo.foo' is not a lazy_property attribute" ): lazy_property.invalidate(f, "foo") def test_invalidate_nonlazy_private_attribute(self): # Invalidating a private attribute that is not lazy_property should # raise an AttributeError. called = [] class Foo: def __foo(self): called.append("foo") return 1 f = Foo() with pytest.raises( AttributeError, match="type object 'Foo' has no attribute 'foo'" ): lazy_property.invalidate(f, "foo") def test_invalidate_unknown_attribute(self): # Invalidating an unknown attribute should # raise an AttributeError. called = [] class Foo: @lazy_property def foo(self): called.append("foo") return 1 f = Foo() with pytest.raises( AttributeError, match="type object 'Foo' has no attribute 'bar'" ): lazy_property.invalidate(f, "bar") def test_invalidate_readonly_object(self): # Calling invalidate on a read-only object should # raise an AttributeError. called = [] class Foo: __slots__ = () @lazy_property def foo(self): called.append("foo") return 1 f = Foo() with pytest.raises( AttributeError, match="'Foo' object has no attribute '__dict__'" ): lazy_property.invalidate(f, "foo") # A lazy_property subclass class cached(lazy_property): pass class TestInvalidateSubclass: def test_invalidate_attribute(self): # It should be possible to invalidate a cached attribute. called = [] class Bar: @cached def bar(self): called.append("bar") return 1 b = Bar() assert b.bar == 1 assert len(called) == 1 cached.invalidate(b, "bar") assert b.bar == 1 assert len(called) == 2 def test_invalidate_attribute_twice(self): # It should be possible to invalidate a cached attribute # twice without causing harm. called = [] class Bar: @cached def bar(self): called.append("bar") return 1 b = Bar() assert b.bar == 1 assert len(called) == 1 cached.invalidate(b, "bar") cached.invalidate(b, "bar") # Nothing happens assert b.bar == 1 assert len(called) == 2 def test_invalidate_uncalled_attribute(self): # It should be possible to invalidate an empty attribute # cache without causing harm. called = [] class Bar: @cached def bar(self): called.append("bar") return 1 b = Bar() assert len(called) == 0 cached.invalidate(b, "bar") # Nothing happens def test_invalidate_private_attribute(self): # It should be possible to invalidate a private cached attribute. called = [] class Bar: @cached def __bar(self): called.append("bar") return 1 def get_bar(self): return self.__bar b = Bar() assert b.get_bar() == 1 assert len(called) == 1 cached.invalidate(b, "__bar") assert b.get_bar() == 1 assert len(called) == 2 def test_invalidate_mangled_attribute(self): # It should be possible to invalidate a private cached attribute # by its mangled name. called = [] class Bar: @cached def __bar(self): called.append("bar") return 1 def get_bar(self): return self.__bar b = Bar() assert b.get_bar() == 1 assert len(called) == 1 cached.invalidate(b, "_Bar__bar") assert b.get_bar() == 1 assert len(called) == 2 def test_invalidate_reserved_attribute(self): # It should be possible to invalidate a reserved cached attribute. called = [] class Bar: @cached def __bar__(self): called.append("bar") return 1 b = Bar() assert b.__bar__ == 1 assert len(called) == 1 cached.invalidate(b, "__bar__") assert b.__bar__ == 1 assert len(called) == 2 def test_invalidate_uncached_attribute(self): # Invalidating an attribute that is not cached should # raise an AttributeError. called = [] class Bar: def bar(self): called.append("bar") return 1 b = Bar() with pytest.raises(AttributeError, match="'Bar.bar' is not a cached attribute"): cached.invalidate(b, "bar") def test_invalidate_uncached_private_attribute(self): # Invalidating a private attribute that is not cached should # raise an AttributeError. called = [] class Bar: def __bar(self): called.append("bar") return 1 b = Bar() with pytest.raises( AttributeError, match="'Bar._Bar__bar' is not a cached attribute" ): cached.invalidate( b, "__bar", ) def test_invalidate_unknown_attribute(self): # Invalidating an unknown attribute should # raise an AttributeError. called = [] class Bar: @cached def bar(self): called.append("bar") return 1 b = Bar() with pytest.raises( AttributeError, match="type object 'Bar' has no attribute 'baz'" ): lazy_property.invalidate( b, "baz", ) def test_invalidate_readonly_object(self): # Calling invalidate on a read-only object should # raise an AttributeError. called = [] class Bar: __slots__ = () @cached def bar(self): called.append("bar") return 1 b = Bar() with pytest.raises( AttributeError, match="'Bar' object has no attribute '__dict__'" ): cached.invalidate( b, "bar", ) def test_invalidate_superclass_attribute(self): # cached.invalidate CANNOT invalidate a superclass (lazy_property) attribute. called = [] class Bar: @lazy_property def bar(self): called.append("bar") return 1 b = Bar() with pytest.raises(AttributeError, match="'Bar.bar' is not a cached attribute"): cached.invalidate( b, "bar", ) def test_invalidate_subclass_attribute(self): # Whereas lazy_property.invalidate CAN invalidate a subclass (cached) attribute. called = [] class Bar: @cached def bar(self): called.append("bar") return 1 b = Bar() assert b.bar == 1 assert len(called) == 1 lazy_property.invalidate(b, "bar") assert b.bar == 1 assert len(called) == 2 class TestTryOrReturn: def test_decorator(self): class A: @return_if_raise(ValueError, "hello") def return_one(self): return 1 @return_if_raise(ValueError, "hello") def return_hello(self): raise ValueError @return_if_raise(KeyError, "hello") def reraise_value_error(self): raise ValueError @return_if_raise([KeyError, ValueError], "hello") def catch_exc_list(self): import random if random.randint(0, 1) == 0: raise ValueError raise KeyError @return_none_if_raise(TypeError) def return_none(self): raise TypeError a = A() assert a.return_one() == 1 assert a.return_hello() == "hello" with pytest.raises(ValueError): a.reraise_value_error() assert a.catch_exc_list() == "hello" assert a.return_none() is None @pytest.mark.parametrize("exc", [KeyError, ValueError]) def test_exc_tuple(self, exc): @return_if_raise((KeyError, ValueError), "hello") def func(): raise exc assert func() == "hello" def test_disabled(self): @return_if_raise(ValueError, "hello", disabled=True) def func(): raise ValueError with pytest.raises(ValueError): func() @pytest.mark.parametrize("bad", ["ValueError", 1, None]) def test_invalid_exception_tuple(self, bad): with pytest.raises(TypeError, match="Wrong exception_tuple"): return_if_raise(bad, "hello") class TestTimeout: @pytest.mark.skipif(platform.system() == "Windows", reason="Skip on windows") def test_with(self): try: with timeout(1, "timeout!"): time.sleep(2) raise AssertionError("Did not timeout!") except TimeoutError as ex: assert ex.message == "timeout!" def test_timeout_error_is_builtin(self): import builtins err = TimeoutError("timeout!") assert isinstance(err, builtins.TimeoutError) assert err.message == str(err) == "timeout!" @pytest.mark.skipif(platform.system() == "Windows", reason="Skip on windows") def test_caught_by_builtin(self): import builtins with ( pytest.raises(builtins.TimeoutError, match="timeout!"), timeout(1, "timeout!"), ): time.sleep(2) class TestProfMain: def test_prof_decorator(self): """Testing prof_main decorator.""" import sys @prof_main def main(): return sys.exit(1) # Have to change argv before calling main. # Will restore original values before returning. _ = sys.argv[:] if len(sys.argv) == 1: sys.argv.append("prof") else: sys.argv[1] = "prof" monty-2026.10.21/tests/test_inspect.py000066400000000000000000000007771526577750300175270ustar00rootroot00000000000000from __future__ import annotations from monty.inspect import all_subclasses, caller_name, find_top_pyfile class LittleCatA: pass class LittleCatB(LittleCatA): pass class LittleCatC: pass class LittleCatD(LittleCatB): pass class TestInspect: def test_func(self): # Not a real test. Need something better. assert find_top_pyfile() assert caller_name() def test_all_subclasses(self): assert all_subclasses(LittleCatA) == [LittleCatB, LittleCatD] monty-2026.10.21/tests/test_io.py000066400000000000000000000427451526577750300164720ustar00rootroot00000000000000from __future__ import annotations import bz2 import gzip import os import warnings from pathlib import Path import pytest from monty.io import ( EncodingWarning, FileLock, FileLockException, _get_line_ending, reverse_readfile, reverse_readline, zopen, ) from monty.tempfile import ScratchDir TEST_DIR = os.path.join(os.path.dirname(__file__), "test_files") class TestGetLineEnding: @pytest.mark.parametrize("l_end", ["\n", "\r\n"]) def test_get_line_ending(self, l_end): """Test files with: Unix line ending (\n). Windows line ending (\r\n). For: - Text file: both text mode and binary mode - gzip file and bzip2 file """ test_file = "test_l_end.txt" test_line = f"This is a test{l_end}Second line{l_end}".encode() with ScratchDir("."): with open(test_file, "wb") as f: f.write(test_line) assert _get_line_ending(test_file) == l_end assert _get_line_ending(Path(test_file)) == l_end # Test text mode with open(test_file, encoding="utf-8") as f: start_pos = f.tell() assert _get_line_ending(f) == l_end assert f.tell() == start_pos # Test binary mode with open(test_file, "rb") as f: start_pos = f.tell() assert _get_line_ending(f) == l_end assert f.tell() == start_pos # Test gzip file gzip_filename = f"{test_file}.gz" with gzip.open(gzip_filename, "wb") as f: f.write(test_line) # Opened file stream with gzip.open(gzip_filename, "rb") as f: start_pos = f.tell() assert _get_line_ending(f) == l_end assert f.tell() == start_pos # Filename directly assert _get_line_ending(gzip_filename) == l_end # Test bzip2 file stream bz2_filename = f"{test_file}.bz2" with bz2.open(bz2_filename, "wb") as f: f.write(test_line) # Opened file stream with bz2.open(bz2_filename, "rb") as f: start_pos = f.tell() assert _get_line_ending(f) == l_end assert f.tell() == start_pos # Filename directly assert _get_line_ending(bz2_filename) == l_end @pytest.mark.parametrize("l_end", ["\n", "\r\n"]) def test_miss_last_l_end(self, l_end): """Make sure this still works if the last l_end is missing.""" test_line = f"This is a test{l_end}Second line".encode() test_file = "test_l_end.txt" with ScratchDir("."): with open(test_file, "wb") as f: f.write(test_line) assert _get_line_ending(test_file) == l_end def test_unknown_file_type(self): unknown_file = 123 with pytest.raises(TypeError, match="Unknown file type int"): _get_line_ending(unknown_file) def test_empty_file(self): with ScratchDir("."): test_file = "empty_file.txt" open(test_file, "w").close() with pytest.warns(match="File is empty, return Unix line ending \n"): assert _get_line_ending(test_file) == "\n" def test_unknown_line_ending(self): with ScratchDir("."): test_file = "test_unknown.txt" with open(test_file, "wb") as f: f.write(b"This is a test\036") with pytest.raises(ValueError, match="Unknown line ending"): _get_line_ending(test_file) class TestReverseReadline: """WARNING for future coder: "reverse_readline" has two branches, one is the in-RAM reverse reading for un-supported file types or small files. As the default RAM threshold is "big" at around 4 MB (usually people just write a few lines to test), you could easily be testing/debugging the in-RAM branch all the time (me for example). """ NUMLINES = 3000 def test_reverse_readline(self): """ We are making sure a file containing line numbers is read in reverse order, i.e. the first line that is read corresponds to the last line. number """ # Test text mode with open( os.path.join(TEST_DIR, "3000_lines.txt"), encoding="utf-8", newline="" ) as f: for idx, line in enumerate(reverse_readline(f)): assert isinstance(line, str) assert line == f"{self.NUMLINES - idx!s}{os.linesep}" # Test binary mode with open(os.path.join(TEST_DIR, "3000_lines.txt"), mode="rb") as f: for idx, line in enumerate(reverse_readline(f)): assert line == f"{self.NUMLINES - idx!s}{os.linesep}" @pytest.mark.parametrize("l_end", ["\n", "\r\n"]) def test_big_file(self, l_end): """ Test read big file. A file of 300,000 lines is about 2 MB, but the default max_mem is still around 4 MB, so we have to reduce it. """ file_name = "big_file.txt" num_lines = 300_000 with ScratchDir("."): # Write test file (~ 2 MB) with open(file_name, "wb") as file: for num in range(1, num_lines + 1): file.write(f"{num}{l_end}".encode()) assert os.path.getsize(file_name) > 1_000_000 # 1 MB # Test text mode with open(file_name, encoding="utf-8", newline="") as file: for idx, line in enumerate(reverse_readline(file, max_mem=4096)): assert line == f"{num_lines - idx!s}{l_end}" # Test binary mode with open(file_name, mode="rb") as file: for idx, line in enumerate(reverse_readline(file, max_mem=4096)): assert line == f"{num_lines - idx!s}{l_end}" def test_read_bz2(self): """ Make sure a file containing line numbers is read in reverse order, i.e. the first line that is read corresponds to the last line number. """ lines = [] with zopen(os.path.join(TEST_DIR, "myfile_bz2.bz2"), "rb") as f: for line in reverse_readline(f): lines.append(line) assert lines == ["\n", "HelloWorld.\n"] # test file has one empty line def test_read_empty_file(self): """ Make sure an empty file does not throw an error when reverse_readline is called, which was a problem with an earlier implementation. """ with pytest.warns(match="File is empty, return Unix line ending \n."): with open(os.path.join(TEST_DIR, "empty_file.txt"), encoding="utf-8") as f: for _line in reverse_readline(f): pytest.fail("No error should be thrown.") @pytest.mark.parametrize("ram", [4, 4096, 4_0000_000]) @pytest.mark.parametrize("l_end", ["\n", "\r\n"]) def test_read_file_with_empty_lines(self, l_end, ram): """Empty lines should not be skipped. Using a very small RAM size to force non in-RAM mode. """ contents = (f"line1{l_end}", f"{l_end}", f"line3{l_end}") filename = "test_empty_line.txt" with ScratchDir("."), warnings.catch_warnings(): warnings.filterwarnings( "ignore", message="max_mem=4 smaller than blk_size=4096" ) # Test text file with open(filename, "wb") as file: for line in contents: file.write(line.encode()) with open(filename, newline="") as file: revert_contents = tuple(reverse_readline(file, max_mem=ram)) assert revert_contents[::-1] == contents # Test gzip file gzip_filename = f"{filename}.gz" with gzip.open(gzip_filename, "w") as file_out: for line in contents: file_out.write(line.encode()) with gzip.open(gzip_filename) as g_file: revert_contents_gzip = tuple(reverse_readline(g_file)) assert revert_contents_gzip[::-1] == contents # Test bzip2 file bz2_filename = f"{filename}.bz2" with bz2.open(bz2_filename, "w") as file_out: for line in contents: file_out.write(line.encode()) with bz2.open(bz2_filename) as b_file: revert_contents_bz2 = tuple(reverse_readline(b_file)) assert revert_contents_bz2[::-1] == contents @pytest.mark.parametrize("ram", [4, 4096, 4_0000_000]) @pytest.mark.parametrize("l_end", ["\n", "\r\n"]) def test_different_line_endings(self, l_end, ram): """Using a very small RAM size to force non in-RAM mode.""" contents = (f"Line1{l_end}", f"Line2{l_end}", f"Line3{l_end}") file_name = "test_file.txt" with ScratchDir("."), warnings.catch_warnings(): warnings.filterwarnings( "ignore", message="max_mem=4 smaller than blk_size=4096" ) with open(file_name, "wb") as file: for line in contents: file.write(line.encode()) # Test text mode with open(file_name, encoding="utf-8") as file: for idx, line in enumerate(reverse_readline(file, max_mem=ram)): # OS would automatically change line ending in text mode assert ( line.rstrip(os.linesep) + l_end == contents[len(contents) - idx - 1] ) assert isinstance(line, str) # Test binary mode with open(file_name, "rb") as file: for idx, line in enumerate(reverse_readline(file)): assert line == contents[len(contents) - idx - 1] @pytest.mark.parametrize("file", ["./file", Path("./file")]) def test_illegal_file_type(self, file): with pytest.raises(TypeError, match="expect a file stream, not file name"): next(reverse_readline(file)) class TestReverseReadfile: NUM_LINES = 3000 def test_reverse_readfile(self): """ Make sure a file containing line numbers is read in reverse order, i.e. the first line that is read corresponds to the last line number. """ fname = os.path.join(TEST_DIR, "3000_lines.txt") for idx, line in enumerate(reverse_readfile(fname)): assert isinstance(line, str) # OS would automatically convert line ending in text mode assert line == f"{self.NUM_LINES - idx!s}{os.linesep}" def test_read_gz(self): """ Make sure a file containing line numbers is read in reverse order, i.e. the first line that is read corresponds to the last line number. """ fname = os.path.join(TEST_DIR, "3000_lines.txt.gz") for idx, line in enumerate(reverse_readfile(fname)): assert isinstance(line, str) assert line == f"{self.NUM_LINES - idx!s}\n" def test_read_bz2(self): """ Make sure a file containing line numbers is read in reverse order, i.e. the first line that is read corresponds to the last line number. """ fname = os.path.join(TEST_DIR, "3000_lines.txt.bz2") for idx, line in enumerate(reverse_readfile(fname)): assert isinstance(line, str) assert line == f"{self.NUM_LINES - idx!s}\n" def test_read_empty_file(self): """ Make sure an empty file does not throw an error when reverse_readline is called, which was a problem with an earlier implementation. """ with ( pytest.warns(match="File is empty, return Unix line ending \n."), pytest.warns(match="trying to mmap an empty file"), ): for _line in reverse_readfile(os.path.join(TEST_DIR, "empty_file.txt")): pytest.fail("No error should be thrown.") @pytest.mark.parametrize("l_end", ["\n", "\r\n"]) def test_read_file_with_empty_lines(self, l_end): """Empty lines should not be skipped.""" contents = (f"line1{l_end}", f"{l_end}", f"line3{l_end}") filename = "test_empty_line.txt" with ScratchDir("."): # Test text file with open(filename, "w", newline="", encoding="utf-8") as file: for line in contents: file.write(line) revert_contents = tuple(reverse_readfile(filename)) assert revert_contents[::-1] == contents # Test gzip file gzip_filename = f"{filename}.gz" with gzip.open(gzip_filename, "w") as file_out: for line in contents: file_out.write(line.encode()) revert_contents_gzip = tuple(reverse_readfile(gzip_filename)) assert revert_contents_gzip[::-1] == contents # Test bzip2 file bz2_filename = f"{filename}.bz2" with bz2.open(bz2_filename, "w") as file_out: for line in contents: file_out.write(line.encode()) revert_contents_bz2 = tuple(reverse_readfile(bz2_filename)) assert revert_contents_bz2[::-1] == contents @pytest.mark.parametrize("l_end", ["\n", "\r\n"]) def test_different_line_endings(self, l_end): contents = (f"Line1{l_end}", f"Line2{l_end}", f"Line3{l_end}") filename = "test_file.txt" with ScratchDir("."): with open(filename, "w", newline="", encoding="utf-8") as file: for line in contents: file.write(line) revert_contents = tuple(reverse_readfile(filename)) assert revert_contents[::-1] == contents class TestZopen: @pytest.mark.parametrize("extension", [".txt", ".bz2", ".gz", ".xz", ".lzma"]) def test_read_write_files(self, extension): """Test read/write in binary/text mode: - uncompressed text file: .txt - compressed files: bz2/gz/xz/lzma """ filename = f"test_file{extension}" content = "This is a test file.\n" with ScratchDir("."): # Test write and read in text mode with zopen(filename, mode="wt", encoding="utf-8") as f: f.write(content) with zopen(Path(filename), mode="rt", encoding="utf-8") as f: assert f.read() == content # Test write and read in binary mode with zopen(Path(filename), "wb") as f: f.write(content.encode()) with zopen(filename, "rb") as f: assert f.read() == content.encode() with ( pytest.raises( RuntimeError, match="Implicit text/binary mode is not allow" ), zopen(Path(filename), "w") as f, ): f.write(content.encode()) def test_lzw_files(self): """gzip is not really able to (de)compress LZW files. TODO: remove text file real_lzw_file.txt.Z after dropping ".Z" extension support """ # Test a fake LZW file (just with .Z extension but DEFLATED algorithm) filename = "test.Z" content = "This is not a real LZW compressed file.\n" with ( ScratchDir("."), pytest.warns(FutureWarning, match="compress LZW-compressed files"), ): # Test write and read in text mode with zopen(filename, "wt", encoding="utf-8") as f: f.write(content) with zopen(filename, "rt", encoding="utf-8") as f: assert f.read() == content # Test write and read in binary mode with zopen(filename, "wb") as f: f.write(content.encode()) with zopen(filename, "rb") as f: assert f.read() == content.encode() # Cannot decompress a real LZW file with ( pytest.warns(FutureWarning, match="compress LZW-compressed files"), pytest.raises(gzip.BadGzipFile, match="Not a gzipped file"), zopen(f"{TEST_DIR}/real_lzw_file.txt.Z", "rt", encoding="utf-8") as f, ): f.read() @pytest.mark.parametrize("extension", [".txt", ".bz2", ".gz", ".xz", ".lzma"]) def test_warnings(self, extension, monkeypatch): filename = f"test_warning{extension}" content = "Test warning" with ScratchDir("."): monkeypatch.setenv("PYTHONWARNDEFAULTENCODING", "1") # Default `encoding` warning with ( pytest.warns(EncodingWarning, match="use UTF-8 by default"), zopen(filename, "wt") as f, ): f.write(content) # No encoding warning if `PYTHONWARNDEFAULTENCODING` not set monkeypatch.delenv("PYTHONWARNDEFAULTENCODING") with warnings.catch_warnings(): warnings.filterwarnings( "error", "We strongly encourage explicit `encoding`", EncodingWarning, ) with zopen(filename, "wt") as f: f.write(content) class TestFileLock: def setup_method(self): self.file_name = "__lock__" self.lock = FileLock(self.file_name, timeout=1) self.lock.acquire() def test_raise(self): with pytest.raises(FileLockException): new_lock = FileLock(self.file_name, timeout=1) new_lock.acquire() def teardown_method(self): self.lock.release() monty-2026.10.21/tests/test_itertools.py000066400000000000000000000026701526577750300201000ustar00rootroot00000000000000from __future__ import annotations import pytest from monty.itertools import chunks, ilotri, iterator_from_slice, iuptri def _ref_tri(items, diago, with_inds, upper): items = list(items) for ii, item1 in enumerate(items): jjs = range(ii if diago else ii + 1, len(items)) if upper else range(ii + diago) for jj in jjs: yield ((ii, jj), (item1, items[jj])) if with_inds else (item1, items[jj]) def test_iterator_from_slice(): assert list(iterator_from_slice(slice(0, 6, 2))) == [0, 2, 4] def test_chunks(): assert list(chunks(range(1, 25), 10)) == [ (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), (11, 12, 13, 14, 15, 16, 17, 18, 19, 20), (21, 22, 23, 24), ] @pytest.mark.parametrize("items", [[], ["a"], ["a", "b", "c", "d"]]) @pytest.mark.parametrize("diago", [True, False]) @pytest.mark.parametrize("with_inds", [True, False]) @pytest.mark.parametrize(("func", "upper"), [(iuptri, True), (ilotri, False)]) def test_triangles(items, diago, with_inds, func, upper): expected = list(_ref_tri(items, diago, with_inds, upper)) # Accepts any iterable, not only sequences. assert list(func(iter(items), diago=diago, with_inds=with_inds)) == expected def test_iuptri_order(): assert list(iuptri([0, 1, 2], diago=False)) == [(0, 1), (0, 2), (1, 2)] assert list(iuptri([0, 1], with_inds=True)) == [ ((0, 0), (0, 0)), ((0, 1), (0, 1)), ((1, 1), (1, 1)), ] monty-2026.10.21/tests/test_json.py000066400000000000000000001535121526577750300170270ustar00rootroot00000000000000from __future__ import annotations import dataclasses import datetime import json import os import pathlib from enum import Enum from typing import Union import numpy as np import pytest from monty.json import ( MontyDecoder, MontyEncoder, MSONable, TypeHandler, _check_type, _load_redirect, jsanitize, load, load2dict, partial_monty_encode, register, save, unregister, ) from . import __version__ as TESTS_VERSION try: import pandas as pd except ImportError: pd = None try: import pint except ImportError: pint = None try: import torch except ImportError: torch = None try: import pydantic except ImportError: pydantic = None try: from bson.objectid import ObjectId except ImportError: ObjectId = None try: from bson.dbref import DBRef except ImportError: DBRef = None try: from bson import json_util except ImportError: json_util = None TEST_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test_files") class GoodMSONClass(MSONable): def __init__(self, a, b, c, d=1, *values, **kwargs): self.a = a self.b = b self._c = c self._d = d self.values = values self.kwargs = kwargs def __eq__(self, other): return ( self.a == other.a and self.b == other.b and self._c == other._c and self._d == other._d and self.kwargs == other.kwargs and self.values == other.values ) class GoodNOTMSONClass: """Literally the same as the GoodMSONClass, except it does not have the MSONable inheritance!""" def __init__(self, a, b, c, d=1, *values, **kwargs): self.a = a self.b = b self._c = c self._d = d self.values = values self.kwargs = kwargs def __eq__(self, other): return ( self.a == other.a and self.b == other.b and self._c == other._c and self._d == other._d and self.kwargs == other.kwargs and self.values == other.values ) class LimitedMSONClass(MSONable): """An MSONable class that only accepts a limited number of options""" def __init__(self, a): self.a = a def __eq__(self, other): return self.a == other.a class GoodNestedMSONClass(MSONable): def __init__(self, a_list, b_dict, c_list_dict_list, **kwargs): assert isinstance(a_list, list) assert isinstance(b_dict, dict) assert isinstance(c_list_dict_list, list) assert isinstance(c_list_dict_list[0], dict) first_key = next(iter(c_list_dict_list[0])) assert isinstance(c_list_dict_list[0][first_key], list) self.a_list = a_list self.b_dict = b_dict self._c_list_dict_list = c_list_dict_list self.kwargs = kwargs class MethodSerializationClass(MSONable): def __init__(self, a): self.a = a def method(self): pass @staticmethod def staticmethod(self): pass @classmethod def classmethod(cls): pass def __call__(self, b): # override call for instances return self.__class__(b) class NestedClass: def inner_method(self): pass class MethodNonSerializationClass: def __init__(self, a): self.a = a def method(self): pass def my_callable(a, b): return a + b class EnumNoAsDict(Enum): name_a = "value_a" name_b = "value_b" class EnumAsDict(Enum): name_a = "value_a" name_b = "value_b" def as_dict(self): return {"v": self.value} @classmethod def from_dict(cls, d): return cls(d["v"]) class EnumTest(MSONable, Enum): a = 1 b = 2 class ClassContainingDataFrame(MSONable): def __init__(self, df): self.df = df class ClassContainingSeries(MSONable): def __init__(self, s): self.s = s class ClassContainingQuantity(MSONable): def __init__(self, qty): self.qty = qty class ClassContainingNumpyArray(MSONable): def __init__(self, np_a): self.np_a = np_a @dataclasses.dataclass class Point: x: float = 1 y: float = 2 class Coordinates(MSONable): def __init__(self, points): self.points = points def __str__(self): return str(self.points) @dataclasses.dataclass class NestedDataClass: points: list[Point] class TestMSONable: def setup_method(self): self.good_cls = GoodMSONClass class BadMSONClass(MSONable): def __init__(self, a, b): self.a = a self.b = b def as_dict(self): return {"init": {"a": self.a, "b": self.b}} self.bad_cls = BadMSONClass class BadMSONClass2(MSONable): def __init__(self, a, b): self.a = a self.c = b self.bad_cls2 = BadMSONClass2 class AutoMSON(MSONable): def __init__(self, a, b): self.a = a self.b = b self.auto_mson = AutoMSON class ClassContainingKWOnlyArgs(MSONable): def __init__(self, *, a): self.a = a self.kw_only_args_cls = ClassContainingKWOnlyArgs def test_to_from_dict(self): obj = self.good_cls("Hello", "World", "Python") d = obj.as_dict() assert d is not None self.good_cls.from_dict(d) jsonstr = obj.to_json() d = json.loads(jsonstr) assert d["@class"], "GoodMSONClass" obj = self.bad_cls("Hello", "World") d = obj.as_dict() assert d is not None with pytest.raises(TypeError): self.bad_cls.from_dict(d) obj = self.bad_cls2("Hello", "World") with pytest.raises(NotImplementedError): obj.as_dict() obj = self.auto_mson(2, 3) d = obj.as_dict() self.auto_mson.from_dict(d) def test_kw_only_args(self): obj = self.kw_only_args_cls(a=1) d = obj.as_dict() assert d is not None assert d["a"] == 1 self.kw_only_args_cls.from_dict(d) jsonstr = obj.to_json() d = json.loads(jsonstr) assert d["@class"], "ClassContainingKWOnlyArgs" def test_unsafe_hash(self): GMC = GoodMSONClass a_list = [GMC(1, 1.0, "one"), GMC(2, 2.0, "two")] b_dict = {"first": GMC(3, 3.0, "three"), "second": GMC(4, 4.0, "four")} c_list_dict_list = [ { "list1": [ GMC(5, 5.0, "five"), GMC(6, 6.0, "six"), GMC(7, 7.0, "seven"), ], "list2": [GMC(8, 8.0, "eight")], }, { "list3": [ GMC(9, 9.0, "nine"), GMC(10, 10.0, "ten"), GMC(11, 11.0, "eleven"), GMC(12, 12.0, "twelve"), ], "list4": [GMC(13, 13.0, "thirteen"), GMC(14, 14.0, "fourteen")], "list5": [GMC(15, 15.0, "fifteen")], }, ] obj = GoodNestedMSONClass( a_list=a_list, b_dict=b_dict, c_list_dict_list=c_list_dict_list ) assert ( a_list[0].unsafe_hash().hexdigest() == "ea44de0e2ef627be582282c02c48e94de0d58ec6" ) assert ( obj.unsafe_hash().hexdigest() == "44204c8da394e878f7562c9aa2e37c2177f28b81" ) def test_version(self): obj = self.good_cls("Hello", "World", "Python") d = obj.as_dict() assert d["@version"] == TESTS_VERSION def test_nested_to_from_dict(self): GMC = GoodMSONClass a_list = [GMC(1, 1.0, "one"), GMC(2, 2.0, "two")] b_dict = {"first": GMC(3, 3.0, "three"), "second": GMC(4, 4.0, "four")} c_list_dict_list = [ { "list1": [ GMC(5, 5.0, "five"), GMC(6, 6.0, "six"), GMC(7, 7.0, "seven"), ], "list2": [GMC(8, 8.0, "eight")], }, { "list3": [ GMC(9, 9.0, "nine"), GMC(10, 10.0, "ten"), GMC(11, 11.0, "eleven"), GMC(12, 12.0, "twelve"), ], "list4": [GMC(13, 13.0, "thirteen"), GMC(14, 14.0, "fourteen")], "list5": [GMC(15, 15.0, "fifteen")], }, ] obj = GoodNestedMSONClass( a_list=a_list, b_dict=b_dict, c_list_dict_list=c_list_dict_list ) obj_dict = obj.as_dict() obj2 = GoodNestedMSONClass.from_dict(obj_dict) assert [obj2.a_list[ii] == aa for ii, aa in enumerate(obj.a_list)] assert [obj2.b_dict[kk] == val for kk, val in obj.b_dict.items()] assert len(obj.a_list) == len(obj2.a_list) assert len(obj.b_dict) == len(obj2.b_dict) s = json.dumps(obj_dict) obj3 = json.loads(s, cls=MontyDecoder) assert [obj2.a_list[ii] == aa for ii, aa in enumerate(obj3.a_list)] assert [obj2.b_dict[kk] == val for kk, val in obj3.b_dict.items()] assert len(obj3.a_list) == len(obj2.a_list) assert len(obj3.b_dict) == len(obj2.b_dict) s = json.dumps(obj, cls=MontyEncoder) obj4 = json.loads(s, cls=MontyDecoder) assert [obj4.a_list[ii] == aa for ii, aa in enumerate(obj.a_list)] assert [obj4.b_dict[kk] == val for kk, val in obj.b_dict.items()] assert len(obj.a_list) == len(obj4.a_list) assert len(obj.b_dict) == len(obj4.b_dict) def test_enum_serialization(self): e = EnumTest.a d = e.as_dict() e_new = EnumTest.from_dict(d) assert e_new.name == e.name assert e_new.value == e.value d = {"123": EnumTest.a} f = jsanitize(d) assert f["123"]["@module"] == "tests.test_json" assert f["123"]["@class"] == "EnumTest" assert f["123"]["value"] == 1 f = jsanitize(d, strict=True) assert f["123"]["@module"] == "tests.test_json" assert f["123"]["@class"] == "EnumTest" assert f["123"]["value"] == 1 f = jsanitize(d, strict=True, enum_values=True) assert f["123"] == 1 f = jsanitize(d, enum_values=True) assert f["123"] == 1 def test_enum_serialization_no_msonable(self): d = {"123": EnumNoAsDict.name_a} f = jsanitize(d) assert f["123"]["@module"] == "tests.test_json" assert f["123"]["@class"] == "EnumNoAsDict" assert f["123"]["value"] == "value_a" f = jsanitize(d, strict=True) assert f["123"]["@module"] == "tests.test_json" assert f["123"]["@class"] == "EnumNoAsDict" assert f["123"]["value"] == "value_a" f = jsanitize(d, strict=True, enum_values=True) assert f["123"] == "value_a" f = jsanitize(d, enum_values=True) assert f["123"] == "value_a" def test_save_load(self, tmp_path): """Tests the save and load serialization methods.""" test_good_class = GoodMSONClass( "Hello", "World", "Python", cant_serialize_me=GoodNOTMSONClass( "Hello2", "World2", "Python2", values=[] ), cant_serialize_me2=[ GoodNOTMSONClass("Hello4", "World4", "Python4", values=[]), GoodNOTMSONClass("Hello4", "World4", "Python4", values=[]), ], cant_serialize_me3=[ { "tmp": GoodMSONClass("Hello5", "World5", "Python5", values=[]), "tmp2": 2, "tmp3": [1, 2, 3], }, { "tmp5": GoodNOTMSONClass( "aHello5", "aWorld5", "aPython5", values=[] ), "tmp2": 5, "tmp3": {"test": "test123"}, }, # Gotta check that if I hide an MSONable class somewhere # it still gets correctly serialized. {"actually_good": GoodMSONClass("1", "2", "3", values=[])}, ], values=[], ) # This will pass test_good_class.as_dict() # This will fail with pytest.raises(TypeError): test_good_class.to_json() # This should also pass though target = tmp_path / "test.json" test_good_class.save(target, json_kwargs={"indent": 4, "sort_keys": True}) # This will fail with pytest.raises(FileExistsError): test_good_class.save(target, strict=True) # Now check that reloading this, the classes are equal! test_good_class2 = GoodMSONClass.load(target) # Final check using load test_good_class3 = load(target) assert test_good_class == test_good_class2 assert test_good_class == test_good_class3 class TestJson: def test_as_from_dict(self): obj = GoodMSONClass(1, 2, 3, hello="world") s = json.dumps(obj, cls=MontyEncoder) obj2 = json.loads(s, cls=MontyDecoder) assert obj2.a == 1 assert obj2.b == 2 assert obj2._c == 3 assert obj2._d == 1 assert obj2.kwargs, {"hello": "world", "values": []} obj = GoodMSONClass(obj, 2, 3) s = json.dumps(obj, cls=MontyEncoder) obj2 = json.loads(s, cls=MontyDecoder) assert obj2.a.a == 1 assert obj2.b == 2 assert obj2._c == 3 assert obj2._d == 1 listobj = [obj, obj2] s = json.dumps(listobj, cls=MontyEncoder) listobj2 = json.loads(s, cls=MontyDecoder) assert listobj2[0].a.a == 1 @pytest.mark.skipif(torch is None, reason="torch not present") def test_torch_tensor(self): # Basic tensor t0 = torch.tensor([0, 1, 2]) t0_json_str = json.dumps(t0, cls=MontyEncoder) t0_json_dict = json.loads(t0_json_str) t0_from_json = json.loads(t0_json_str, cls=MontyDecoder) assert isinstance(t0_from_json, torch.Tensor) assert t0_from_json.type() == t0.type() assert t0_json_dict["size"] == list(t0.size()) assert np.array_equal(t0_from_json, t0) # Empty tensor t_empty = torch.empty((0, 2)) t_empty_json_str = json.dumps(t_empty, cls=MontyEncoder) t_empty_json_dict = json.loads(t_empty_json_str) t_empty_from_json = json.loads(t_empty_json_str, cls=MontyDecoder) assert isinstance(t_empty_from_json, torch.Tensor) assert t_empty_from_json.size() == t_empty.size() assert t_empty_json_dict["size"] == list(t_empty.size()) assert np.array_equal(t_empty_from_json.numpy(), t_empty.numpy()) # Complex tensor ct0 = torch.tensor([1 + 1j, 2 + 1j]) ct0_json_str = json.dumps(ct0, cls=MontyEncoder) ct0_json_dict = json.loads(ct0_json_str) ct0_from_json = json.loads(ct0_json_str, cls=MontyDecoder) assert isinstance(ct0_from_json, torch.Tensor) assert ct0_from_json.type() == ct0.type() assert ct0_json_dict["size"] == list(ct0.size()) assert np.allclose(ct0_from_json.numpy(), ct0.numpy()) # Empty complex tensor ct_empty = torch.empty((0, 2), dtype=torch.complex64) ct_empty_json_str = json.dumps(ct_empty, cls=MontyEncoder) ct_empty_json_dict = json.loads(ct_empty_json_str) ct_empty_from_json = json.loads(ct_empty_json_str, cls=MontyDecoder) assert isinstance(ct_empty_from_json, torch.Tensor) assert ct_empty_from_json.size() == ct_empty.size() assert ct_empty_json_dict["size"] == list(ct_empty.size()) assert np.array_equal(ct_empty_from_json.numpy(), ct_empty.numpy()) @pytest.mark.skipif(torch is None, reason="torch not present") def test_torch_tensor_backwards_compatibility(self): # Simulate an old-style JSON (no "size") old_json = json.dumps( { "@module": "torch", "@class": "Tensor", "dtype": "torch.LongTensor", "data": [0, 1, 2], } ) t = json.loads(old_json, cls=MontyDecoder) assert isinstance(t, torch.Tensor) assert t.dtype == torch.long assert t.size() == torch.Size([3]) assert torch.equal(t, torch.tensor([0, 1, 2])) # Test old decoder is compatible with new JSON (with `size`) def old_decoder_simulation(json_obj): if ( json_obj.get("@module") == "torch" and json_obj.get("@class") == "Tensor" ): dtype = json_obj["dtype"] data = json_obj["data"] return torch.tensor(data).type(dtype) else: raise RuntimeError("") # New-style JSON with `size` t = torch.empty((0, 2), dtype=torch.float32) new_json = json.dumps(t, cls=MontyEncoder) json_obj = json.loads(new_json) decoded = old_decoder_simulation(json_obj) assert isinstance(decoded, torch.Tensor) assert list(decoded.size()) == [0] != list(t.size()) def test_datetime(self): dt = datetime.datetime.now() jsonstr = json.dumps(dt, cls=MontyEncoder) d = json.loads(jsonstr, cls=MontyDecoder) assert isinstance(d, datetime.datetime) assert dt == d # Test a nested datetime. a = {"dt": dt, "a": 1} jsonstr = json.dumps(a, cls=MontyEncoder) d = json.loads(jsonstr, cls=MontyDecoder) assert isinstance(d["dt"], datetime.datetime) jsanitize(dt, strict=True) # test timezone aware datetime API. The decoder now preserves the # timezone via ``datetime.fromisoformat`` (the legacy ``strptime`` + # ``split("+")`` path discarded it). created_at = datetime.datetime.now(tz=datetime.UTC) data = json.loads(json.dumps(created_at, cls=MontyEncoder)) created_at_after = MontyDecoder().process_decoded(data) assert created_at_after == created_at assert created_at_after.tzinfo is not None def test_uuid(self): from uuid import UUID, uuid4 uuid = uuid4() jsonstr = json.dumps(uuid, cls=MontyEncoder) d = json.loads(jsonstr, cls=MontyDecoder) assert isinstance(d, UUID) assert uuid == d # Test a nested UUID. a = {"uuid": uuid, "a": 1} jsonstr = json.dumps(a, cls=MontyEncoder) d = json.loads(jsonstr, cls=MontyDecoder) assert isinstance(d["uuid"], UUID) def test_path(self): from pathlib import Path p = Path("/home/user/") jsonstr = json.dumps(p, cls=MontyEncoder) d = json.loads(jsonstr, cls=MontyDecoder) assert isinstance(d, Path) assert d == p def test_nan(self): x = [float("NaN")] djson = json.dumps(x, cls=MontyEncoder) d = json.loads(djson) assert isinstance(d[0], float) def test_numpy(self): x = np.array([1, 2, 3], dtype="int64") with pytest.raises(TypeError): json.dumps(x) djson = json.dumps(x, cls=MontyEncoder) d = json.loads(djson) assert d["@class"] == "array" assert d["@module"] == "numpy" assert d["data"], [1, 2 == 3] assert d["dtype"] == "int64" x = json.loads(djson, cls=MontyDecoder) assert isinstance(x, np.ndarray) x = np.min([1, 2, 3]) > 2 with pytest.raises(TypeError): json.dumps(x) x = np.array([1 + 1j, 2 + 1j, 3 + 1j], dtype="complex64") with pytest.raises(TypeError): json.dumps(x) djson = json.dumps(x, cls=MontyEncoder) d = json.loads(djson) assert d["@class"] == "array" assert d["@module"] == "numpy" assert d["data"], [[1.0, 2.0, 3.0], [1.0, 1.0 == 1.0]] assert d["dtype"] == "complex64" x = json.loads(djson, cls=MontyDecoder) assert isinstance(x, np.ndarray) assert x.dtype == "complex64" x = np.array([[1 + 1j, 2 + 1j], [3 + 1j, 4 + 1j]], dtype="complex64") with pytest.raises(TypeError): json.dumps(x) djson = json.dumps(x, cls=MontyEncoder) d = json.loads(djson) assert d["@class"] == "array" assert d["@module"] == "numpy" assert d["data"], [[[1.0, 2.0], [3.0, 4.0]], [[1.0, 1.0], [1.0 == 1.0]]] assert d["dtype"] == "complex64" x = json.loads(djson, cls=MontyDecoder) assert isinstance(x, np.ndarray) assert x.dtype == "complex64" x = {"energies": [np.float64(1234.5)]} d = jsanitize(x, strict=True) assert isinstance(d["energies"][0], float) x = {"energy": np.array(-1.0)} d = jsanitize(x, strict=True) assert isinstance(d["energy"], float) # Test data nested in a class x = np.array([[1 + 1j, 2 + 1j], [3 + 1j, 4 + 1j]], dtype="complex64") cls = ClassContainingNumpyArray(np_a={"a": [{"b": x}]}) d = json.loads(json.dumps(cls, cls=MontyEncoder)) assert d["np_a"]["a"][0]["b"]["@module"] == "numpy" assert d["np_a"]["a"][0]["b"]["@class"] == "array" assert d["np_a"]["a"][0]["b"]["data"] == [ [[1.0, 2.0], [3.0, 4.0]], [[1.0, 1.0], [1.0, 1.0]], ] assert d["np_a"]["a"][0]["b"]["dtype"] == "complex64" obj = ClassContainingNumpyArray.from_dict(d) assert isinstance(obj, ClassContainingNumpyArray) assert isinstance(obj.np_a["a"][0]["b"], np.ndarray) assert obj.np_a["a"][0]["b"][0][1] == 2 + 1j @pytest.mark.skipif(pd is None, reason="pandas not present") def test_pandas(self): cls = ClassContainingDataFrame( df=pd.DataFrame([{"a": 1, "b": 1}, {"a": 1, "b": 2}]) ) d = json.loads(MontyEncoder().encode(cls)) assert d["df"]["@module"] == "pandas" assert d["df"]["@class"] == "DataFrame" obj = ClassContainingDataFrame.from_dict(d) assert isinstance(obj, ClassContainingDataFrame) assert isinstance(obj.df, pd.DataFrame) assert list(obj.df.a), [1 == 1] cls = ClassContainingSeries(s=pd.Series({"a": [1, 2, 3], "b": [4, 5, 6]})) d = json.loads(MontyEncoder().encode(cls)) assert d["s"]["@module"] == "pandas" assert d["s"]["@class"] == "Series" obj = ClassContainingSeries.from_dict(d) assert isinstance(obj, ClassContainingSeries) assert isinstance(obj.s, pd.Series) assert list(obj.s.a), [1, 2 == 3] cls = ClassContainingSeries( s={"df": [pd.Series({"a": [1, 2, 3], "b": [4, 5, 6]})]} ) d = json.loads(MontyEncoder().encode(cls)) assert d["s"]["df"][0]["@module"] == "pandas" assert d["s"]["df"][0]["@class"] == "Series" obj = ClassContainingSeries.from_dict(d) assert isinstance(obj, ClassContainingSeries) assert isinstance(obj.s["df"][0], pd.Series) assert list(obj.s["df"][0].a), [1, 2 == 3] @pytest.mark.skipif(pint is None, reason="pint not present") def test_pint_quantity(self): ureg = pint.UnitRegistry() cls = ClassContainingQuantity(qty=pint.Quantity("9.81 m/s**2")) d = json.loads(MontyEncoder().encode(cls)) assert isinstance(d, dict) assert d["qty"]["@module"] == "pint" assert d["qty"]["@class"] == "Quantity" assert d["qty"].get("@version") is not None obj = ClassContainingQuantity.from_dict(d) assert isinstance(obj, ClassContainingQuantity) assert isinstance(obj.qty, pint.Quantity) assert obj.qty.magnitude == 9.81 assert str(obj.qty.units) == "meter / second ** 2" def test_callable(self): instance = MethodSerializationClass(a=1) for function in [ # builtins str, list, sum, open, # functions os.path.join, my_callable, # unbound methods MethodSerializationClass.NestedClass.inner_method, MethodSerializationClass.staticmethod, instance.staticmethod, # methods bound to classes MethodSerializationClass.classmethod, instance.classmethod, # classes MethodSerializationClass, Enum, ]: with pytest.raises(TypeError): json.dumps(function) djson = json.dumps(function, cls=MontyEncoder) d = json.loads(djson) assert "@callable" in d assert "@module" in d x = json.loads(djson, cls=MontyDecoder) assert x == function # test method bound to instance for function in [instance.method]: with pytest.raises(TypeError): json.dumps(function) djson = json.dumps(function, cls=MontyEncoder) d = json.loads(djson) assert "@callable" in d assert "@module" in d x = json.loads(djson, cls=MontyDecoder) # can't just check functions are equal as the instance the function is bound # to will be different. Instead, we check that the serialized instance # is the same, and that the function qualname is the same assert x.__qualname__ == function.__qualname__ assert x.__self__.as_dict() == function.__self__.as_dict() # test method bound to object that is not serializable for function in [MethodNonSerializationClass(1).method]: with pytest.raises(TypeError): json.dumps(function, cls=MontyEncoder) # test that callable MSONable objects still get serialized as the objects # rather than as a callable djson = json.dumps(instance, cls=MontyEncoder) assert "@class" in djson @pytest.mark.skipif(ObjectId is None, reason="bson not present") def test_objectid(self): oid = ObjectId("562e8301218dcbbc3d7d91ce") with pytest.raises(TypeError): json.dumps(oid) djson = json.dumps(oid, cls=MontyEncoder) x = json.loads(djson, cls=MontyDecoder) assert isinstance(x, ObjectId) @pytest.mark.skipif(DBRef is None, reason="bson not present") def test_dbref(self): ref = DBRef( "my_collection", ObjectId("562e8301218dcbbc3d7d91ce"), database="my_database", extra_field="extra_value", ) # vanilla json can't serialize DBRef with pytest.raises(TypeError): json.dumps(ref) djson = json.dumps(ref, cls=MontyEncoder) encoded = json.loads(djson) assert encoded["@module"] == "bson.dbref" assert encoded["@class"] == "DBRef" assert encoded["collection"] == "my_collection" assert encoded["database"] == "my_database" assert encoded["extras"] == {"extra_field": "extra_value"} rebuilt = json.loads(djson, cls=MontyDecoder) assert isinstance(rebuilt, DBRef) assert rebuilt.collection == "my_collection" assert rebuilt.database == "my_database" assert rebuilt.extra_field == "extra_value" # Nested ObjectId round-trips through MontyDecoder recursion. assert isinstance(rebuilt.id, ObjectId) assert rebuilt.id == ref.id @pytest.mark.skipif(DBRef is None, reason="bson not present") def test_dbref_no_database(self): # ``database`` is optional on the wire and absent when not set. ref = DBRef("collection", 42) encoded = json.loads(json.dumps(ref, cls=MontyEncoder)) assert "database" not in encoded assert "extras" not in encoded rebuilt = json.loads(json.dumps(ref, cls=MontyEncoder), cls=MontyDecoder) assert isinstance(rebuilt, DBRef) assert rebuilt.database is None assert rebuilt.id == 42 @pytest.mark.skipif(DBRef is None, reason="bson not present") def test_dbref_jsanitize_allow_bson(self): ref = DBRef("collection", 1) # With allow_bson, DBRef passes through unchanged for direct MongoDB insertion. assert jsanitize(ref, allow_bson=True) is ref def test_jsanitize(self): # clean_json should have no effect on None types. d = {"hello": 1, "world": None} clean = jsanitize(d) assert clean["world"] is None assert json.loads(json.dumps(d)) == json.loads(json.dumps(clean)) d = {"hello": GoodMSONClass(1, 2, 3), "test": "hi"} with pytest.raises(TypeError): json.dumps(d) clean = jsanitize(d) assert isinstance(clean["hello"], str) clean_strict = jsanitize(d, strict=True) assert clean_strict["hello"]["a"] == 1 assert clean_strict["hello"]["b"] == 2 assert clean_strict["test"] == "hi" clean_recursive_msonable = jsanitize(d, recursive_msonable=True) assert clean_recursive_msonable["hello"]["a"] == 1 assert clean_recursive_msonable["hello"]["b"] == 2 assert clean_recursive_msonable["hello"]["c"] == 3 assert clean_recursive_msonable["test"] == "hi" d = {"hello": [GoodMSONClass(1, 2, 3), "test"], "test": "hi"} clean_recursive_msonable = jsanitize(d, recursive_msonable=True) assert clean_recursive_msonable["hello"][0]["a"] == 1 assert clean_recursive_msonable["hello"][0]["b"] == 2 assert clean_recursive_msonable["hello"][0]["c"] == 3 assert clean_recursive_msonable["hello"][1] == "test" assert clean_recursive_msonable["test"] == "hi" d = {"hello": (GoodMSONClass(1, 2, 3), "test"), "test": "hi"} clean_recursive_msonable = jsanitize(d, recursive_msonable=True) assert clean_recursive_msonable["hello"][0]["a"] == 1 assert clean_recursive_msonable["hello"][0]["b"] == 2 assert clean_recursive_msonable["hello"][0]["c"] == 3 assert clean_recursive_msonable["hello"][1] == "test" assert clean_recursive_msonable["test"] == "hi" DoubleGoodMSONClass = GoodMSONClass(1, 2, 3) DoubleGoodMSONClass.values = [GoodMSONClass(1, 2, 3)] clean_recursive_msonable = jsanitize( DoubleGoodMSONClass, recursive_msonable=True ) assert clean_recursive_msonable["a"] == 1 assert clean_recursive_msonable["b"] == 2 assert clean_recursive_msonable["c"] == 3 assert clean_recursive_msonable["values"][0]["a"] == 1 assert clean_recursive_msonable["values"][0]["b"] == 2 assert clean_recursive_msonable["values"][0]["c"] == 3 d = {"dt": datetime.datetime.now()} clean = jsanitize(d) assert isinstance(clean["dt"], str) clean = jsanitize(d, allow_bson=True) assert isinstance(clean["dt"], datetime.datetime) rnd_bin = bytes(np.random.rand(10)) d = {"a": bytes(rnd_bin)} clean = jsanitize(d, allow_bson=True) assert clean["a"] == bytes(rnd_bin) assert isinstance(clean["a"], bytes) p = pathlib.Path("/home/user/") clean = jsanitize(p, strict=True) assert clean, ["/home/user" in "\\home\\user"] # test jsanitizing callables (including classes) instance = MethodSerializationClass(a=1) for function in [ # builtins str, list, sum, open, # functions os.path.join, my_callable, # unbound methods MethodSerializationClass.NestedClass.inner_method, MethodSerializationClass.staticmethod, instance.staticmethod, # methods bound to classes MethodSerializationClass.classmethod, instance.classmethod, # classes MethodSerializationClass, Enum, ]: d = {"f": function} clean = jsanitize(d) assert "@module" in clean["f"] assert "@callable" in clean["f"] # test method bound to instance for function in [instance.method]: d = {"f": function} clean = jsanitize(d) assert "@module" in clean["f"] assert "@callable" in clean["f"] assert clean["f"].get("@bound", None) is not None assert "@class" in clean["f"]["@bound"] # test method bound to object that is not serializable for function in [MethodNonSerializationClass(1).method]: d = {"f": function} clean = jsanitize(d) assert isinstance(clean["f"], str) # test that strict checking gives an error with pytest.raises(AttributeError): jsanitize(d, strict=True) # test that callable MSONable objects still get serialized as the objects # rather than as a callable d = {"c": instance} clean = jsanitize(d, strict=True) assert "@class" in clean["c"] def test_unserializable_composite(self): class Unserializable: def __init__(self, a): self._a = a def __str__(self): return "Unserializable" class Composite(MSONable): def __init__(self, name, unserializable, msonable): self.name = name self.unserializable = unserializable self.msonable = msonable composite_dictionary = { "name": "test", "unserializable": Unserializable(1), "msonable": GoodMSONClass(1, 2, 3), } with pytest.raises(AttributeError): jsanitize(composite_dictionary, strict=True) composite_obj = Composite.from_dict(composite_dictionary) with pytest.raises(AttributeError): jsanitize(composite_obj, strict=True) # Test that skip mode preserves unserializable objects skipped_dict = jsanitize(composite_obj, strict="skip", recursive_msonable=True) assert skipped_dict["name"] == "test", "String values should remain unchanged" assert skipped_dict["unserializable"]._a == 1, ( "Unserializable object should be preserved in skip mode" ) assert skipped_dict["msonable"]["a"] == 1, ( "MSONable object should be properly serialized" ) # Test non-strict mode converts unserializable to string dict_with_str = jsanitize(composite_obj, strict=False, recursive_msonable=True) assert isinstance(dict_with_str["unserializable"], str), ( "Unserializable object should be converted to string in non-strict mode" ) @pytest.mark.skipif(pd is None, reason="pandas not present") def test_jsanitize_pandas(self): s = pd.Series({"a": [1, 2, 3], "b": [4, 5, 6]}) clean = jsanitize(s) assert clean == s.to_dict() @pytest.mark.skipif(ObjectId is None, reason="bson not present") def test_jsanitize_numpy_bson(self): d = { "a": ["b", np.array([1, 2, 3])], "b": ObjectId.from_datetime(datetime.datetime.now()), } clean = jsanitize(d) assert clean["a"], ["b", [1, 2 == 3]] assert isinstance(clean["b"], str) def test_redirect(self): MSONable.REDIRECT["tests.test_json"] = { "test_class": {"@class": "GoodMSONClass", "@module": "tests.test_json"}, "another_test_class": { "@class": "AnotherClass", "@module": "tests.test_json2", }, } d = { "@class": "test_class", "@module": "tests.test_json", "a": 1, "b": 1, "c": 1, } obj = json.loads(json.dumps(d), cls=MontyDecoder) assert isinstance(obj, GoodMSONClass) d2 = { "@class": "another_test_class", "@module": "tests.test_json", "a": 2, "b": 2, "c": 2, } with pytest.raises(ImportError, match="No module named 'tests.test_json2'"): # This should raise ImportError because it's trying to load # AnotherClass from tests.test_json instead of tests.test_json2 json.loads(json.dumps(d2), cls=MontyDecoder) def test_missing_optional_module_falls_back_to_dict(self): # A non-redirected class whose module is not importable (e.g. an # optional dependency such as ``emmet`` referenced inside a serialized # ComputedEntry) must fall back to the raw dict rather than crashing # the whole decode. d = { "@module": "some.uninstalled.optional.package", "@class": "SomeClass", "foo": 1, "bar": [1, 2, 3], } obj = json.loads(json.dumps(d), cls=MontyDecoder) assert obj == d def test_redirect_settings_file(self): data = _load_redirect(os.path.join(TEST_DIR, "settings_for_test.yaml")) assert data == { "old_module": { "old_class": {"@class": "new_class", "@module": "new_module"} } } @pytest.mark.skipif(pydantic is None, reason="pydantic not present") def test_pydantic_integrations(self): from pydantic import BaseModel, ValidationError global ModelWithMSONable # allow model to be deserialized in test global LimitedMSONClass class ModelWithMSONable(BaseModel): a: GoodMSONClass test_object = ModelWithMSONable(a=GoodMSONClass(1, 1, 1)) test_dict_object = ModelWithMSONable(a=test_object.a.as_dict()) assert test_dict_object.a.a == test_object.a.a dict_no_class = test_object.a.as_dict() dict_no_class.pop("@class") dict_no_class.pop("@module") test_dict_object = ModelWithMSONable(a=dict_no_class) assert test_dict_object.a.a == test_object.a.a assert test_object.model_json_schema() == { "title": "ModelWithMSONable", "type": "object", "properties": { "a": { "title": "A", "type": "object", "properties": { "@class": {"enum": ["GoodMSONClass"], "type": "string"}, "@module": {"enum": ["tests.test_json"], "type": "string"}, "@version": {"type": "string"}, }, "required": ["@class", "@module"], } }, "required": ["a"], } d = jsanitize(test_object, strict=True, enum_values=True, allow_bson=True) assert d == { "a": { "@module": "tests.test_json", "@class": "GoodMSONClass", "@version": "0.1", "a": 1, "b": 1, "c": 1, "d": 1, "values": [], }, "@module": "tests.test_json", "@class": "ModelWithMSONable", "@version": "0.1", } obj = MontyDecoder().process_decoded(d) assert isinstance(obj, BaseModel) assert isinstance(obj.a, GoodMSONClass) assert obj.a.b == 1 # check that a model that is not validated by pydantic still # gets completely deserialized. global ModelWithDict # allow model to be deserialized in test class ModelWithDict(BaseModel): a: dict test_object_with_dict = ModelWithDict(a={"x": GoodMSONClass(1, 1, 1)}) d = jsanitize( test_object_with_dict, strict=True, enum_values=True, allow_bson=True ) assert d == { "a": { "x": { "@module": "tests.test_json", "@class": "GoodMSONClass", "@version": "0.1", "a": 1, "b": 1, "c": 1, "d": 1, "values": [], } }, "@module": "tests.test_json", "@class": "ModelWithDict", "@version": "0.1", } obj = MontyDecoder().process_decoded(d) assert isinstance(obj, BaseModel) assert isinstance(obj.a["x"], GoodMSONClass) assert obj.a["x"].b == 1 # check that if an MSONable object raises an exception during # the model validation it is properly handled by pydantic global ModelWithUnion # allow model to be deserialized in test global ModelWithLimited # allow model to be deserialized in test class ModelWithLimited(BaseModel): a: LimitedMSONClass class ModelWithUnion(BaseModel): a: LimitedMSONClass | dict limited_dict = jsanitize(ModelWithLimited(a=LimitedMSONClass(1)), strict=True) assert ModelWithLimited.model_validate(limited_dict) limited_dict["a"]["b"] = 2 with pytest.raises(ValidationError): ModelWithLimited.model_validate(limited_dict) limited_union_dict = jsanitize( ModelWithUnion(a=LimitedMSONClass(1)), strict=True ) validated_model = ModelWithUnion.model_validate(limited_union_dict) assert isinstance(validated_model, ModelWithUnion) assert isinstance(validated_model.a, LimitedMSONClass) limited_union_dict["a"]["b"] = 2 validated_model = ModelWithUnion.model_validate(limited_union_dict) assert isinstance(validated_model, ModelWithUnion) assert isinstance(validated_model.a, dict) def test_dataclass(self): c = Coordinates([Point(1, 2), Point(3, 4)]) d = c.as_dict() c2 = Coordinates.from_dict(d) assert d["points"][0]["x"] == 1 assert d["points"][1]["y"] == 4 assert isinstance(c2, Coordinates) assert isinstance(c2.points[0], Point) s = MontyEncoder().encode(Point(1, 2)) p = MontyDecoder().decode(s) assert p.x == 1 assert p.y == 2 ndc = NestedDataClass([Point(1, 2), Point(3, 4)]) str_ = json.dumps(ndc, cls=MontyEncoder) ndc2 = json.loads(str_, cls=MontyDecoder) assert isinstance(ndc2, NestedDataClass) def test_enum(self): s = MontyEncoder().encode(EnumNoAsDict.name_a) p = MontyDecoder().decode(s) assert p.name == "name_a" assert p.value == "value_a" na1 = EnumAsDict.name_a d_ = na1.as_dict() assert d_ == {"v": "value_a"} na2 = EnumAsDict.from_dict(d_) assert na2 == na1 def test_partial_serializable(self, tmp_path): is_m = GoodMSONClass(a=1, b=2, c=3) not_m = GoodNOTMSONClass(a="a", b="b", c="c") is_m_jsons, is_m_map = partial_monty_encode(is_m) is_m_d = json.loads(is_m_jsons) assert is_m_d["@class"] == "GoodMSONClass" assert is_m_d["a"] == 1 # Empty maps are now reported as ``None`` so ``save()`` no longer # writes a stub ``.pkl`` companion file. assert is_m_map is None not_m_jsons, not_m_map = partial_monty_encode(not_m) not_m_d = json.loads(not_m_jsons) assert not_m_d["@class"] == "GoodNOTMSONClass" assert "@object_reference" in not_m_d assert len(not_m_map) == 1 mixed = {"is_m": is_m, "not_m": not_m} mixed_jsons, _mixed_map = partial_monty_encode(mixed, {"indent": 2}) mixed_d = json.loads(mixed_jsons) assert mixed_d["is_m"]["a"] == 1 assert mixed_d["is_m"]["@class"] == "GoodMSONClass" assert "@object_reference" in mixed_d["not_m"] assert mixed_d["not_m"]["@class"] == "GoodNOTMSONClass" mixed = {"is_m": is_m, "not_m": not_m} save(mixed, tmp_path / "mixed.json") loaded = load2dict(tmp_path / "mixed.json") assert loaded["is_m"]["a"] == 1 assert loaded["not_m"].a == "a" # Test when you are allowed to overwrite with pytest.raises(FileExistsError): save(mixed, tmp_path / "mixed.json") save(mixed, tmp_path / "mixed.json", strict=False) class TestCheckType: def test_check_subclass(self): class A: pass class B(A): pass a, b = A(), B() class_name_A = f"{type(a).__module__}.{type(a).__qualname__}" class_name_B = f"{type(b).__module__}.{type(b).__qualname__}" # a is an instance of A, but not B assert _check_type(a, class_name_A) assert isinstance(a, A) assert not _check_type(a, class_name_B) assert not isinstance(a, B) # b is an instance of both B and A assert _check_type(b, class_name_B) assert isinstance(b, B) assert _check_type(b, class_name_A) assert isinstance(b, A) def test_check_class(self): """This should not work for classes.""" class A: pass class B(A): pass class_name_A = f"{A.__module__}.{A.__qualname__}" class_name_B = f"{B.__module__}.{B.__qualname__}" # Test class behavior (should return False, like isinstance does) assert not _check_type(A, class_name_A) assert not _check_type(B, class_name_B) assert not _check_type(B, class_name_A) def test_callable(self): # Test function def my_function(): pass callable_class_name = ( f"{type(my_function).__module__}.{type(my_function).__qualname__}" ) assert _check_type(my_function, callable_class_name), callable_class_name assert isinstance(my_function, type(my_function)) # Test callable class class MyCallableClass: def __call__(self): pass callable_instance = MyCallableClass() assert callable(callable_instance) callable_class_instance_name = f"{type(callable_instance).__module__}.{type(callable_instance).__qualname__}" assert _check_type(callable_instance, callable_class_instance_name), ( callable_class_instance_name ) assert isinstance(callable_instance, MyCallableClass) def test_numpy(self): # Test NumPy array arr = np.array([1, 2, 3]) assert _check_type(arr, "numpy.ndarray") assert isinstance(arr, np.ndarray) # Test NumPy generic scalar = np.float64(3.14) assert _check_type(scalar, "numpy.generic") assert isinstance(scalar, np.generic) @pytest.mark.skipif(pd is None, reason="pandas is not installed") def test_pandas(self): # Test pandas DataFrame df = pd.DataFrame({"a": [1, 2, 3]}) assert _check_type(df, "pandas.DataFrame") assert isinstance(df, pd.DataFrame) assert _check_type(df, "pandas.core.base.PandasObject") assert isinstance(df, pd.core.base.PandasObject) # Test pandas Series series = pd.Series([1, 2, 3]) assert _check_type(series, "pandas.Series") assert isinstance(series, pd.Series) assert _check_type(series, "pandas.core.base.PandasObject") assert isinstance(series, pd.core.base.PandasObject) @pytest.mark.skipif(torch is None, reason="torch is not installed") def test_torch(self): tensor = torch.tensor([1, 2, 3]) assert _check_type(tensor, "torch.Tensor") assert isinstance(tensor, torch.Tensor) @pytest.mark.skipif(pydantic is None, reason="pydantic is not installed") def test_pydantic(self): class MyModel(pydantic.BaseModel): name: str model_instance = MyModel(name="Alice") assert _check_type(model_instance, "pydantic.main.BaseModel") assert isinstance(model_instance, pydantic.BaseModel) @pytest.mark.skipif(pint is None, reason="pint is not installed") def test_pint(self): ureg = pint.UnitRegistry() qty = 3 * ureg.meter assert _check_type(qty, "pint.registry.Quantity") assert isinstance(qty, pint.Quantity) @pytest.mark.skipif(ObjectId is None, reason="bson not present") @pytest.mark.skipif(json_util is None, reason="pymongo not present") def test_extended_json(self): ext_json_dict = { "datetime": datetime.datetime.now(datetime.UTC), "NaN": float("NaN"), "infinity": float("inf"), "-infinity": -float("inf"), } ext_json_str = json_util.dumps(ext_json_dict) not_serialized = json.loads(ext_json_str) assert all(isinstance(v, dict) for v in not_serialized.values()) reserialized = MontyDecoder().decode(ext_json_str) for k, v in ext_json_dict.items(): if k == "datetime": # BSON's json_util only saves datetimes up to microseconds assert reserialized[k].timestamp() == pytest.approx( v.timestamp(), abs=1e-3 ) elif k == "NaN": assert np.isnan(reserialized[k]) else: assert v == reserialized[k] assert not isinstance(reserialized[k], dict) class _Color: """Simple non-MSONable type used as a stand-in for a third-party class.""" def __init__(self, name: str) -> None: self.name = name def __eq__(self, other: object) -> bool: return isinstance(other, _Color) and self.name == other.name class _ColorHandler(TypeHandler): module = "tests.color" class_name = "Color" def matches(self, obj): return isinstance(obj, _Color) def encode(self, obj): return {"@module": self.module, "@class": self.class_name, "name": obj.name} def decode(self, d): return _Color(d["name"]) class HasColor(MSONable): """Module-level MSONable wrapper for plugin nested-decode tests.""" def __init__(self, color: _Color): self.color = color class TestTypeHandlerPlugin: def setup_method(self): self.handler = _ColorHandler() register(self.handler) def teardown_method(self): unregister(self.handler) def test_register_round_trip(self): color = _Color("red") encoded = json.dumps(color, cls=MontyEncoder) # Encoder emits the handler's dict shape. assert json.loads(encoded) == { "@module": "tests.color", "@class": "Color", "name": "red", } decoded = json.loads(encoded, cls=MontyDecoder) assert decoded == color assert isinstance(decoded, _Color) def test_unregister_removes_handler(self): unregister(self.handler) # After unregister, the encoder no longer knows how to serialize _Color. with pytest.raises(TypeError, match="not JSON serializable"): json.dumps(_Color("blue"), cls=MontyEncoder) # Re-register so teardown's unregister is a no-op and the test is # repeatable. register(self.handler) def test_re_register_replaces_previous(self): class _ColorHandlerV2(TypeHandler): module = "tests.color" class_name = "Color" def matches(self, obj): return isinstance(obj, _Color) def encode(self, obj): return { "@module": self.module, "@class": self.class_name, "name": obj.name.upper(), } def decode(self, d): return _Color(d["name"].lower()) v2 = _ColorHandlerV2() register(v2) try: encoded = json.dumps(_Color("green"), cls=MontyEncoder) assert json.loads(encoded)["name"] == "GREEN" finally: unregister(v2) def test_builtin_dict_shapes_unchanged(self): """Plugin refactor must preserve byte-identical JSON for built-ins.""" assert MontyEncoder().default(datetime.datetime(2024, 1, 2, 3, 4, 5)) == { "@module": "datetime", "@class": "datetime", "string": "2024-01-02 03:04:05", } # ``str(Path)`` differs across platforms (POSIX vs. Windows separators). # Use a no-separator filename so the expected value is portable. assert MontyEncoder().default(pathlib.Path("scratch.txt")) == { "@module": "pathlib", "@class": "Path", "string": "scratch.txt", } assert MontyEncoder().default(np.array([1, 2, 3]))["@module"] == "numpy" def test_handler_with_multiple_class_names(self): """A handler that claims multiple ``@class`` names registers each as its own decoder key and discriminates inside ``encode``. """ class _Shape: def __init__(self, name: str) -> None: self.name = name def __eq__(self, other: object) -> bool: return isinstance(other, type(self)) and self.name == other.name class _Circle(_Shape): pass class _Square(_Shape): pass class _ShapeHandler(TypeHandler): module = "tests.shape" class_name = ("Circle", "Square") def matches(self, obj): return isinstance(obj, (_Circle, _Square)) def encode(self, obj): return { "@module": self.module, "@class": "Circle" if isinstance(obj, _Circle) else "Square", "name": obj.name, } def decode(self, d): cls = _Circle if d["@class"] == "Circle" else _Square return cls(d["name"]) handler = _ShapeHandler() register(handler) try: c, s = _Circle("c1"), _Square("s1") enc_c = json.loads(json.dumps(c, cls=MontyEncoder)) enc_s = json.loads(json.dumps(s, cls=MontyEncoder)) assert enc_c["@class"] == "Circle" assert enc_s["@class"] == "Square" assert MontyDecoder().decode(json.dumps(c, cls=MontyEncoder)) == c assert MontyDecoder().decode(json.dumps(s, cls=MontyEncoder)) == s finally: unregister(handler) def test_nested_user_type_decodes_inside_msonable(self): original = HasColor(_Color("teal")) encoded = json.dumps(original.as_dict(), cls=MontyEncoder) rebuilt = MontyDecoder().decode(encoded) assert isinstance(rebuilt, HasColor) assert rebuilt.color == _Color("teal") monty-2026.10.21/tests/test_logging.py000066400000000000000000000004061526577750300174750ustar00rootroot00000000000000from __future__ import annotations import logging from io import StringIO from monty.logging import logged @logged() def add(a, b): return a + b def test_logged(): s = StringIO() logging.basicConfig(level=logging.DEBUG, stream=s) add(1, 2) monty-2026.10.21/tests/test_math.py000066400000000000000000000002351526577750300170000ustar00rootroot00000000000000from __future__ import annotations from monty.math import nCr, nPr def test_nCr(): assert nCr(4, 2) == 6 def test_nPr(): assert nPr(4, 2) == 12 monty-2026.10.21/tests/test_multiprocessing.py000066400000000000000000000011671526577750300213030ustar00rootroot00000000000000from __future__ import annotations from math import sqrt import pytest try: from tqdm.autonotebook import tqdm from monty.multiprocessing import imap_tqdm except ImportError: tqdm = None @pytest.mark.skipif(tqdm is None, reason="tqdm not installed") def test_imap_tqdm(): results = imap_tqdm(4, sqrt, range(10_000)) assert len(results) == 10_000 assert results[0] == 0 assert results[400] == 20 assert results[9999] == 99.99499987499375 results = imap_tqdm(4, sqrt, (i**2 for i in range(10_000))) assert len(results) == 10_000 assert results[0] == 0 assert results[400] == 400 monty-2026.10.21/tests/test_operator.py000066400000000000000000000012571526577750300177070ustar00rootroot00000000000000from __future__ import annotations import pytest from monty.operator import operator_from_str def test_operator_from_str(): assert operator_from_str("==")(1, 1) assert operator_from_str("+")(1, 1) == 2 @pytest.mark.parametrize( ("op", "expected"), [ ("!=", True), (">", False), (">=", False), ("<", True), ("<=", True), ("-", -1), ("*", 2), ("%", 1), ("^", 3), ("/", 0.5), ], ) def test_operator_from_str_all(op, expected): assert operator_from_str(op)(1, 2) == expected def test_operator_from_str_invalid(): with pytest.raises(KeyError): operator_from_str("**") monty-2026.10.21/tests/test_os.py000066400000000000000000000067001526577750300164730ustar00rootroot00000000000000from __future__ import annotations import os from typing import TYPE_CHECKING import pytest from monty.os import cd, makedirs_p from monty.os.path import find_exts, zpath if TYPE_CHECKING: from pathlib import Path MODULE_DIR = os.path.dirname(__file__) TEST_DIR = os.path.join(MODULE_DIR, "test_files") class TestPath: def test_zpath_str(self, tmp_path: Path): tmp_gz = tmp_path / "tmp.gz" tmp_gz.touch() ret_path = zpath(str(tmp_gz)) assert isinstance(ret_path, str) assert ret_path == str(tmp_gz) tmp_not_bz2 = tmp_path / "tmp_not_bz2" tmp_not_bz2.touch() ret_path = zpath(f"{tmp_not_bz2}.bz2") assert ret_path == str(tmp_not_bz2) assert isinstance(ret_path, str) def test_zpath_path(self, tmp_path: Path): # Test with Path input tmp_gz = tmp_path / "tmp.gz" tmp_gz.touch() ret_path = zpath(tmp_gz) assert ret_path == str(tmp_gz) assert isinstance(ret_path, str) def test_zpath_multiple_extensions(self, tmp_path: Path): exts = ["", ".gz", ".GZ", ".bz2", ".BZ2", ".z", ".Z"] for ext in exts: tmp_file = tmp_path / f"tmp{ext}" # create files with all supported compression extensions tmp_file.touch() # zpath should return the file without compression extension ret_path = zpath(tmp_path / "tmp") assert ret_path == str(tmp_path / "tmp") assert isinstance(ret_path, str) (tmp_path / "tmp").unlink() # Remove the uncompressed file ret_path = zpath(tmp_path / "tmp") assert ret_path == str(tmp_path / "tmp.gz") # should find .gz first now def test_zpath_nonexistent_file(self, tmp_path: Path): # should return path as is for non-existent file nonexistent = tmp_path / "nonexistent.txt" ret_path = zpath(nonexistent) assert ret_path == str(nonexistent) ret_path = zpath(f"{nonexistent}.bz2") assert ret_path == str(nonexistent) def test_find_exts(self): assert len(find_exts(MODULE_DIR, "py")) >= 18 assert len(find_exts(MODULE_DIR, "bz2")) == 2 n_bz2_excl_tests = len(find_exts(MODULE_DIR, "bz2", exclude_dirs="test_files")) assert n_bz2_excl_tests == 0 n_bz2_w_tests = find_exts(MODULE_DIR, "bz2", include_dirs="test_files") assert len(n_bz2_w_tests) == 2 class TestCd: def test_cd(self): with pytest.warns(FutureWarning, match="contextlib.chdir"), cd(TEST_DIR): assert os.path.exists("empty_file.txt") assert not os.path.exists("empty_file.txt") def test_cd_exception(self): cwd = os.getcwd() with ( pytest.warns(FutureWarning), pytest.raises(RuntimeError), cd(TEST_DIR), ): raise RuntimeError assert os.getcwd() == cwd class TestMakedirs_p: def setup_method(self): self.test_dir_path = os.path.join(TEST_DIR, "test_dir") def test_makedirs_p(self): with pytest.warns(FutureWarning, match="exist_ok=True"): makedirs_p(self.test_dir_path) assert os.path.exists(self.test_dir_path) with pytest.warns(FutureWarning): makedirs_p(self.test_dir_path) with pytest.warns(FutureWarning), pytest.raises(OSError, match="exists"): makedirs_p(os.path.join(TEST_DIR, "3000_lines.txt")) def teardown_method(self): os.rmdir(self.test_dir_path) monty-2026.10.21/tests/test_pprint.py000066400000000000000000000016031526577750300173630ustar00rootroot00000000000000from __future__ import annotations from monty.pprint import draw_tree, pprint_table class TestPprintTable: def test_print(self): table = [["one", "two"], ["1", "2"]] pprint_table(table) class TestDrawTree: def test_draw_tree(self): class Node: def __init__(self, name, children): self.name = name self.children = children def __str__(self): return self.name root = Node( "root", [ Node("sub1", []), Node("sub2", [Node("sub2sub1", [])]), Node( "sub3", [ Node("sub3sub1", [Node("sub3sub1sub1", [])]), Node("sub3sub2", []), ], ), ], ) assert draw_tree(root) monty-2026.10.21/tests/test_re.py000066400000000000000000000014561526577750300164630ustar00rootroot00000000000000from __future__ import annotations import os from monty.re import regrep TEST_DIR = os.path.join(os.path.dirname(__file__), "test_files") def test_regrep(): """ We are making sure a file containing line numbers is read in reverse order, i.e. the first line that is read corresponds to the last line. number """ fname = os.path.join(TEST_DIR, "3000_lines.txt") matches = regrep(fname, {"1": r"1(\d+)", "3": r"3(\d+)"}, postprocess=int) assert len(matches["1"]) == 1380 assert len(matches["3"]) == 571 assert matches["1"][0][0][0] == 0 matches = regrep( fname, {"1": r"1(\d+)", "3": r"3(\d+)"}, reverse=True, terminate_on_match=True, postprocess=int, ) assert len(matches["1"]) == 1 assert len(matches["3"]) == 11 monty-2026.10.21/tests/test_serialization.py000066400000000000000000000231261526577750300207300ustar00rootroot00000000000000from __future__ import annotations import datetime import glob import json import os import pathlib import numpy as np import pytest from monty.json import MontyDecoder, MSONable, TypeHandler, register, unregister from monty.serialization import dumpfn, loadfn from monty.tempfile import ScratchDir try: import msgpack except ImportError: msgpack = None class toyMsonable(MSONable): """Dummy class to test de-/serialization.""" def __init__(self, a: int, b: str): self.a = a self.b = b def __eq__(self, other): if not isinstance(other, self.__class__): return False return all( hasattr(other, attr) and getattr(other, attr, None) == getattr(self, attr) for attr in {"a", "b"} ) class TestSerial: @classmethod def teardown_class(cls): # Cleans up test files if a test fails files_to_clean_up = glob.glob("monte_test.*") for fn in files_to_clean_up: os.remove(fn) def test_dumpfn_loadfn(self, tmp_dir): d = {"hello": "world"} # Test standard configuration for ext in ( "json", "yaml", "yml", "json.gz", "yaml.gz", "json.bz2", "yaml.bz2", ): fn = f"monte_test.{ext}" dumpfn(d, fn) d2 = loadfn(fn) assert d == d2, f"Test file with extension {ext} did not parse correctly" # Test custom kwarg configuration dumpfn(d, "monte_test.json", indent=4) d2 = loadfn("monte_test.json") assert d == d2 dumpfn(d, "monte_test.yaml") d2 = loadfn("monte_test.yaml") assert d == d2 # Check if fmt override works. dumpfn(d, "monte_test.json", fmt="yaml") with pytest.raises(json.decoder.JSONDecodeError): loadfn("monte_test.json") d2 = loadfn("monte_test.json", fmt="yaml") assert d == d2 with pytest.raises(TypeError): dumpfn(d, "monte_test.txt", fmt="garbage") with pytest.raises(TypeError): loadfn("monte_test.txt", fmt="garbage") @pytest.mark.skipif(msgpack is None, reason="msgpack-python not installed.") def test_mpk(self, tmp_dir): d = {"hello": "world"} # Test automatic format detection dumpfn(d, "monte_test.mpk") d2 = loadfn("monte_test.mpk") assert d == d2 # Test to ensure basename is respected, and not directory with ScratchDir("."): os.mkdir("mpk_test") os.chdir("mpk_test") fname = os.path.abspath("test_file.json") dumpfn({"test": 1}, fname) with open("test_file.json", encoding="utf-8") as f: reloaded = json.loads(f.read()) assert reloaded["test"] == 1 def test_json_lines(self, tmp_dir): d = [ {"obj": toyMsonable(a=i, b=str(i)), "other": 1.0, "stuff": {"c": 3, "d": 4}} for i in range(5) ] dumpfn(d, "monte_test.jsonl.gz") new_d = loadfn("monte_test.jsonl.gz") assert all(new_d[i] == entry for i, entry in enumerate(d)) assert all(isinstance(entry["obj"], toyMsonable) for entry in new_d) new_d = loadfn("monte_test.jsonl.gz", cls=None) assert all( isinstance(entry["obj"], dict) and toyMsonable.from_dict(entry["obj"]) == d[i]["obj"] for i, entry in enumerate(new_d) ) def test_yaml_msonable_roundtrip(self, tmp_dir): """MSONable subclasses round-trip through YAML (issue #587).""" obj = toyMsonable(a=7, b="seven") dumpfn(obj, "monte_test.yaml") reloaded = loadfn("monte_test.yaml") assert isinstance(reloaded, toyMsonable) assert reloaded == obj # Nested inside list and dict. nested = {"items": [toyMsonable(a=i, b=str(i)) for i in range(3)]} dumpfn(nested, "monte_test.yaml") reloaded = loadfn("monte_test.yaml") assert all(isinstance(o, toyMsonable) for o in reloaded["items"]) assert reloaded["items"] == nested["items"] # ``cls=None`` opts out of reconstruction, mirroring the JSON path. raw = loadfn("monte_test.yaml", cls=None) assert isinstance(raw["items"][0], dict) assert raw["items"][0]["@class"] == "toyMsonable" def test_yaml_custom_decoder_cls(self, tmp_dir): """A user-supplied ``cls`` is honored for YAML, not replaced by MontyDecoder.""" used = [] class TrackingDecoder(MontyDecoder): def __init__(self, *args, **kwargs): used.append(True) super().__init__(*args, **kwargs) obj = toyMsonable(a=7, b="seven") dumpfn(obj, "monte_test.yaml") assert loadfn("monte_test.yaml", cls=TrackingDecoder) == obj assert used @pytest.mark.parametrize( ("fn", "attr", "msg"), [ ("monte_test.mpk", "msgpack", "Dumping to message pack"), ("monte_test.yaml", "YAML", "Dumping to YAML"), ], ) def test_dumpfn_missing_backend(self, tmp_dir, monkeypatch, fn, attr, msg): import monty.serialization monkeypatch.setattr(monty.serialization, attr, None) with pytest.raises(RuntimeError, match=msg): dumpfn({"a": 1}, fn) @pytest.mark.parametrize( ("fn", "attr", "msg"), [ pytest.param( "monte_test.mpk", "msgpack", "Loading of message pack", marks=pytest.mark.skipif( msgpack is None, reason="msgpack-python not installed." ), ), ("monte_test.yaml", "YAML", "Loading of YAML"), ], ) def test_loadfn_missing_backend(self, tmp_dir, monkeypatch, fn, attr, msg): import monty.serialization dumpfn({"a": 1}, fn) monkeypatch.setattr(monty.serialization, attr, None) with pytest.raises(RuntimeError, match=msg): loadfn(fn) def test_yaml_numpy_path_roundtrip(self, tmp_dir): """numpy arrays and pathlib paths round-trip through YAML.""" payload = { "arr": np.array([1.0, 2.0, 3.0]), "p": pathlib.Path("/tmp/example"), } dumpfn(payload, "monte_test.yaml") reloaded = loadfn("monte_test.yaml") assert isinstance(reloaded["arr"], np.ndarray) np.testing.assert_array_equal(reloaded["arr"], payload["arr"]) assert isinstance(reloaded["p"], pathlib.PurePath) assert reloaded["p"] == payload["p"] def test_yaml_preserves_native_datetime(self, tmp_dir): """datetime keeps ruamel.yaml's native rendering (no @module envelope).""" when = datetime.datetime(2026, 5, 18, 12, 0, 0) dumpfn({"when": when}, "monte_test.yaml") with open("monte_test.yaml", encoding="utf-8") as f: raw = f.read() # Native ruamel.yaml emits the timestamp as a bare scalar, not as a # ``@module``/``@class`` envelope. assert "@module" not in raw assert "2026-05-18" in raw reloaded = loadfn("monte_test.yaml") assert reloaded["when"] == when def test_yaml_plain_dict_unchanged(self, tmp_dir): """Plain dict YAML output is byte-identical to pre-#587 behavior.""" dumpfn({"hello": "world"}, "monte_test.yaml") with open("monte_test.yaml", encoding="utf-8") as f: raw = f.read() assert raw == "hello: world\n" def test_yaml_thread_safe_roundtrip(self, tmp_dir): """Concurrent dumpfn/loadfn from threads do not corrupt YAML state (issue #795).""" import concurrent.futures def worker(idx: int) -> dict: fn = f"monte_test_{idx}.yaml" payload = { "obj": toyMsonable(a=idx, b=str(idx)), "arr": np.array([float(idx), float(idx) + 1.0]), "p": pathlib.Path(f"/tmp/{idx}"), } dumpfn(payload, fn) return loadfn(fn) n = 32 with concurrent.futures.ThreadPoolExecutor(max_workers=8) as ex: results = list(ex.map(worker, range(n))) for idx, result in enumerate(results): assert isinstance(result["obj"], toyMsonable) assert result["obj"].a == idx assert result["obj"].b == str(idx) np.testing.assert_array_equal(result["arr"], [float(idx), float(idx) + 1.0]) assert result["p"] == pathlib.Path(f"/tmp/{idx}") def test_yaml_user_typehandler(self, tmp_dir): """User-registered TypeHandlers participate in YAML round-trip.""" class MyType: def __init__(self, value: int): self.value = value def __eq__(self, other): return isinstance(other, MyType) and self.value == other.value class MyHandler(TypeHandler): module = "tests.test_serialization" class_name = "MyType" def matches(self, obj): return isinstance(obj, MyType) def encode(self, obj): return { "@module": self.module, "@class": self.class_name, "value": obj.value, } def decode(self, d): return MyType(d["value"]) handler = MyHandler() register(handler) try: obj = MyType(42) dumpfn(obj, "monte_test.yaml") reloaded = loadfn("monte_test.yaml") assert isinstance(reloaded, MyType) assert reloaded == obj finally: unregister(handler) monty-2026.10.21/tests/test_shutil.py000066400000000000000000000201501526577750300173550ustar00rootroot00000000000000from __future__ import annotations import os import platform import shutil import tempfile from gzip import GzipFile from pathlib import Path import pytest from monty.shutil import ( compress_dir, compress_file, copy_r, decompress_dir, decompress_file, gzip_dir, remove, ) TEST_DIR = os.path.join(os.path.dirname(__file__), "test_files") class TestCopyR: def setup_method(self): os.mkdir(os.path.join(TEST_DIR, "cpr_src")) with open( os.path.join(TEST_DIR, "cpr_src", "test"), "w", encoding="utf-8" ) as f: f.write("what") os.mkdir(os.path.join(TEST_DIR, "cpr_src", "sub")) with open( os.path.join(TEST_DIR, "cpr_src", "sub", "testr"), "w", encoding="utf-8" ) as f: f.write("what2") if platform.system() != "Windows": os.symlink( os.path.join(TEST_DIR, "cpr_src", "test"), os.path.join(TEST_DIR, "cpr_src", "mysymlink"), ) def test_recursive_copy_and_compress(self): with pytest.warns(DeprecationWarning, match="shutil.copytree"): copy_r(os.path.join(TEST_DIR, "cpr_src"), os.path.join(TEST_DIR, "cpr_dst")) assert os.path.exists(os.path.join(TEST_DIR, "cpr_dst", "test")) assert os.path.exists(os.path.join(TEST_DIR, "cpr_dst", "sub", "testr")) compress_dir(os.path.join(TEST_DIR, "cpr_src")) assert os.path.exists(os.path.join(TEST_DIR, "cpr_src", "test.gz")) assert os.path.exists(os.path.join(TEST_DIR, "cpr_src", "sub", "testr.gz")) decompress_dir(os.path.join(TEST_DIR, "cpr_src")) assert os.path.exists(os.path.join(TEST_DIR, "cpr_src", "test")) assert os.path.exists(os.path.join(TEST_DIR, "cpr_src", "sub", "testr")) with open(os.path.join(TEST_DIR, "cpr_src", "test"), encoding="utf-8") as f: txt = f.read() assert txt == "what" def test_pathlib(self): test_path = Path(TEST_DIR) with pytest.warns(DeprecationWarning, match="shutil.copytree"): copy_r(test_path / "cpr_src", test_path / "cpr_dst") assert (test_path / "cpr_dst" / "test").exists() assert (test_path / "cpr_dst" / "sub" / "testr").exists() def teardown_method(self): shutil.rmtree(os.path.join(TEST_DIR, "cpr_src")) shutil.rmtree(os.path.join(TEST_DIR, "cpr_dst")) class TestCompressFileDir: def setup_method(self): with open(os.path.join(TEST_DIR, "tempfile"), "w", encoding="utf-8") as f: f.write("hello world") def test_compress_and_decompress_file(self): fname = os.path.join(TEST_DIR, "tempfile") for fmt in ["gz", "bz2"]: compress_file(fname, fmt) assert os.path.exists(fname + "." + fmt) assert not os.path.exists(fname) decompress_file(fname + "." + fmt) assert os.path.exists(fname) assert not os.path.exists(fname + "." + fmt) with open(fname, encoding="utf-8") as f: assert f.read() == "hello world" with pytest.raises(ValueError): compress_file("whatever", "badformat") # test decompress non-existent/non-compressed file assert decompress_file("non-existent") is None assert decompress_file("non-existent.gz") is None assert decompress_file("non-existent.bz2") is None def test_compress_and_decompress_with_target_dir(self): fname = os.path.join(TEST_DIR, "tempfile") target_dir = os.path.join(TEST_DIR, "temp_target_dir") for fmt in ["gz", "bz2"]: compress_file(fname, fmt, target_dir) compressed_file_path = os.path.join( target_dir, f"{os.path.basename(fname)}.{fmt}" ) assert os.path.exists(compressed_file_path) assert not os.path.exists(fname) decompress_file(compressed_file_path, target_dir) decompressed_file_path = os.path.join(target_dir, os.path.basename(fname)) assert os.path.exists(decompressed_file_path) assert not os.path.exists(compressed_file_path) # Reset temp file position shutil.move(decompressed_file_path, fname) shutil.rmtree(target_dir) with open(fname, encoding="utf-8") as f: assert f.read() == "hello world" def teardown_method(self): os.remove(os.path.join(TEST_DIR, "tempfile")) class TestGzipDir: def setup_method(self): os.mkdir(os.path.join(TEST_DIR, "gzip_dir")) with open( os.path.join(TEST_DIR, "gzip_dir", "tempfile"), "w", encoding="utf-8" ) as f: f.write("what") self.mtime = os.path.getmtime(os.path.join(TEST_DIR, "gzip_dir", "tempfile")) def test_gzip_dir(self): full_f = os.path.join(TEST_DIR, "gzip_dir", "tempfile") gzip_dir(os.path.join(TEST_DIR, "gzip_dir")) assert os.path.exists(f"{full_f}.gz") assert not os.path.exists(full_f) with GzipFile(f"{full_f}.gz") as g: assert g.readline().decode("utf-8") == "what" assert os.path.getmtime(f"{full_f}.gz") == pytest.approx(self.mtime, 4) def test_gzip_dir_file_coexist(self): """Test case where both file and file.gz exist.""" full_f = os.path.join(TEST_DIR, "gzip_dir", "temptestfile") gz_f = f"{full_f}.gz" # Create both the file and its gzipped version with open(full_f, "w", encoding="utf-8") as f: f.write("not gzipped") with GzipFile(gz_f, "wb") as g: g.write(b"gzipped") with pytest.warns( UserWarning, match="Both temptestfile and temptestfile.gz exist." ): gzip_dir(os.path.join(TEST_DIR, "gzip_dir")) # Verify contents of the files with open(full_f, encoding="utf-8") as f: assert f.read() == "not gzipped" with GzipFile(gz_f, "rb") as g: assert g.read() == b"gzipped" def test_handle_sub_dirs(self): sub_dir = os.path.join(TEST_DIR, "gzip_dir", "sub_dir") sub_file = os.path.join(sub_dir, "new_tempfile") os.mkdir(sub_dir) with open(sub_file, "w", encoding="utf-8") as f: f.write("anotherwhat") gzip_dir(os.path.join(TEST_DIR, "gzip_dir")) assert os.path.exists(f"{sub_file}.gz") assert not os.path.exists(sub_file) with GzipFile(f"{sub_file}.gz") as g: assert g.readline().decode("utf-8") == "anotherwhat" def teardown_method(self): shutil.rmtree(os.path.join(TEST_DIR, "gzip_dir")) class TestRemove: @pytest.mark.skipif(platform.system() == "Windows", reason="Skip on windows") def test_remove_file(self): tempdir = tempfile.mkdtemp(dir=TEST_DIR) tempf = tempfile.mkstemp(dir=tempdir)[1] remove(tempf) assert not os.path.isfile(tempf) shutil.rmtree(tempdir) @pytest.mark.skipif(platform.system() == "Windows", reason="Skip on windows") def test_remove_folder(self): tempdir = tempfile.mkdtemp(dir=TEST_DIR) remove(tempdir) assert not os.path.isdir(tempdir) @pytest.mark.skipif(platform.system() == "Windows", reason="Skip on windows") def test_remove_symlink(self): tempdir = tempfile.mkdtemp(dir=TEST_DIR) tempf = tempfile.mkstemp(dir=tempdir)[1] os.symlink(tempdir, os.path.join(TEST_DIR, "temp_link")) templink = os.path.join(TEST_DIR, "temp_link") remove(templink) assert os.path.isfile(tempf) assert os.path.isdir(tempdir) assert not os.path.islink(templink) remove(tempdir) @pytest.mark.skipif(platform.system() == "Windows", reason="Skip on windows") def test_remove_symlink_follow(self): tempdir = tempfile.mkdtemp(dir=TEST_DIR) tempf = tempfile.mkstemp(dir=tempdir)[1] os.symlink(tempdir, os.path.join(TEST_DIR, "temp_link")) templink = os.path.join(TEST_DIR, "temp_link") remove(templink, follow_symlink=True) assert not os.path.isfile(tempf) assert not os.path.isdir(tempdir) assert not os.path.islink(templink) monty-2026.10.21/tests/test_string.py000066400000000000000000000006741526577750300173640ustar00rootroot00000000000000from __future__ import annotations import random from monty.string import remove_non_ascii def test_remove_non_ascii(): s = "".join(chr(random.randint(0, 127)) for _ in range(10)) s += "".join(chr(random.randint(128, 150)) for _ in range(10)) clean = remove_non_ascii(s) assert len(clean) == 10 def test_remove_non_ascii_preserves_order(): assert remove_non_ascii("caf\u00e9 \u2014 na\u00efve\x7f") == "caf nave\x7f" monty-2026.10.21/tests/test_subprocess.py000066400000000000000000000027631526577750300202470ustar00rootroot00000000000000from __future__ import annotations import pytest from monty.subprocess import Command def test_command(): """Test Command class""" sleep05 = Command("sleep 0.5") # NOTE: use a generous timeout relative to the 0.5s sleep. A tight # timeout (e.g. 1s) is flaky on Windows CI, where process spawn # overhead can push total runtime past the timeout, causing the # subprocess to be killed and retcode to be non-zero (PR702). sleep05.run(timeout=20) full_msg = f"{sleep05=}\n{sleep05.error=}\n{sleep05.output}" assert sleep05.retcode == 0, full_msg assert not sleep05.killed sleep05.run(timeout=0.1) assert sleep05.retcode != 0 assert sleep05.killed @pytest.mark.parametrize("command", [["sleep", "0.1"], ("sleep", "0.1")]) def test_command_sequence(command): com = Command(command) assert com.command == ["sleep", "0.1"] com.run(timeout=20) assert com.retcode == 0 assert not com.killed def test_command_timeout_does_not_block(): import time start = time.perf_counter() com = Command("sleep 10").run(timeout=0.2) assert com.killed assert com.retcode != 0 assert time.perf_counter() - start < 5 def test_command_output(): com = Command(["python", "-c", "print('hello')"]).run(timeout=20) assert com.retcode == 0 assert com.output.strip() == b"hello" def test_command_not_found(): com = Command("monty_nonexistent_executable").run(timeout=20) assert com.retcode == -1 assert "Error" in com.error monty-2026.10.21/tests/test_tempfile.py000066400000000000000000000126611526577750300176620ustar00rootroot00000000000000from __future__ import annotations import os import platform import shutil import pytest from monty.tempfile import ScratchDir TEST_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test_files") class TestScratchDir: def setup_method(self): self.cwd = os.getcwd() os.chdir(TEST_DIR) self.scratch_root = os.path.join(TEST_DIR, "..", "..", "tempscratch") os.mkdir(self.scratch_root) def test_with_copy(self): # We write a pre-scratch file. with open("pre_scratch_text", "w", encoding="utf-8") as f: f.write("write") orig_cwd = os.getcwd() # Expect a warning on exit due to newer file in CWD than in temp with ( pytest.warns(RuntimeWarning, match="files newer in CWD"), ScratchDir( self.scratch_root, copy_from_current_on_enter=True, copy_to_current_on_exit=True, ) as d, ): with open("scratch_text", "w", encoding="utf-8") as f: f.write("write") files = os.listdir(d) assert "scratch_text" in files assert "empty_file.txt" in files assert "pre_scratch_text" in files # Make a file in the ORIGINAL CWD newer than the copy in temp. with open( os.path.join(orig_cwd, "empty_file.txt"), "a", encoding="utf-8" ) as f: f.write("hello\n") # We remove the pre-scratch file. os.remove("pre_scratch_text") # Make sure the tempdir is deleted. assert not os.path.exists(d) files = os.listdir(".") assert "scratch_text" in files os.remove("scratch_text") os.remove("pre_scratch_text") def test_with_copy_gzip(self): # We write a pre-scratch file. with open("pre_scratch_text", "w", encoding="utf-8") as f: f.write("write") init_gz_files = [f for f in os.listdir(os.getcwd()) if f.endswith(".gz")] with pytest.warns(match="Both 3000_lines.txt and 3000_lines.txt.gz exist."): with ( ScratchDir( self.scratch_root, copy_from_current_on_enter=True, copy_to_current_on_exit=True, gzip_on_exit=True, ), open("scratch_text", "w", encoding="utf-8") as f, ): f.write("write") files = os.listdir(os.getcwd()) # Make sure the scratch_text.gz exists assert "scratch_text.gz" in files for f in files: if f.endswith(".gz") and f not in init_gz_files: os.remove(f) os.remove("pre_scratch_text") os.remove("scratch_text") def test_no_copy(self): with ScratchDir( self.scratch_root, copy_from_current_on_enter=False, copy_to_current_on_exit=False, ) as d: with open("scratch_text", "w", encoding="utf-8") as f: f.write("write") files = os.listdir(d) assert "scratch_text" in files assert "empty_file.txt" not in files # Make sure the tempdir is deleted. assert not os.path.exists(d) files = os.listdir(".") assert "scratch_text" not in files def test_symlink(self): if platform.system() != "Windows": orig_cwd = os.getcwd() # where the symlink will be created with ScratchDir( self.scratch_root, copy_from_current_on_enter=False, copy_to_current_on_exit=False, create_symbolic_link=True, ) as d: with open("scratch_text", "w", encoding="utf-8") as f: f.write("write") files = os.listdir(d) assert "scratch_text" in files assert "empty_file.txt" not in files # Check symlink link_path = os.path.join(orig_cwd, ScratchDir.SCR_LINK) assert os.path.islink(link_path) assert os.readlink(link_path) == d # Make sure the tempdir is deleted. assert not os.path.exists(d) files = os.listdir(".") assert "scratch_text" not in files # Make sure the symlink is removed assert not os.path.islink(ScratchDir.SCR_LINK) def test_bad_rootpath(self): # rootpath doesn't exist assert not os.path.isdir("non_existent_root") with pytest.warns(RuntimeWarning, match="pass through"): with ScratchDir("non_existent_root") as d: assert d == TEST_DIR # rootpath isn't a directory assert os.path.isfile("empty_file.txt") with pytest.warns(RuntimeWarning, match="pass through"): with ScratchDir("empty_file.txt") as d: assert d == TEST_DIR def test_rootpath_as_none(self): orig_cwd = os.getcwd() scratch_file_name = "scratch_text" with ScratchDir( rootpath=None, ) as d: assert d == orig_cwd assert os.getcwd() == orig_cwd with open(scratch_file_name, "w", encoding="utf-8") as f: f.write("write") assert os.path.exists(scratch_file_name) os.remove(scratch_file_name) def teardown_method(self): os.chdir(self.cwd) shutil.rmtree(self.scratch_root) monty-2026.10.21/tests/test_termcolor.py000066400000000000000000000052261526577750300200620ustar00rootroot00000000000000from __future__ import annotations import os import sys from monty.termcolor import ( cprint, cprint_map, enable, get_terminal_size, stream_has_colours, ) class TestFunc: def test_remove_non_ascii(self): enable(True) print("Current terminal type: {}".format(os.getenv("TERM"))) print("Test basic colors:") cprint("Grey color", "grey") cprint("Red color", "red") cprint("Green color", "green") cprint("Yellow color", "yellow") cprint("Blue color", "blue") cprint("Magenta color", "magenta") cprint("Cyan color", "cyan") cprint("White color", "white") print("-" * 78) print("Test highlights:") cprint("On grey color", on_color="on_grey") cprint("On red color", on_color="on_red") cprint("On green color", on_color="on_green") cprint("On yellow color", on_color="on_yellow") cprint("On blue color", on_color="on_blue") cprint("On magenta color", on_color="on_magenta") cprint("On cyan color", on_color="on_cyan") cprint("On white color", color="grey", on_color="on_white") print("-" * 78) print("Test attributes:") cprint("Bold grey color", "grey", attrs=["bold"]) cprint("Dark red color", "red", attrs=["dark"]) cprint("Underline green color", "green", attrs=["underline"]) cprint("Blink yellow color", "yellow", attrs=["blink"]) cprint("Reversed blue color", "blue", attrs=["reverse"]) cprint("Concealed Magenta color", "magenta", attrs=["concealed"]) cprint( "Bold underline reverse cyan color", "cyan", attrs=["bold", "underline", "reverse"], ) cprint( "Dark blink concealed white color", "white", attrs=["dark", "blink", "concealed"], ) print("-" * 78) print("Test mixing:") cprint("Underline red on grey color", "red", "on_grey", ["underline"]) cprint("Reversed green on red color", "green", "on_red", ["reverse"]) # Test cprint_keys cprint_map("Hello world", {"Hello": "red"}) cprint_map("Hello world", {"Hello": {"color": "blue", "on_color": "on_red"}}) # Test terminal size. print("terminal size: %s", get_terminal_size()) enable(False) def test_stream_has_colors(self): # TODO: not a real test. Need to do a proper test. assert not stream_has_colours(sys.stdout) def test_get_terminal_size_env(monkeypatch): monkeypatch.setenv("LINES", "42") monkeypatch.setenv("COLUMNS", "123") assert get_terminal_size() == (42, 123) monty-2026.10.21/uv.lock000066400000000000000000017727621526577750300146260ustar00rootroot00000000000000version = 1 revision = 5 requires-python = ">=3.11" resolution-markers = [ "python_full_version >= '3.15' and sys_platform == 'win32'", "python_full_version >= '3.15' and sys_platform == 'emscripten'", "python_full_version >= '3.15' and sys_platform != 'emscripten' and sys_platform != 'win32'", "python_full_version == '3.14.*' and sys_platform == 'win32'", "python_full_version == '3.14.*' and sys_platform == 'emscripten'", "python_full_version == '3.14.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", "python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'win32'", "python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'emscripten'", "python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", "python_full_version < '3.12' and sys_platform == 'win32'", "python_full_version < '3.12' and sys_platform == 'emscripten'", "python_full_version < '3.12' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] [[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-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 = "ast-serialize" version = "0.13.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/21/d5/5dc1ee8a80c3b20a0b63c61b43ba6bc53517faecd1def47bcd752d22268e/ast_serialize-0.13.1.tar.gz", hash = "sha256:401cc84e8888d4d76f2c8d296fa006ed1a5ff993b6aff90dd777c03973efd025", size = 955137, upload-time = "2026-10-17T00:04:17.183Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/f3/a8/fbd136b9f70c59e75f59a8e974c84102976f1201828b4f886480ba956936/ast_serialize-0.13.1-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:3e129d44b0cffbea24a7f40117ce49e30993c3d119e584d4817ebd6f87246456", size = 897306, upload-time = "2026-10-17T00:02:52.479Z" }, { url = "https://files.pythonhosted.org/packages/50/3f/2ad51e9823a790e7a70fd781e9595ab3abeace27f3aefcaa1939457efd72/ast_serialize-0.13.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:523d45bab16ddaf1399c04c4fe81bbf180f81e33c2f7bcbe76be56b0f7311ab4", size = 1236082, upload-time = "2026-10-17T00:02:54.82Z" }, { url = "https://files.pythonhosted.org/packages/c0/5c/8e959db5cc2237f9d4c560a8e2253c98f9746883fb4774651e4cda458901/ast_serialize-0.13.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:638333fb8ae72c62753f9e794fda20290883ddc65b0d85e26e08f8bb227567ad", size = 1221242, upload-time = "2026-10-17T00:02:56.395Z" }, { url = "https://files.pythonhosted.org/packages/d6/05/ab1c56c3b7adcac88764bba609502d6b4989e449b2dd60eb478e1d20e369/ast_serialize-0.13.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc34c670747d85d4232834665e247009413eaebe47c69eaf60a5c439aaecaed9", size = 1282105, upload-time = "2026-10-17T00:02:58.275Z" }, { url = "https://files.pythonhosted.org/packages/0d/f4/41981fcd2ddffe0760e5326be9dcbd2eda9478a8430a637e5123bd8fcb26/ast_serialize-0.13.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8c8ebd419811c435812d242fb2a173e57dfede198c9ac9a0a584666ebc9b9331", size = 1287905, upload-time = "2026-10-17T00:03:00.068Z" }, { url = "https://files.pythonhosted.org/packages/6a/43/b783addc5681153707121991b7b47892f7e9c8ba58a0d03b71a3b023ba47/ast_serialize-0.13.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8899c038b1c15ae8b98e379057fb3ef398ceb0b21d1737a8156dd5a0923b7e51", size = 1541806, upload-time = "2026-10-17T00:03:01.503Z" }, { url = "https://files.pythonhosted.org/packages/47/10/969db095038ee15270f65ad20d1129c5e4da605bf7e93b70ae640f1c8a9f/ast_serialize-0.13.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e14c4de98f965647a74e6eaf37e20207124e45451ccd36e84a6f6ebab45e0372", size = 1309946, upload-time = "2026-10-17T00:03:02.971Z" }, { url = "https://files.pythonhosted.org/packages/06/dd/7c623d2fb0b868948952d1787e629a43b866f7d4caefd5445e20aefacec4/ast_serialize-0.13.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f3e8a3eff69af640db985360fef35073fb46956dfc3e5c614cf00920d2746dd", size = 1302773, upload-time = "2026-10-17T00:03:04.378Z" }, { url = "https://files.pythonhosted.org/packages/d4/c2/4d49469110a19a44fc6269f4fd59679bcf84df068f185f89b73bee4da19b/ast_serialize-0.13.1-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:75d7750fe98f6f35a96c43aba8d98a2e623e22c778a0c17ab9ede92eb10f5d82", size = 1299579, upload-time = "2026-10-17T00:03:05.88Z" }, { url = "https://files.pythonhosted.org/packages/9d/9a/2d381f1f262dda15affc8ad643fba1619eb07e7d9f8bd904deffef183006/ast_serialize-0.13.1-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43e8ddd63e80fc280c2f790157386f27f9b9f6ccb9c4f8e803b863cbfb085769", size = 1355969, upload-time = "2026-10-17T00:03:07.321Z" }, { url = "https://files.pythonhosted.org/packages/9d/9c/2266794e6c25fa9ce51ce04a9bf4b7e330e3ac9351ba3fa14e487678acdb/ast_serialize-0.13.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9221e09496fb942901993c1812ee87950cc0ecbb514c7c0f1f5fa6d78f701ed8", size = 1460227, upload-time = "2026-10-17T00:03:08.733Z" }, { url = "https://files.pythonhosted.org/packages/2b/d6/14deb28e5d8f328f626a0778ea2cf98fe908f2bbcccd804cb6f449ee1782/ast_serialize-0.13.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:7a5c38bdb93669c596f94fb7204dd6ebe4fadb19058ac9a2faf2948c2a175f96", size = 1562691, upload-time = "2026-10-17T00:03:10.25Z" }, { url = "https://files.pythonhosted.org/packages/f5/19/7a28c0e5ba54f0d3e054f847a2a549b748cb179ab433321a8dc1b39e398d/ast_serialize-0.13.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:acf4e9f055d75058ab01536da330648746f2f82b7697a85230547f2d5ebe895c", size = 1558669, upload-time = "2026-10-17T00:03:11.799Z" }, { url = "https://files.pythonhosted.org/packages/18/9a/f9e2690eab58217f1d395a964a78efa7eaf813a1e38be8dfd9a8d45d0840/ast_serialize-0.13.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:87427913c325adc811e81e7c9a757b061f47ef1e29114ac479aa0953a2687a98", size = 1665071, upload-time = "2026-10-17T00:03:13.284Z" }, { url = "https://files.pythonhosted.org/packages/8e/f3/ef5b159a0d7161b404f05e7ec21cf7735ee7edc10c000cd2cbbc7bb6b69a/ast_serialize-0.13.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:ad88921f95b92bc144d9ad059a0e16f8c1ae69f5239f2d3c6536fd2774f73dfe", size = 1473364, upload-time = "2026-10-17T00:03:14.563Z" }, { url = "https://files.pythonhosted.org/packages/1d/87/6e8ac4a865124a12cc4f915bf1bcfac3bba426cd5f58d3712a873ee61012/ast_serialize-0.13.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f8b17e2921e56621bcb46792bd3e0b82ca3b85de78d5936e7b8174ba1758b0aa", size = 1500566, upload-time = "2026-10-17T00:03:15.917Z" }, { url = "https://files.pythonhosted.org/packages/f5/1e/29155f1621433008013ad5c940a03d41a676be0680c41527040472d37583/ast_serialize-0.13.1-cp314-cp314t-win32.whl", hash = "sha256:2f9a9ce8b0994f757b941f7f7fe384a6666b4162b941ebc5c248081baea18e47", size = 1128674, upload-time = "2026-10-17T00:03:17.481Z" }, { url = "https://files.pythonhosted.org/packages/bb/64/2506da65143ea138de5822e9173e0b72320a2f70e23bd723f044033175f1/ast_serialize-0.13.1-cp314-cp314t-win_amd64.whl", hash = "sha256:5d99910e6b9a9b9360bcca2ae99aee36cc912ce058df2a57d1c33099b6cb2593", size = 1163306, upload-time = "2026-10-17T00:03:19.046Z" }, { url = "https://files.pythonhosted.org/packages/6d/8f/c7cb22638899b0cf15908809c270560e46395e65604bc59e4b623ab9f405/ast_serialize-0.13.1-cp314-cp314t-win_arm64.whl", hash = "sha256:a789cbe14d0a0e9ec9b32a456e5abc81ad8799479c3cfd88a29e3442262aebe6", size = 1133775, upload-time = "2026-10-17T00:03:20.377Z" }, { url = "https://files.pythonhosted.org/packages/2b/e2/b0c140fe50fa39dd249e382f7733af6f816c90021fe7959a0b026f86237f/ast_serialize-0.13.1-cp315-abi3.abi3t-macosx_10_12_x86_64.whl", hash = "sha256:23d768369b89d551077dc173da6892fad00443338417523b6732f4e8ba4a7ed5", size = 1236160, upload-time = "2026-10-17T00:03:21.945Z" }, { url = "https://files.pythonhosted.org/packages/23/c4/a8a2ca21e3943555b48221f8fba546877a7ad39efaf6505506524967d7c4/ast_serialize-0.13.1-cp315-abi3.abi3t-macosx_11_0_arm64.whl", hash = "sha256:68f8829d114dab6c9db4a8bbb8d0e342958faee1b5e15a29022678df639960f8", size = 1222214, upload-time = "2026-10-17T00:03:23.462Z" }, { url = "https://files.pythonhosted.org/packages/15/19/2f58f2ba64e4799b39de85c140aef09a03aa6ea53be75dd292a9d9b9d8ae/ast_serialize-0.13.1-cp315-abi3.abi3t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e385b17d5bde892a6184003a9aff3518387908b73f8f5ea539313c07c8c0ede", size = 1282979, upload-time = "2026-10-17T00:03:24.695Z" }, { url = "https://files.pythonhosted.org/packages/b1/af/ca6087fe84210c1ccd43e3182917bb70649fa1e69745a90c1d59ba08fea8/ast_serialize-0.13.1-cp315-abi3.abi3t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:02686b281ec9b8e9614f6f0db27e12e4cac515f336c5d05b678bc9eb73ff2af5", size = 1288596, upload-time = "2026-10-17T00:03:26.04Z" }, { url = "https://files.pythonhosted.org/packages/b0/2c/4ef964c763329a0347125e745ec0451ba4fbaceec9efe2ac729b7cd55f17/ast_serialize-0.13.1-cp315-abi3.abi3t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8ab2c2585b2e22e48cd4aff2136fce4eab4ced569b85f150ef9a5a5d6f34d49", size = 1545540, upload-time = "2026-10-17T00:03:27.52Z" }, { url = "https://files.pythonhosted.org/packages/bb/85/aa961dbb75813cfa94de0ce9a16a9510c226b95f604c405421e727f44bb0/ast_serialize-0.13.1-cp315-abi3.abi3t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c652d9f5d52d8b81eff3ff2c95c9dd0f281de45f6ad5d3fa95527550c396454a", size = 1309374, upload-time = "2026-10-17T00:03:29.091Z" }, { url = "https://files.pythonhosted.org/packages/b4/e6/f2b67c327d9f9533e41791804403ccc2dc457821195a2e51f0b587a90b90/ast_serialize-0.13.1-cp315-abi3.abi3t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:121e1d08d58b75c15491cc3003609cbad71ac2b0016043c36d30a6b2032b6605", size = 1303466, upload-time = "2026-10-17T00:03:30.451Z" }, { url = "https://files.pythonhosted.org/packages/73/1d/33f18b81d1bb1f5d682943ea92fda8130a6593627f12f6201668d40824fd/ast_serialize-0.13.1-cp315-abi3.abi3t-manylinux_2_31_riscv64.whl", hash = "sha256:30cf89b6a6844542d116c758725d13de5b97b9410a51ee577715f761270d0c1c", size = 1300576, upload-time = "2026-10-17T00:03:32.102Z" }, { url = "https://files.pythonhosted.org/packages/25/cb/64914144925f1a4abdd9217e717b122255c38fc5ebe4342f92052f3bacbc/ast_serialize-0.13.1-cp315-abi3.abi3t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:732aaae9e498c973fc63fd7f308009b57c4afa6ff59d0b674d894e57d0bca01a", size = 1355960, upload-time = "2026-10-17T00:03:33.676Z" }, { url = "https://files.pythonhosted.org/packages/ee/80/bd29379fab2bce19adc0bf9177002b11b23dfe8d8fecf409998b458b4624/ast_serialize-0.13.1-cp315-abi3.abi3t-musllinux_1_2_aarch64.whl", hash = "sha256:d9c1a920b2aa0c1e016bed7721689717034ca0dba64ac3a3ff243b003d4e8dd8", size = 1459779, upload-time = "2026-10-17T00:03:35.09Z" }, { url = "https://files.pythonhosted.org/packages/83/89/012dbe733de05ffdf8e40ca0f9fa5d417cb16ec93a74463c57c001914198/ast_serialize-0.13.1-cp315-abi3.abi3t-musllinux_1_2_armv7l.whl", hash = "sha256:847cad4c22953823f5e76d0b126c6f9da670cfa45b1df41b9324e22189d77611", size = 1563399, upload-time = "2026-10-17T00:03:37.285Z" }, { url = "https://files.pythonhosted.org/packages/69/37/ee4bcb0358bee38744eb0f18560446572d095fe3bf6b63d6f739d08a839c/ast_serialize-0.13.1-cp315-abi3.abi3t-musllinux_1_2_i686.whl", hash = "sha256:aca07de3ca8e3d9f2b716c3c31f4f384fe4bd2d03e09912417cff7a3e08036f7", size = 1558808, upload-time = "2026-10-17T00:03:38.711Z" }, { url = "https://files.pythonhosted.org/packages/54/1c/ff44c5355251d61ef22934c4430bb31a61de4781d25a992154aac9b8c82a/ast_serialize-0.13.1-cp315-abi3.abi3t-musllinux_1_2_ppc64le.whl", hash = "sha256:5db12d843d931b9d1f1519ce66b9cbfe72d8563b75c1204d255322254d1964dd", size = 1666324, upload-time = "2026-10-17T00:03:40.376Z" }, { url = "https://files.pythonhosted.org/packages/c8/bb/6da4bfc8aa3403e6447607131bf3463acaf954d990c6c8b6787c1902ddfe/ast_serialize-0.13.1-cp315-abi3.abi3t-musllinux_1_2_riscv64.whl", hash = "sha256:fb8021f4dc3296de18737e3b8b34994411da725374d74a0b9eb32a738f2a23d0", size = 1474089, upload-time = "2026-10-17T00:03:41.715Z" }, { url = "https://files.pythonhosted.org/packages/21/97/897e33bef2eefd880e6350e375cc66bc5bcd00a139be480fd655f5b3f095/ast_serialize-0.13.1-cp315-abi3.abi3t-musllinux_1_2_x86_64.whl", hash = "sha256:0d764913374ba21df8cd618045b371ed104ce55c6276de7c59e554a4f5ba26fd", size = 1501542, upload-time = "2026-10-17T00:03:43.08Z" }, { url = "https://files.pythonhosted.org/packages/8d/4c/821211ac83870c27e4412381b7c7838336456b40575bf840e4680b2018d9/ast_serialize-0.13.1-cp315-abi3.abi3t-win32.whl", hash = "sha256:2bad302ae2427454ef9dab71bd5c3ad67188860c39d36daee38f72031edb39c4", size = 1126118, upload-time = "2026-10-17T00:03:44.616Z" }, { url = "https://files.pythonhosted.org/packages/1f/86/2b2d5e6c4fa352874a80618e742ffd32d249dee6c119f4233b51afc6b8f4/ast_serialize-0.13.1-cp315-abi3.abi3t-win_amd64.whl", hash = "sha256:032b09d86c785c3984e975378b7861f2a68ac44e22ba7b07b93a536b2524eeb8", size = 1163766, upload-time = "2026-10-17T00:03:45.986Z" }, { url = "https://files.pythonhosted.org/packages/77/a3/d610cfcdabaa44fd62a54ca1fc57a7dba120643798b089a14914973562de/ast_serialize-0.13.1-cp315-abi3.abi3t-win_arm64.whl", hash = "sha256:929eda0c419e622ab49df3a4c45f81c57dcc10874bbad55d0470a4a03324dac3", size = 1134043, upload-time = "2026-10-17T00:03:48.453Z" }, { url = "https://files.pythonhosted.org/packages/f0/89/0e30f9eddf7d44ccf9d25979030754fd0457af61fa4279acb8c293a04f97/ast_serialize-0.13.1-cp315-cp315-pyemscripten_2026_5_wasm32.whl", hash = "sha256:bf53a3ba1cbe45399fc1e4ccd684b8f2a11cca450f89706b79122f478534c6f5", size = 897546, upload-time = "2026-10-17T00:03:50.093Z" }, { url = "https://files.pythonhosted.org/packages/81/92/d705be88ff452b9ba0088b554a0cbd308fd01879da092b33fd2ad7d1aa60/ast_serialize-0.13.1-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:4bcf1d5f4eefecaa325a34ecf079b2741189e7d0821523f92cb343a389a67489", size = 1242416, upload-time = "2026-10-17T00:03:51.521Z" }, { url = "https://files.pythonhosted.org/packages/60/c2/98370845a7f35cb8a25782e78284b48e01bf3128339881d48d613f304f8f/ast_serialize-0.13.1-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1b158f1c9e3a0d386913924c57995d6df78224868a4d0f215bdd41587c97b34a", size = 1229729, upload-time = "2026-10-17T00:03:52.825Z" }, { url = "https://files.pythonhosted.org/packages/d8/8b/2d7ffed76addd9d3fcf37fb171400942735c8912264c763561a85407f6a8/ast_serialize-0.13.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77a6201b69ce42e919f2fd9a559138d5410b5d8afff7c3a6b1f500b0481ff7d8", size = 1292255, upload-time = "2026-10-17T00:03:54.148Z" }, { url = "https://files.pythonhosted.org/packages/6b/2a/bb9e0e719d89cc950fadfcfcc9cb4bc7640419c4228c852f031ab8abf440/ast_serialize-0.13.1-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6eb0be64c9b8f1ed26637eef345abe75ea90351c92c85a8aec7838b3af971011", size = 1298501, upload-time = "2026-10-17T00:03:55.559Z" }, { url = "https://files.pythonhosted.org/packages/7a/32/13ce07dce48226f5bd9cfd8f708ec101a8be05aa430cda4918ce31ce8c82/ast_serialize-0.13.1-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7f2427bddfca208e84de700044fadf9aef2769a70bae740a1bdabb89ee9e1117", size = 1553758, upload-time = "2026-10-17T00:03:56.952Z" }, { url = "https://files.pythonhosted.org/packages/e2/fb/9b51d186db0c20ca28cbaaefd50f03b573c89327b9a2627820cbce22196b/ast_serialize-0.13.1-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88df960e67184a71874e5b2ee014f87d1254a0dbc1f903c7bd7b1ab7733ecaef", size = 1318258, upload-time = "2026-10-17T00:03:58.418Z" }, { url = "https://files.pythonhosted.org/packages/c5/fa/da311559dd3dae9af5825cf21660775a929b970f72e3786af3f2cd667944/ast_serialize-0.13.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f99786e0d62082a5b121b3437f3167562133711df22128de1e9886f57f0b226", size = 1313260, upload-time = "2026-10-17T00:04:00.194Z" }, { url = "https://files.pythonhosted.org/packages/2b/11/97a4b9e5b4776d72f47fcd9a09a497bbf68ec8c1ae074307a2c51e410d85/ast_serialize-0.13.1-cp39-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:a01b515b25a03184eff4acef25b981ae007916379682e908fc8785b342a0bf3e", size = 1309992, upload-time = "2026-10-17T00:04:01.575Z" }, { url = "https://files.pythonhosted.org/packages/2e/c4/62f85121a80cd451ef04f550cf0f7ea0ad9ff46cc4e9a5b9ae439b6527b1/ast_serialize-0.13.1-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:29422d7bcd9e7f39411571c36cec45ce8a7a9b3ad4b2e7aa64497c15a9e397f6", size = 1362715, upload-time = "2026-10-17T00:04:02.881Z" }, { url = "https://files.pythonhosted.org/packages/c1/fa/c5f4a545f72a7681e3295bab6e3600ee0862ec4391bed961fe9f735b67e0/ast_serialize-0.13.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6ffb0f548a7dc126067fdfb7b2325ab5dfcdeecc29faf5e0f0461c96d6ebfa3d", size = 1469931, upload-time = "2026-10-17T00:04:04.181Z" }, { url = "https://files.pythonhosted.org/packages/38/a9/65aed4f8fa7a001a7cfdc03e68e844517ab041ba6fb614b7d78a1d6ac056/ast_serialize-0.13.1-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:2876444a5f87a7c76f371af3c07c2fda563a08bc8af52568df812e8aba4bf568", size = 1570945, upload-time = "2026-10-17T00:04:05.778Z" }, { url = "https://files.pythonhosted.org/packages/fb/8c/44b2da991cede79bfbf52089f33a5f0168945466b3d9cd38b5dcf08e7130/ast_serialize-0.13.1-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:885a62ec6481ce58ab24c6357360d7a82023b62dd7e5e7ceccf59e9662a3272b", size = 1569978, upload-time = "2026-10-17T00:04:07.347Z" }, { url = "https://files.pythonhosted.org/packages/46/e4/109b2a5beca700237767d5add920c2f8e1ba9bd5799b0faf143d0e9cf4ef/ast_serialize-0.13.1-cp39-abi3-musllinux_1_2_ppc64le.whl", hash = "sha256:2015fd0165e463aac3b1aadc6a1fa1e5820c14ca950821f4fe02f8a3f6a388d6", size = 1676082, upload-time = "2026-10-17T00:04:08.7Z" }, { url = "https://files.pythonhosted.org/packages/73/e0/7df70f6dbb11b5762da5416318f08316a1c51348e0d69ec79ca5f98f836a/ast_serialize-0.13.1-cp39-abi3-musllinux_1_2_riscv64.whl", hash = "sha256:eb41e1906502ac80d24ff343f45008552a3f5b5158607959fe6a07dbfc6eb037", size = 1483207, upload-time = "2026-10-17T00:04:10.162Z" }, { url = "https://files.pythonhosted.org/packages/1f/bc/523aa1c08bd69b5654621beb3dc1a9035715a4a63762fb8d219d6fb3eb81/ast_serialize-0.13.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ca9acc67f796aa2554fa3037dccc022a4b08b38b2ad153edfac9c9bb7cb1f3c6", size = 1512140, upload-time = "2026-10-17T00:04:11.589Z" }, { url = "https://files.pythonhosted.org/packages/66/83/6607060659998f00afdea0d8375c1e6e2b7d515ab905090d9a5a02f48851/ast_serialize-0.13.1-cp39-abi3-win32.whl", hash = "sha256:4f98da562e5901d69c7dd30885594c5438f859edf354e9ac7517d188fb026c3a", size = 1131889, upload-time = "2026-10-17T00:04:12.953Z" }, { url = "https://files.pythonhosted.org/packages/9f/6f/bafd6490fe7b355627fabe95f4417e3d02da93102c8552550eb9a0774e1e/ast_serialize-0.13.1-cp39-abi3-win_amd64.whl", hash = "sha256:ddf7cbc9c8abf70102c4a088efe154bb86bfb825b0a10e556d2b15972cf99bd7", size = 1171153, upload-time = "2026-10-17T00:04:14.362Z" }, { url = "https://files.pythonhosted.org/packages/11/25/4235f4b375a67a37ac595bf478a5407a744eaf7b64113c1c3a5432b8d954/ast_serialize-0.13.1-cp39-abi3-win_arm64.whl", hash = "sha256:48f11d96c9ec71119612f8e79a8c55c12f2b136716d68347433c561d27a25f43", size = 1139035, upload-time = "2026-10-17T00:04:15.767Z" }, ] [[package]] name = "asttokens" version = "3.0.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/25/1e/faf0f247f6f881b98fc4d6d07e14085cb89d13665084e6d6ac1dc2c03d0b/asttokens-3.0.2.tar.gz", hash = "sha256:3ecdbd8f2cc195f53ccada3a613538bb5f9ef6f6869129f13e03c30a677b8fe2", size = 63136, upload-time = "2026-07-12T03:31:49.084Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d4/2b/04b8a15f3a1c77bc79ddf5c73875327f34b4fa75982df2b76e45e402d364/asttokens-3.0.2-py3-none-any.whl", hash = "sha256:9da13157f5b28becde0bd374fc677dcd3c290614264eff096f167c469cd9f933", size = 28702, upload-time = "2026-07-12T03:31:47.542Z" }, ] [[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 = "certifi" version = "2026.10.19" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a6/bd/1436c50cc46699de0230fbaacc1d1de7bfec413176099949e9d5112e88f2/certifi-2026.10.19.tar.gz", hash = "sha256:035c1e85572b141bf1c3a3eff0e33a8eb74917522f2559075ff8d2fea780a1ae", size = 137598, upload-time = "2026-10-20T02:24:16.604Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/c4/51/29046e48f693c54e5b7412216d447a1d8362c9653148d98c02cdf65fa733/certifi-2026.10.19-py3-none-any.whl", hash = "sha256:42d35340cc5b9ba78e818ddbff0c5b1c2b779de448a340fd1b989f5fa8670e1b", size = 136464, upload-time = "2026-10-20T02:24:15.072Z" }, ] [[package]] name = "cfgv" version = "3.5.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" }, ] [[package]] name = "charset-normalizer" version = "3.5.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/33/1c/f41d4e74c28ab327ff3acd36053f7ea506c55872d7a90b0fa71aa3ab0c89/charset_normalizer-3.5.2.tar.gz", hash = "sha256:39de2a259fc954455c57274dc94c79d5842774e1247a016aff30bc0efed0f4ef", size = 172659, upload-time = "2026-09-30T04:39:23.398Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/22/67/6a0b94a7960d5e1b5eacd2fb529f3fccc47db4644f7f0a7cfdcfc3be578a/charset_normalizer-3.5.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3d21b8b13c7592db2ac5e544a6d83187b995257472b0c9e8351b6d507ae37ed6", size = 370642, upload-time = "2026-09-30T04:35:06.91Z" }, { url = "https://files.pythonhosted.org/packages/fb/94/01009e13b94041599004edf32e56e382c24e570f60f79bab8efe45cfe1eb/charset_normalizer-3.5.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d760fe2a4d7c3b226cb9026d6a842868d52a7901bd98420e1baf14e80da85cf5", size = 259280, upload-time = "2026-09-30T04:35:08.448Z" }, { url = "https://files.pythonhosted.org/packages/66/85/3b5358f60a13210f0b67d3755c168ef758701b021e655d88d4da28554467/charset_normalizer-3.5.2-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c9790464842f85f437dbbb54417eda1e0e6bfc52dd8d22d6fd1c994b73b2dc74", size = 245335, upload-time = "2026-09-30T04:35:10.104Z" }, { url = "https://files.pythonhosted.org/packages/74/75/77c1c479b09ecd751d1e767b251ea5c14d4d50ff757bf404afab2692f600/charset_normalizer-3.5.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4685902cf26edf013ed7a3da0f426ebba7a00ebb9541386d835afbf002c11cab", size = 291707, upload-time = "2026-09-30T04:35:11.575Z" }, { url = "https://files.pythonhosted.org/packages/0b/0d/363f78cacb70f58f15f4b083961bbd9d292f335d3f5c66fc4f1cfe69cb90/charset_normalizer-3.5.2-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4495c5002a7b28557e7e222e77e0b661183e432b7d6d2e788101e3f240e05b8c", size = 286747, upload-time = "2026-09-30T04:35:13.022Z" }, { url = "https://files.pythonhosted.org/packages/e4/ed/cf505d3011ffceb12c2067a7a5d3cfe92b875d4d44bb0ff0d69375e2c184/charset_normalizer-3.5.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:211d5a3eb6af8f513b8d4ca19a8c1b7accab1b5f0d3175f9826b03c1a920dc1f", size = 269972, upload-time = "2026-09-30T04:35:14.606Z" }, { url = "https://files.pythonhosted.org/packages/15/d8/f0a93a431d170e7ca681d4f6650fee3de934d18560e474e7267eb4b0f987/charset_normalizer-3.5.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ef4fcbf3327382cd4c9f540babd61248208af7b93eec4de397b4d5f58a09e288", size = 269339, upload-time = "2026-09-30T04:35:16.087Z" }, { url = "https://files.pythonhosted.org/packages/86/bd/9b2bd1c5b7af02462c9752d33994834ff972a96b4c483eefde9e594488e2/charset_normalizer-3.5.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd16aabe4a02a297c23417aa17ac6299dbd8c49f673bcd645b4929b11f5a4400", size = 261683, upload-time = "2026-09-30T04:35:17.488Z" }, { url = "https://files.pythonhosted.org/packages/76/a5/cac540ab0fd61f3fec88ad3dbb64509e71424593d73cfdfff5ab3e4db279/charset_normalizer-3.5.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:fb9e68df06293761f9fe66ade60a9bc6d0f5e42b8acf2939a9158af86ab0e5bd", size = 248143, upload-time = "2026-09-30T04:35:18.849Z" }, { url = "https://files.pythonhosted.org/packages/71/7a/ff467301deef2089fad87f72df9e000a26a78fec7acbb18e1999371b8369/charset_normalizer-3.5.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:59f63901b0031c3136cf64704dcb21de0bbae62ce2c9529bc39d27665463de37", size = 292358, upload-time = "2026-09-30T04:35:20.326Z" }, { url = "https://files.pythonhosted.org/packages/ad/77/22d7e785d1e210afc2e2f58600dd1799d17a35665faf84383f002826c5f8/charset_normalizer-3.5.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:304d5463e65a35d7bb0850550e0780395395f6fcf452f04db7d5ca7cecc425ac", size = 268766, upload-time = "2026-09-30T04:35:21.72Z" }, { url = "https://files.pythonhosted.org/packages/ae/91/e8e946267f1c2d9e2bd651726e2fbd2addf02c4d36cea5069e32ca9d7bb5/charset_normalizer-3.5.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9cf9b1a857e25c4baceeb3624e92a56df3668f398c4acba74e174d81fb4d1d3a", size = 287432, upload-time = "2026-09-30T04:35:23.273Z" }, { url = "https://files.pythonhosted.org/packages/4e/88/7561d8a88d555e7df6623abe7c0070b4baf47549b9408783a2ae0a1a6cf7/charset_normalizer-3.5.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:114e4d0c92d618409ed82a99e22b5c5e768fe995f2973f78265f4524f49d4640", size = 272470, upload-time = "2026-09-30T04:35:24.655Z" }, { url = "https://files.pythonhosted.org/packages/35/7e/578c702301ec036f01455f30744a08d2b42f6ab35b9b2d4bf8cae0ef2a80/charset_normalizer-3.5.2-cp311-cp311-win32.whl", hash = "sha256:2625388c6c754520c37abaf3b41eb34d1cc4a373f457898f08606c8e362b891d", size = 186688, upload-time = "2026-09-30T04:35:26.225Z" }, { url = "https://files.pythonhosted.org/packages/e8/fc/fdf8cf52ff21cd5bf158f20978991cf985325842f74283eb6df26c8a39d8/charset_normalizer-3.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:87e50a3e7cb90af586b6c5faf23e302a970415ac73bd7bd90a515a04b427ef96", size = 214932, upload-time = "2026-09-30T04:35:27.796Z" }, { url = "https://files.pythonhosted.org/packages/97/66/3e45a506d8110b632541faf9a9470185aa9878f1ed44020f31346c1c5e5b/charset_normalizer-3.5.2-cp311-cp311-win_arm64.whl", hash = "sha256:254eb48b9fa5ee9898a3c445825a1f340fe53712a098904b39b0bddba8ea3cb1", size = 202828, upload-time = "2026-09-30T04:35:29.259Z" }, { url = "https://files.pythonhosted.org/packages/e7/c8/693809898870237d82785a03f3b2b58fe4c9f14669f84a7d4e623c92a59e/charset_normalizer-3.5.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ed2a239c0ea213acc1908150a3037257083c7c083128f1a4cec2ec4b97dca491", size = 367780, upload-time = "2026-09-30T04:35:30.888Z" }, { url = "https://files.pythonhosted.org/packages/c9/87/2fea8c13dc24b3ca9c6f803a5b2dfdeae73eb4f9e12c7885ed908ff0433c/charset_normalizer-3.5.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b91363207bd9dc966a691e959bb47f64b30f7ac4b072be9968b366982f7db77c", size = 246730, upload-time = "2026-09-30T04:35:32.286Z" }, { url = "https://files.pythonhosted.org/packages/a8/9e/09efac30b937722f46d3110ba30b875b24b2e3a266ed746cc4e376a94d80/charset_normalizer-3.5.2-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:38a873987f3be698494da8b2e3085e29da02da7b633dce73e79c699a113d7bf0", size = 237707, upload-time = "2026-09-30T04:35:33.709Z" }, { url = "https://files.pythonhosted.org/packages/9e/18/70d76670b13686237863a379928d60bd10e021f17d243ab3d7014c4a5f4e/charset_normalizer-3.5.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:355ad8011081dec5412240c087a9a0c9d4d5039f3ed11a3f13e18c2b29b56c51", size = 273050, upload-time = "2026-09-30T04:35:35.138Z" }, { url = "https://files.pythonhosted.org/packages/54/e2/77a8b09d5adc013ed07b95b01b8b8fa5441c4e810e83ee7e4aae2fa4d91a/charset_normalizer-3.5.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ee21e28f0430bd6dc9086c6e525d5e818a44a5ad19720c8a0ef766792f3eb5e5", size = 270345, upload-time = "2026-09-30T04:35:36.502Z" }, { url = "https://files.pythonhosted.org/packages/7f/c5/38806a25ab5e65fc178f39affeda20858efafede2fce1ffc2556cfc9fe73/charset_normalizer-3.5.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3d31298449090ab8d47b7b1b2a555ff73cac7ed438a08b7ac160980c7ebed649", size = 257601, upload-time = "2026-09-30T04:35:37.919Z" }, { url = "https://files.pythonhosted.org/packages/ae/8d/213565184708fdb263ae55e2c04ee1ff748129dd65d48ed0e3502da9c85a/charset_normalizer-3.5.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5cde776b7cc66e4f6c99612cea4aa7269aa65863f7a15841b2c264f103822f4e", size = 252222, upload-time = "2026-09-30T04:35:39.544Z" }, { url = "https://files.pythonhosted.org/packages/7e/24/76d2cefc25472531e4c5c7dfff68865eb1c39b78482f0fdc15b46f047830/charset_normalizer-3.5.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ae4f5fea5b8b8ccff88238cc8569303e5ee95efae67fa62922a311397a71f346", size = 248482, upload-time = "2026-09-30T04:35:41.088Z" }, { url = "https://files.pythonhosted.org/packages/7d/dc/65a801b66ab4c197e22c433ab25e7ac24324ac6f45a2269aca42cce309bf/charset_normalizer-3.5.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:f7d486c83842422badd511868fd8a9a20e9407ace71564b6af47ce7e60a336c1", size = 241206, upload-time = "2026-09-30T04:35:42.59Z" }, { url = "https://files.pythonhosted.org/packages/a7/95/ca9b5eabde673002c6f1e7ada1b223916fe18f6d661da7aabd4d643718f1/charset_normalizer-3.5.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:11a4d68a6ecda3292cb1e50239e111543ba5d709bb62a6b4ea1afcfa729d8875", size = 273190, upload-time = "2026-09-30T04:35:44.347Z" }, { url = "https://files.pythonhosted.org/packages/2d/8b/803b4d2a3f6e1740f63f1e87b04d14b42f3d4fdfe6ed7d4db2d34102b14f/charset_normalizer-3.5.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d6734d2ef8a50fbf8445c139477da401f50d62a0606bf00e20ec6d87773fefb1", size = 253527, upload-time = "2026-09-30T04:35:45.915Z" }, { url = "https://files.pythonhosted.org/packages/a9/55/93c0e5dbd085ae0471346026abbe7e0db9ea2d6fea74e51f0b5a46f233a7/charset_normalizer-3.5.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a815775b6c38d4e0ff7bcffbeba67feded90202bb6a226b8dd35f1c855217413", size = 271285, upload-time = "2026-09-30T04:35:47.49Z" }, { url = "https://files.pythonhosted.org/packages/95/69/0dbd0e0b9b16cfa816cdfcb3e2e3854a1f680dc07fb1245ea125e7448060/charset_normalizer-3.5.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:23851fb4e1b85ed3f6c2a27b777cdfe2e19fb5b38429a8faf38c7542b7665869", size = 260010, upload-time = "2026-09-30T04:35:48.996Z" }, { url = "https://files.pythonhosted.org/packages/58/9d/e7b88e7b1bf403590c3b573277b5e1e488c68c7a6fbacca310a2c324e90c/charset_normalizer-3.5.2-cp312-cp312-win32.whl", hash = "sha256:db19d07e2e0129e974a0e65d0064fc222a446cd5122c2fd4184d2af9fc734a9e", size = 184125, upload-time = "2026-09-30T04:35:50.777Z" }, { url = "https://files.pythonhosted.org/packages/eb/e6/e6e083884cbcfd49c64865af05027fe7011be7b2d9179524f099a1b611f3/charset_normalizer-3.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:780fbe7cab297b81dad9fb8dc5eb003c0468ffb0d9e5f65068c53a34661a96bc", size = 207486, upload-time = "2026-09-30T04:35:52.194Z" }, { url = "https://files.pythonhosted.org/packages/c4/e3/017aea0911ada7405a825c7d937eb3a13009664e2f5b38e8c4bbf2abf894/charset_normalizer-3.5.2-cp312-cp312-win_arm64.whl", hash = "sha256:e2af3aad578aa6bd1384bcf4750fc285e5a9de53f40b7d41e5a0bf748edeb2b3", size = 196734, upload-time = "2026-09-30T04:35:53.636Z" }, { url = "https://files.pythonhosted.org/packages/c5/34/68292d68512768591aaff07c59bb53ee31341c87759433a859c4641a50c2/charset_normalizer-3.5.2-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:ed905975ab14056a2e5eb1c376cb2e1ebc5396baf84163939c518556fccde9f5", size = 225946, upload-time = "2026-09-30T04:35:55.313Z" }, { url = "https://files.pythonhosted.org/packages/e3/80/bee0b01b90ccd5322ae1d0abb33fab1bd95b7c2eadaf02aeccf22e04ee83/charset_normalizer-3.5.2-cp313-cp313-android_24_x86_64.whl", hash = "sha256:a66c3bc5ab1f0ff2164fc9965ddd611ff0802173f4b9d24554c563f6ab7e1d6e", size = 238619, upload-time = "2026-09-30T04:35:56.863Z" }, { url = "https://files.pythonhosted.org/packages/78/6e/60ce52a85a7fd631ae8482ae6d74521014ca2f255892679484dc04d7ef56/charset_normalizer-3.5.2-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:d2374b62878abb00cd8309b32af6c0b715cd02dec0ca74ef12e5069bdc64144a", size = 206701, upload-time = "2026-09-30T04:35:58.639Z" }, { url = "https://files.pythonhosted.org/packages/36/8c/71aafad23f971afc84c2b295bc0c560739ce1dac558aad9fec22e39f3639/charset_normalizer-3.5.2-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:d376bbd28b3a8999db1a103b3b388aee6f1ddeb3e51bc2172993efdcd86e064d", size = 210506, upload-time = "2026-09-30T04:36:00.147Z" }, { url = "https://files.pythonhosted.org/packages/91/da/3c5a7798c046df7d2d68ad653cf5b6c5a8bfee225055a843c6f2f42aac1a/charset_normalizer-3.5.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6045373d5a89a5ec71afde535db987ca28e76dfa276c2d4c818265b375d4b055", size = 366626, upload-time = "2026-09-30T04:36:01.77Z" }, { url = "https://files.pythonhosted.org/packages/e1/16/710ac3de2ee354e2bd1a9c94efe45a2d27b5c6ad39b2d6a905be2c094b6c/charset_normalizer-3.5.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:849df64e889b2e17230d58410a03dba311a65b163508fd33679b2b737d4b7858", size = 244624, upload-time = "2026-09-30T04:36:03.389Z" }, { url = "https://files.pythonhosted.org/packages/d6/39/45c7439f5b63d24f7d5b2a1d760f34af7628782d7144b4cc8ded45c2d4bc/charset_normalizer-3.5.2-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:15c44f7edfd477b06f517a5cc317fc1707edb9de2c865f43d4b6513907473234", size = 235731, upload-time = "2026-09-30T04:36:04.987Z" }, { url = "https://files.pythonhosted.org/packages/4d/34/38f3154785ce92e9f56eb226f4d35bdfae6b008480dd055f58837a89c810/charset_normalizer-3.5.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a89012d6d5476ee112d20d998570ed58df2260a852afb1758809cd6900411d21", size = 270352, upload-time = "2026-09-30T04:36:06.412Z" }, { url = "https://files.pythonhosted.org/packages/04/f3/859f74e7babc977705026b30593b3be04049632a522fb7000f83c033d747/charset_normalizer-3.5.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0c951d5e6dd9c2ff60609476752bee49da4206adde960ebc247766937f72e718", size = 267393, upload-time = "2026-09-30T04:36:07.865Z" }, { url = "https://files.pythonhosted.org/packages/4b/85/41d27f234b82e47c167a5f6c0f62501dc0c640585ff4aba79e08a390336a/charset_normalizer-3.5.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7218e8f32b0956cfcd048fd42d9d5779809745ca1d86113ca56f66e7ae1549c4", size = 254660, upload-time = "2026-09-30T04:36:09.248Z" }, { url = "https://files.pythonhosted.org/packages/58/ca/5d1a997587febe5b26d8daffe363b5c1a091cece19828eec6502fd09c5ef/charset_normalizer-3.5.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a19a731138fc27d5682277d3b9df22855cea1239bce7fcec5f78f42ef2d1f3c3", size = 249996, upload-time = "2026-09-30T04:36:10.73Z" }, { url = "https://files.pythonhosted.org/packages/b3/1f/d1e78246f7ed60c8c8d606b4ac27f66ce49cc3e95f24893ccbeba9f77302/charset_normalizer-3.5.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:62603db9a7caa0802eaa28c1c46fecd7b3a263a774069c24c3c28c302448721c", size = 247028, upload-time = "2026-09-30T04:36:12.294Z" }, { url = "https://files.pythonhosted.org/packages/8e/37/eba316edd4f0c4d3a5d945924c4eeeae59abac4056aa815d8a4268f863a2/charset_normalizer-3.5.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:b6856554c4f44d79fc2307d5768854310a8f0096e501c75637542c82292b0429", size = 240562, upload-time = "2026-09-30T04:36:13.887Z" }, { url = "https://files.pythonhosted.org/packages/c8/8e/aaa037d40ca9ef045977f1a661048b1aa33f223adfce3452fe9be9f79d14/charset_normalizer-3.5.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1bc0baf5ef96b6ede57d47f4b8fe4d9d84019c3bfcbeb20a41edc6a6ee341f1f", size = 271699, upload-time = "2026-09-30T04:36:15.41Z" }, { url = "https://files.pythonhosted.org/packages/26/19/1c1c9f75974adf523b87f34b8a2adc5a435cd65916812bcbd0dfa45f9a29/charset_normalizer-3.5.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:56bc200a365efb37383b7852e4cc5898d3b2da5987289b543956cf8cad71018a", size = 252030, upload-time = "2026-09-30T04:36:16.839Z" }, { url = "https://files.pythonhosted.org/packages/bc/90/0660ef18e18df0a4d2a1a0edff7dfbba42d4e50ef2425557a5bb7051f77b/charset_normalizer-3.5.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:2c9ad19a6cfcd5ea5c0d41161d22f9df1dcc277e9bef2751391334546a314c00", size = 268565, upload-time = "2026-09-30T04:36:18.468Z" }, { url = "https://files.pythonhosted.org/packages/79/ba/57adc269824e8658f1a0f97a9e514c247445a9632b3419b97e0ba37f16dc/charset_normalizer-3.5.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e243bd13217235fc7290c621941c3f5cc8b66e4872495be821d7436ba2fb838d", size = 257627, upload-time = "2026-09-30T04:36:19.938Z" }, { url = "https://files.pythonhosted.org/packages/9a/85/33abd4315c052d3d4f54c92b1ee49bfbc0dc7115a981e462a793b6d2ab87/charset_normalizer-3.5.2-cp313-cp313-pyemscripten_2025_0_wasm32.whl", hash = "sha256:a090bb2c68df85450502e3e20d665e3a5af9c65a84d6508ed477badd49166fd3", size = 143407, upload-time = "2026-09-30T04:36:21.376Z" }, { url = "https://files.pythonhosted.org/packages/4f/de/6435e18d1aaa5d910b896d551411c96af1f42a0c56c29afc2016c61ccc2e/charset_normalizer-3.5.2-cp313-cp313-win32.whl", hash = "sha256:2b7b3bbfb4fe8ef40600792d762fbaa9057559f9d3fad209525b7a22b99e91fd", size = 183207, upload-time = "2026-09-30T04:36:22.776Z" }, { url = "https://files.pythonhosted.org/packages/9c/76/b8ec57f4e9ee3253541abf95e4a462c0175fe8032dcd070f1f2421240942/charset_normalizer-3.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:78456a747de8dc58360ffa581f30a002baf5aa28cb262536545e91f113ed7639", size = 206489, upload-time = "2026-09-30T04:36:24.306Z" }, { url = "https://files.pythonhosted.org/packages/3e/60/c647c6ae47480221e875ea5d743ff94946f7416e3c69415ab772928e8d32/charset_normalizer-3.5.2-cp313-cp313-win_arm64.whl", hash = "sha256:11912e4bb14baae7c5d8791aa55ba0a3a03ec6729073307b0f57270abaa713d3", size = 195501, upload-time = "2026-09-30T04:36:25.846Z" }, { url = "https://files.pythonhosted.org/packages/58/ca/7aa91362a2f77ac8e9e28a9b902a74f7d0e11a851ef0d27a74308da8cd90/charset_normalizer-3.5.2-cp314-cp314-android_24_arm64_v8a.whl", hash = "sha256:1afb975bd5d68d5ce9f6b6d44fdf2f7e34b895a35e95708a7a91b20a3b51d187", size = 226010, upload-time = "2026-09-30T04:36:27.669Z" }, { url = "https://files.pythonhosted.org/packages/a8/cf/ac8878d0322cf88a1aad4c7b147db32ca0bd806eb0060957b2e31486dbe6/charset_normalizer-3.5.2-cp314-cp314-android_24_x86_64.whl", hash = "sha256:bbbfc8e28816f19d7c0f1816664980c0a9875d01b27cdf8eedddb639d9e108ad", size = 239266, upload-time = "2026-09-30T04:36:29.434Z" }, { url = "https://files.pythonhosted.org/packages/c9/6d/9a08d7e0b29b7208e2c6c01dc56c8e0520e7c7beadbbfb024b58fd69c8a5/charset_normalizer-3.5.2-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:7967d08cf06dee78443b874f98c98036f624f3a4e73e11f9f64f5be4d25393cf", size = 206783, upload-time = "2026-09-30T04:36:30.872Z" }, { url = "https://files.pythonhosted.org/packages/82/44/b0aa350280e6ff5a5492d17cf10460dd39d5ee848f872f7ba2df10607f60/charset_normalizer-3.5.2-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:4c2b5031f63e331e3839b40aed2dd6f191e9c07edbde303e7876846ea1946995", size = 210449, upload-time = "2026-09-30T04:36:32.625Z" }, { url = "https://files.pythonhosted.org/packages/7c/8a/40db9aa9f5907bb0e6f8b6d64064bf8852fb33d4b813ff9414911df7647c/charset_normalizer-3.5.2-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:fcff63213e8e6e47770541a4607175404f47cbb3ebea7b6058cc82d524a0e424", size = 367815, upload-time = "2026-09-30T04:36:34.197Z" }, { url = "https://files.pythonhosted.org/packages/7f/72/9c5e7707b57c8ddfa9ddf7b0b1d009d7fbab9e9e887d5b721060f37e307d/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8d86d6fc60743dc916eb79e2eb1ec4818e21e427731543af40a3021851174a13", size = 247095, upload-time = "2026-09-30T04:36:35.803Z" }, { url = "https://files.pythonhosted.org/packages/83/09/71e453691e927de4ddf792770cfaab3f49d494e222f66ea5e404bbd5e39c/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7a881931aa470808df94a8c380eed2bbbc76cd9dc622310f99665658c821eb6d", size = 233942, upload-time = "2026-09-30T04:36:37.407Z" }, { url = "https://files.pythonhosted.org/packages/9f/86/85c84e4da8b27dd409577d9437926ff581c5f9d3c66038dc68c1a526de51/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8024d00c3faf3fc0c16e07a69f4405e8eac7cc0ab15f65fe6cf43827c4cf72b4", size = 273762, upload-time = "2026-09-30T04:36:38.904Z" }, { url = "https://files.pythonhosted.org/packages/92/08/564955a4b5f2ccb410ab480bbe8c6a18063ff27f2d35458731c4a5335df9/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4d48f2d08b9de5864e2c8744d4461b862fb149a18274abc8b698c45975573438", size = 269514, upload-time = "2026-09-30T04:36:40.469Z" }, { url = "https://files.pythonhosted.org/packages/18/24/bad3ac4271589df29cf5ce2f5ae490518a5739358052bd0d61209e6fea54/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34276fd796040bf0993ab33a369aa572e6979c7aab225a88893667ad8eac8f7a", size = 255056, upload-time = "2026-09-30T04:36:42.02Z" }, { url = "https://files.pythonhosted.org/packages/d6/3e/350d89ad49916b86554d6f5f2d03ec1152148f87e5ff735106c6a03b1a36/charset_normalizer-3.5.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0521c5665880b33d603717defa76c094048900010897909952397feb3039da56", size = 251311, upload-time = "2026-09-30T04:36:43.577Z" }, { url = "https://files.pythonhosted.org/packages/56/5b/4970a2d154df502e133402906dd04e3ae7cada7b3011283c88d0479a2585/charset_normalizer-3.5.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:eff0ac9dbe711a4aee69bf04a83896aa9b85f19641264053a9f6d48573abb7dd", size = 250190, upload-time = "2026-09-30T04:36:45.185Z" }, { url = "https://files.pythonhosted.org/packages/88/8c/f1a91bddc8fb47c2889e29ea7ea49a194eb0d9868675d786806519c00d76/charset_normalizer-3.5.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:1503bccbeb36d5527790c3930327704c39af22de3112f1b1666a9f3ce15ee204", size = 237098, upload-time = "2026-09-30T04:36:46.689Z" }, { url = "https://files.pythonhosted.org/packages/24/0e/bb5dace3cc7e79068425386a6589c19b5a2ab5fefc2a46abea6919683332/charset_normalizer-3.5.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:52aa6992700996af31f375de0c6bacd402b0097fe40b53c426b9f51a90ebabc7", size = 274228, upload-time = "2026-09-30T04:36:48.31Z" }, { url = "https://files.pythonhosted.org/packages/9d/79/b849ad523017ea9f5a45581bbebed91439e0cf42fd2860a6f64e358eb5a6/charset_normalizer-3.5.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e09a3942ecbdee5cce73ea9d42da82b81b72ac1bf031ce069b93b5adf4eac8cd", size = 252401, upload-time = "2026-09-30T04:36:50.091Z" }, { url = "https://files.pythonhosted.org/packages/89/8c/75469d690cf47200bce8f6cad7655724fc23148e147abfc5ce78b5f65863/charset_normalizer-3.5.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:c7c9ab723cde841fefb34efbad91e87f00a674b1fe1cd0784fde742bf2c154dc", size = 271846, upload-time = "2026-09-30T04:36:51.719Z" }, { url = "https://files.pythonhosted.org/packages/26/cd/6d52d3c7437cdcf2e310ce9f28f282e733d4ef60ed19105d1819c356255f/charset_normalizer-3.5.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ddc7dacc8ece3a182e7f15cb862d1fd616b46d076cb1ae9dd232b2c38b655874", size = 258151, upload-time = "2026-09-30T04:36:53.234Z" }, { url = "https://files.pythonhosted.org/packages/f7/4c/070b38bdb5f49a70199fce923ec0726a49536a63ab262abbfcaaf351110b/charset_normalizer-3.5.2-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:ee43c17b173d46a3212baa6ead3ae258eeabdae48c263a01ccf0218c366dd655", size = 143570, upload-time = "2026-09-30T04:36:54.816Z" }, { url = "https://files.pythonhosted.org/packages/81/84/9ebfc8ed6c8c4fcd8e726ff6bf220cc8deb3966e31dce9be8dd8aa017e64/charset_normalizer-3.5.2-cp314-cp314-win32.whl", hash = "sha256:4f87960d57feabfb618e4e0af6e7371645fa26a277860739d6e5d6e0012c92f0", size = 186412, upload-time = "2026-09-30T04:36:56.643Z" }, { url = "https://files.pythonhosted.org/packages/d1/78/5ed86f743d4bc350db307e7636419a0a5ee1d91806d30c7f667bd5c80dae/charset_normalizer-3.5.2-cp314-cp314-win_amd64.whl", hash = "sha256:e4e81e09c1578b8df602e3db08b0b3ea0a6947ad612f52bf8dc5ea8d47691f0c", size = 210965, upload-time = "2026-09-30T04:36:58.205Z" }, { url = "https://files.pythonhosted.org/packages/53/94/a3a7698e9b1a395e1eb99ccd9a324be9347973bff4e72db2a06496d7cd27/charset_normalizer-3.5.2-cp314-cp314-win_arm64.whl", hash = "sha256:80d02b6f04e92601a081dd97b23d3128033098bff5d35d392ddcc0476ea11253", size = 200406, upload-time = "2026-09-30T04:36:59.764Z" }, { url = "https://files.pythonhosted.org/packages/c1/48/c5dd00d5ef7791f02666de250a5bb6071e29b7e133cf4b835800b6d3bc27/charset_normalizer-3.5.2-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:dca9ab98072a5a54ebacebdc45f53e645336b320c667410b061be1ca588ae709", size = 396871, upload-time = "2026-09-30T04:37:01.543Z" }, { url = "https://files.pythonhosted.org/packages/12/c8/8379554b42e8368161d898476686947a0fdbd3e8865170d7909dcabfdee8/charset_normalizer-3.5.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f0aa869112ef88429ae17820d99c3dd9504c9e9c671d3c246f3d7442cb051084", size = 249711, upload-time = "2026-09-30T04:37:03.111Z" }, { url = "https://files.pythonhosted.org/packages/4a/eb/2ddb1035d17320caa9f41682935123a9a250277b261c3efc86b2d2a21343/charset_normalizer-3.5.2-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c0afc6800ba57ccc350374c5bd6150419915d95ce93cdbab2d783d75eaf30ecb", size = 231146, upload-time = "2026-09-30T04:37:04.721Z" }, { url = "https://files.pythonhosted.org/packages/4a/24/2ecb4bde104322cd7859d6594fcfa74649f8d90b3221c9feecbef149875b/charset_normalizer-3.5.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7dcd882da75ef9adf94903b1e3b9419e8aa8fb4c7396822b834b9ef7fb96954f", size = 271552, upload-time = "2026-09-30T04:37:06.295Z" }, { url = "https://files.pythonhosted.org/packages/3f/98/9d5f6ebc3aee9fef5d30b4aff11fb2ab7a1222b4064f8ef2c7c87cde217a/charset_normalizer-3.5.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2e06a3a98f916dd41d27f3105e02e7a40181c98c94b9158733d03a6f80506c09", size = 269810, upload-time = "2026-09-30T04:37:07.905Z" }, { url = "https://files.pythonhosted.org/packages/09/e1/a3b06a10461b1b7628853c934c644e03bc28e42767116afb52f19a56519b/charset_normalizer-3.5.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6bd128f206a7752ae1f2ab6c61bf8a24ba28913a10df8b14c2637b973ff97a80", size = 259845, upload-time = "2026-09-30T04:37:09.554Z" }, { url = "https://files.pythonhosted.org/packages/fd/d3/6f561f74a296cf27d61775a1dc665ad13f3bff6a798810ca05907f37a7c4/charset_normalizer-3.5.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c8f3d67aeaf55f017982b73683f0e7342ba2f6635a78f69ce89ebb26aa411e5c", size = 252825, upload-time = "2026-09-30T04:37:11.274Z" }, { url = "https://files.pythonhosted.org/packages/26/9f/69e13ca3b18f43e0eafcd34c04a45b732ae22a43b54a5fc9e119103356eb/charset_normalizer-3.5.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fe9753dfee015c570d73df76f899f18444d41388bffcde097deba51c4fadbb9f", size = 252659, upload-time = "2026-09-30T04:37:12.941Z" }, { url = "https://files.pythonhosted.org/packages/73/a9/ace29806a0dae18939919c76ba526472d83214afa101105fabff2cf30625/charset_normalizer-3.5.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:92888bb3187c5ba50500b00b3b310c9f2c651709d28036077680cb5255450a03", size = 238819, upload-time = "2026-09-30T04:37:14.659Z" }, { url = "https://files.pythonhosted.org/packages/f8/c1/6116d52a2e3311ec80f21f5fb5e17b27405f10b9608af8f6e69516841a1b/charset_normalizer-3.5.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:d008d90a7f2471519aef0c90dfbe73b3e6e4d5e66ac48e19154c17e89e98b604", size = 272973, upload-time = "2026-09-30T04:37:16.346Z" }, { url = "https://files.pythonhosted.org/packages/19/aa/9955c7e93bba10a9c7e8f7a5031b7ced66f3a1883a55c00712b8d5850ff3/charset_normalizer-3.5.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:31f3930700408d211f13378ccbe1c40845d8da54bd0681fac3a9b5aae81c7aa8", size = 253692, upload-time = "2026-09-30T04:37:18.212Z" }, { url = "https://files.pythonhosted.org/packages/bb/33/2a6ae7fdc1b10cb581cef91addd8cdfc5f40d50abb5702309369d5834579/charset_normalizer-3.5.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:2a925889534b3748302dae5dead07cc13480de1dac3aea80a941b729b471ef93", size = 268757, upload-time = "2026-09-30T04:37:19.877Z" }, { url = "https://files.pythonhosted.org/packages/a2/22/80992720a0282cd39bba1db35868e6b9c22f41281160143a836544bc1d8a/charset_normalizer-3.5.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f5ec61164adcec446f8969a3358ec3f9b26bbda3b9213e5586d219afa8df2915", size = 262220, upload-time = "2026-09-30T04:37:21.583Z" }, { url = "https://files.pythonhosted.org/packages/92/9f/181fd07e1bffea1d95cd80c84ac537354f50699c22cfc4d3c02b6fc16208/charset_normalizer-3.5.2-cp314-cp314t-win32.whl", hash = "sha256:598a11a2c7ebaa5334bf698bf29568c9c390abac6a154d8170fedecd1cea38c5", size = 197797, upload-time = "2026-09-30T04:37:23.235Z" }, { url = "https://files.pythonhosted.org/packages/49/1c/25d8415ec1c4f2f41f1680435e4c87cfb378ff2f677d950946f2a45d0632/charset_normalizer-3.5.2-cp314-cp314t-win_amd64.whl", hash = "sha256:7fdde2c9fd9e3eca40631e024664cf2584272cc8f96308cbe5fdfc930f51d8bc", size = 222765, upload-time = "2026-09-30T04:37:24.891Z" }, { url = "https://files.pythonhosted.org/packages/3e/b4/46b48f013dadfc0d0d33b375438e31bdf5a989dc68389c6bf627054d4df9/charset_normalizer-3.5.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d1befeed746d247c81127bb14de9dc3d30edb6e5976d34f83f86ed262b1d9105", size = 210985, upload-time = "2026-09-30T04:37:26.634Z" }, { url = "https://files.pythonhosted.org/packages/ca/e9/34e597dee616d0b8ee4b34d29399e85c2204ade174157a48505d42baa4ff/charset_normalizer-3.5.2-cp315-cp315-macosx_10_15_universal2.whl", hash = "sha256:87475fabc8d9996fd9c27debb395e642e8c838d78a00b6e932227a0e06b81e26", size = 367676, upload-time = "2026-09-30T04:37:28.329Z" }, { url = "https://files.pythonhosted.org/packages/60/9f/a5d1c91c0263745e2cd344c5a4415d787c575501ab1d449f1148ac6b495d/charset_normalizer-3.5.2-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9409a8bf35cf78353942504b24a57de3d75b708997a1e4bd8db71ac8633ce364", size = 248414, upload-time = "2026-09-30T04:37:30.167Z" }, { url = "https://files.pythonhosted.org/packages/26/79/e697f77464748a3ee3cf490c83d592459400d4898380d66c38366b03080c/charset_normalizer-3.5.2-cp315-cp315-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:498dc3188ca05a68231ac3fdbfc7f57eb67e1343c30e0fea17f8218c1599b253", size = 244775, upload-time = "2026-09-30T04:37:31.964Z" }, { url = "https://files.pythonhosted.org/packages/ca/87/3d42a42e18ea066e2513936fd678a00696e77878b5ae04528976abdbcb83/charset_normalizer-3.5.2-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e242bb1c5e76e97dfa9e7f209a71e93a01d7f19ffdd5cfbb2e2d55b4f08f8ab0", size = 273877, upload-time = "2026-09-30T04:37:33.661Z" }, { url = "https://files.pythonhosted.org/packages/c3/76/8a28136f3938ba9836f84280ce0c4d61ed1cf15a036b2034900c62634162/charset_normalizer-3.5.2-cp315-cp315-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:def79fa35ef0cef8d2accec024f4fdc7ead3012ff02f5215c783f39f03ef8cfc", size = 269455, upload-time = "2026-09-30T04:37:35.573Z" }, { url = "https://files.pythonhosted.org/packages/a0/a1/4fbf5d0f0f1b2a080474c1cf9a2f12c4c6531bb0e8ba591055e846d2b4e9/charset_normalizer-3.5.2-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3df041de8887954562c9b261cba85ca0e9ded74048daf125f45edcfaa4832229", size = 257336, upload-time = "2026-09-30T04:37:37.397Z" }, { url = "https://files.pythonhosted.org/packages/ba/a2/8b50aa320adb880ad579518e6f718f24944804b42a88b83d267d5d444125/charset_normalizer-3.5.2-cp315-cp315-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:04851f73ae72b8413dddadb16a49dfee95263553741fd42d546f7d66907e6be5", size = 257584, upload-time = "2026-09-30T04:37:39.522Z" }, { url = "https://files.pythonhosted.org/packages/a5/57/50e3fed84e175f40349bd0da7a4fce94c87f0378f52d74f511d89e0bdc20/charset_normalizer-3.5.2-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:183b88127acdb4fabe59d951ab424faf1af7b63cdbb5f776186c1ea2ffcaed98", size = 251854, upload-time = "2026-09-30T04:37:41.23Z" }, { url = "https://files.pythonhosted.org/packages/d6/54/f7fbb3493c9f49091213b9c2d6dd65800696f1ce1a3f196a4205f50417b1/charset_normalizer-3.5.2-cp315-cp315-musllinux_1_2_armv7l.whl", hash = "sha256:16fa0eccf81304b79c5cd87f9271c3b85dd9dd99245e4422ae9c0dd45e0f99d3", size = 248767, upload-time = "2026-09-30T04:37:42.883Z" }, { url = "https://files.pythonhosted.org/packages/d9/37/b3a6385acc5a1e45b39ae9c90bfb9cf838a09b9dd37ef2740ab4c6b4a2eb/charset_normalizer-3.5.2-cp315-cp315-musllinux_1_2_ppc64le.whl", hash = "sha256:7441d755b7ab94f8d4eb3e43ec05482d760842fd263d003a99102d742cd835e2", size = 274479, upload-time = "2026-09-30T04:37:44.658Z" }, { url = "https://files.pythonhosted.org/packages/89/44/809913e2cfd279e635a9294fdbbfb1b1dc62a8189d473d561f649fce98d8/charset_normalizer-3.5.2-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:ca403d7e4798f525fdfc78e258820419cbbd0f0ecbab9de7840e3c017cf6b8cf", size = 258310, upload-time = "2026-09-30T04:37:46.529Z" }, { url = "https://files.pythonhosted.org/packages/af/a2/f28400ab13359d91bd39179df8e149376b9bf36588e739a3a4f9de2b84b2/charset_normalizer-3.5.2-cp315-cp315-musllinux_1_2_s390x.whl", hash = "sha256:df29a0a7107f7011e77f4eebdddec4c7331e24d787a0b21a46d63bdf7445da95", size = 271100, upload-time = "2026-09-30T04:37:48.399Z" }, { url = "https://files.pythonhosted.org/packages/e9/89/9bab37955edf0adb3b66f8a3a6617d9f2f487e0d56f295a6a286cb640aa6/charset_normalizer-3.5.2-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:f3c96f633825733f735c5a9cf21d21a257d8e1edf0b1cee0a064b9c424ca0f7d", size = 259936, upload-time = "2026-09-30T04:37:50.023Z" }, { url = "https://files.pythonhosted.org/packages/23/b5/4459e08d45a679f903d50fea08bc52cfa728cca4d7bd02c757b5e5abda2e/charset_normalizer-3.5.2-cp315-cp315-win32.whl", hash = "sha256:281cb91036248400f4cc957495cccd44c275c2e0c5854f7e45ac5cf7dc193847", size = 186301, upload-time = "2026-09-30T04:37:51.722Z" }, { url = "https://files.pythonhosted.org/packages/98/e8/55d5fd3935b4bce6da4fe0df61898e8c82653e317e677bd58aceb9c60f13/charset_normalizer-3.5.2-cp315-cp315-win_amd64.whl", hash = "sha256:89b53f3cda69831909888e0494f4fa0bcd3537e3e138dabeb620bd6ad946bae8", size = 210858, upload-time = "2026-09-30T04:37:53.427Z" }, { url = "https://files.pythonhosted.org/packages/a9/5b/974423c2fd8e524c7a7f64318c1e02240ef954912fa2b4d70344107b9c68/charset_normalizer-3.5.2-cp315-cp315-win_arm64.whl", hash = "sha256:6be488a102b8cf28d0391d8c4ba7748938ae28b78ad901f8585520fca33ead1a", size = 200309, upload-time = "2026-09-30T04:37:55.015Z" }, { url = "https://files.pythonhosted.org/packages/ee/f9/00ee0195db1013d8f7c416fd770fbeb560bb46eb2e36b054d05cb56f6cfa/charset_normalizer-3.5.2-cp315-cp315t-macosx_10_15_universal2.whl", hash = "sha256:915563965d418f986e7e145accc592eae9e1a1be3566ff98a05d7a9ec42a76e1", size = 395343, upload-time = "2026-09-30T04:37:56.743Z" }, { url = "https://files.pythonhosted.org/packages/04/3a/c00b50e94c964cf934c7899cd47c97952fc11dad71cc5884b3c61795b09b/charset_normalizer-3.5.2-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:65cd72beeeca9d3aaea1201e5923859f308f952f9c71de93f06063c79f0f7a3b", size = 250114, upload-time = "2026-09-30T04:37:58.607Z" }, { url = "https://files.pythonhosted.org/packages/50/27/d102dc880bbcffd0479ab64dfc1fb96777a854355a55e2bda72a71efadcb/charset_normalizer-3.5.2-cp315-cp315t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b7fd005a73d9e657273b7a10dc71a9e03c8fb9ee6999798d6918ce095b81ac7f", size = 239997, upload-time = "2026-09-30T04:38:00.511Z" }, { url = "https://files.pythonhosted.org/packages/a5/4a/bf7ef45794dd293fab5f98a9309817977fbb845b9998f171b8cc5d8437a3/charset_normalizer-3.5.2-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e54da4baf05720032d527874d40b65fa4d7e5c6c6a43d0c3adbeffcaf275a2b3", size = 272313, upload-time = "2026-09-30T04:38:02.509Z" }, { url = "https://files.pythonhosted.org/packages/e8/ee/008a2837737991474c5754bb3191010007663860979701990982a502cbaf/charset_normalizer-3.5.2-cp315-cp315t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:124fbf1a8ff966d87ae05bb8bd45a71f966055ed8bba320d0c7cf450bc5f4d0e", size = 269986, upload-time = "2026-09-30T04:38:04.435Z" }, { url = "https://files.pythonhosted.org/packages/93/ad/bd74a283940dc910c5b14f8e4f80a248082bc9c0fcbe1f54530cb6d9cc5e/charset_normalizer-3.5.2-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:28b4f0d66fb834ff90f28209ac7bce77868c45d8c93e26f906709d9b7c2e1af9", size = 260202, upload-time = "2026-09-30T04:38:06.549Z" }, { url = "https://files.pythonhosted.org/packages/8a/7b/ed341c66f69f688723501fac752be3d63c7159ca0d0d4174fc611e5710bb/charset_normalizer-3.5.2-cp315-cp315t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:58ca3755ee7ff7f59b57789ec9833c9de9ea275405cdd240eda1f193112e398a", size = 259083, upload-time = "2026-09-30T04:38:08.311Z" }, { url = "https://files.pythonhosted.org/packages/cc/9d/e41588b777965e5031a43128a1e96173ebb35ac75fc53ec3b517e7c21cd4/charset_normalizer-3.5.2-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:443eae2bf318abeaf6f15d785138f71fd6de770e99a92158b8b814265e079115", size = 253081, upload-time = "2026-09-30T04:38:10.402Z" }, { url = "https://files.pythonhosted.org/packages/81/35/b761eb6d8c1eb218b9b42b9b4d5ac902afdc399fb6dac6f9a9aac7bda589/charset_normalizer-3.5.2-cp315-cp315t-musllinux_1_2_armv7l.whl", hash = "sha256:58f361dcbab699cf8f42db3f47c8e7fd1036f138c23a5d08de9fde5f425a730c", size = 248712, upload-time = "2026-09-30T04:38:12.317Z" }, { url = "https://files.pythonhosted.org/packages/4d/2c/147169a041b747759f37405c0a97157e8e92de967968373101ff14915cba/charset_normalizer-3.5.2-cp315-cp315t-musllinux_1_2_ppc64le.whl", hash = "sha256:1b4cbc7c3491ccb4aa17fcd8165649d01cf39f76de1696da8631b5f71b85401d", size = 274176, upload-time = "2026-09-30T04:38:14.138Z" }, { url = "https://files.pythonhosted.org/packages/f0/2d/0ff8db0d373ba8538db686db11cd7e8912031490b9e4f383b41912e8d594/charset_normalizer-3.5.2-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:ba0b1d2620edf869789c3879223f52bf2afc5d31b3cb47cc57b3a12c05e2aa9d", size = 259413, upload-time = "2026-09-30T04:38:15.841Z" }, { url = "https://files.pythonhosted.org/packages/8a/8e/b4a085fb47c9d3a7e43576a4784fdd8fe23f907514a972de8086edaf7a48/charset_normalizer-3.5.2-cp315-cp315t-musllinux_1_2_s390x.whl", hash = "sha256:5e2b6b57e9733d39f0c9fd3185efa6b8e29652c4cd8fe94180272cf6ed9a78c4", size = 269434, upload-time = "2026-09-30T04:38:17.626Z" }, { url = "https://files.pythonhosted.org/packages/83/1c/d8d8d7322a7c3eecdf3237a4a419cf41d2eaad8e006ce7dfdd9d4c8fa2eb/charset_normalizer-3.5.2-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:51cf45226a9b588d0d2b4880c62d686934b63ab0bd79ca23ab0e9762eb27441b", size = 262716, upload-time = "2026-09-30T04:38:19.214Z" }, { url = "https://files.pythonhosted.org/packages/a0/16/0e4c6ba9b44e97a2da150e52d331e8f9c968b21b358fbffa6c856cebcd89/charset_normalizer-3.5.2-cp315-cp315t-win32.whl", hash = "sha256:5fb29fb8cd1a46c27a1bf9613ad5ec2599310d46b4025d9556404a6b6a292800", size = 197159, upload-time = "2026-09-30T04:38:21.037Z" }, { url = "https://files.pythonhosted.org/packages/be/33/e90bc2b1374f7f36ef106f56620de5a783907e19ca857efe2277e31cac3e/charset_normalizer-3.5.2-cp315-cp315t-win_amd64.whl", hash = "sha256:a192e2c40070d92c3ccf777e3a5c4ff515573cd2bb7ed0c537fdadbbec5bbf21", size = 221322, upload-time = "2026-09-30T04:38:22.886Z" }, { url = "https://files.pythonhosted.org/packages/66/89/dfa6dcb08c200b7830ab56439e8c1890f2971d51aafbb3937894a2e7fcfc/charset_normalizer-3.5.2-cp315-cp315t-win_arm64.whl", hash = "sha256:749e97e1b32313717a565abbe321bc2190bc8b35f1a67e4cdbc7c56c8d8ffe58", size = 209192, upload-time = "2026-09-30T04:38:24.648Z" }, { url = "https://files.pythonhosted.org/packages/8c/ab/176fbfd5b64939c55d652366aa5b9ef1d767af207a3aa6ebeb0d226c484d/charset_normalizer-3.5.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:4275811936e2f06feff5e598fb42a1b7ae852da8e39605211892b56b81a34efd", size = 331815, upload-time = "2026-09-30T04:38:26.216Z" }, { url = "https://files.pythonhosted.org/packages/7e/84/371eac6b30bdbcbf2d632a1a01809103459216fcaae61b8b8d922c1bfb8a/charset_normalizer-3.5.2-cp37-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1c50fe28bbc2ced33386f298650d91218076c05420e6cbd790b913adc41659e7", size = 253276, upload-time = "2026-09-30T04:38:28.032Z" }, { url = "https://files.pythonhosted.org/packages/43/6f/c4fbae58febff71709c51bc7e18fdfa55341dc382704740f9f0cbf03817b/charset_normalizer-3.5.2-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d19fbd981a488e22cd04883659ca6b08f50b5974f9fd7c95655ef6a043e5893f", size = 241239, upload-time = "2026-09-30T04:38:29.732Z" }, { url = "https://files.pythonhosted.org/packages/61/71/458c3f42164a07d0c5210798e9e704b39e540a6793b05aba67f3a35243a9/charset_normalizer-3.5.2-cp37-abi3-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0fed1d06615f022ee3b13caf5e8b180cfea32bb2c5aded8a9d44277afc040f93", size = 231121, upload-time = "2026-09-30T04:38:31.462Z" }, { url = "https://files.pythonhosted.org/packages/09/54/ab9e89367076f6331bb6c65c4bf14a5361fa5191cb6561bf534f18504e1b/charset_normalizer-3.5.2-cp37-abi3-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:838dcc90063569a0448120554591a1d6c4a4ffe11babf048908793154ab86ade", size = 260350, upload-time = "2026-09-30T04:38:33.239Z" }, { url = "https://files.pythonhosted.org/packages/7c/c1/061431ecc688d9d76602502cb57cc01e691e682c18f1beb45f9673b5bbd2/charset_normalizer-3.5.2-cp37-abi3-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2ce45c6627b22c47e390bc91a41c3d13032192e699fa0bea96e9671b373d69b0", size = 255430, upload-time = "2026-09-30T04:38:34.865Z" }, { url = "https://files.pythonhosted.org/packages/8d/1f/20c8949f0676f7ab811abdeb7f4d7f1cbc6e61ff20bef08b44edeb092bc8/charset_normalizer-3.5.2-cp37-abi3-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0774bf9bf620249fee3e0b8b9fd3065de213be30f3aa94ce2494b3b638949e26", size = 250612, upload-time = "2026-09-30T04:38:36.649Z" }, { url = "https://files.pythonhosted.org/packages/2b/9e/46f2fa4c431fc98c4ae76a8cb5bdca54e0341e3cfc3fcfd8e82740250818/charset_normalizer-3.5.2-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1db38f4c5496827c1a501846d64d14c3b80c7e6714e406cd7dc36a9899fa1011", size = 242083, upload-time = "2026-09-30T04:38:38.26Z" }, { url = "https://files.pythonhosted.org/packages/bd/39/559be29a0c0f086e0bba6922babd38916cc5e0b58ced4de13ee01ea05508/charset_normalizer-3.5.2-cp37-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:304d8e4d493af723536393eee0c689eb7813f4a474c8b479dee63f1fdd98f621", size = 232738, upload-time = "2026-09-30T04:38:39.81Z" }, { url = "https://files.pythonhosted.org/packages/ff/6c/387b0e4f756a282831c1d9fc6aeb6c51ca4507ca202767c8de15ce9b12e2/charset_normalizer-3.5.2-cp37-abi3-musllinux_1_2_ppc64le.whl", hash = "sha256:9b7f416ff0978e2f2249330527f0ad6fa02f4932e6199692d3b52da2048c19e4", size = 260703, upload-time = "2026-09-30T04:38:41.346Z" }, { url = "https://files.pythonhosted.org/packages/96/92/1fdf015f09ef449f50d3ac4b67c90887c9c318b727daa95cc4f866e6521d/charset_normalizer-3.5.2-cp37-abi3-musllinux_1_2_riscv64.whl", hash = "sha256:01077390b03f7988f11d700a2194e69b119741a86b1a638b1db88891e3eced8e", size = 247622, upload-time = "2026-09-30T04:38:42.937Z" }, { url = "https://files.pythonhosted.org/packages/dc/3c/8e7b8a5671ad5d433669fb2a76f1a0164df2d9b1718b0206bc2a16d840cc/charset_normalizer-3.5.2-cp37-abi3-musllinux_1_2_s390x.whl", hash = "sha256:7e841fb9010836c992c9f12fcbd43a831de93a5f726fc1ccd8ca1d0268c5014c", size = 257500, upload-time = "2026-09-30T04:38:44.604Z" }, { url = "https://files.pythonhosted.org/packages/b4/f0/45b579df5cabc1d5d53ea1cc35e8437d3ca768c0acccc7041517cb6fbb32/charset_normalizer-3.5.2-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9cae88599c7219005d879f98e5ed53341e9a122af585e1091200358a3003d2a0", size = 255100, upload-time = "2026-09-30T04:38:46.289Z" }, { url = "https://files.pythonhosted.org/packages/31/68/fdec18a343f5fb3f310588dd478b09ac4799e0b187dbade3a8cd776f03ef/charset_normalizer-3.5.2-cp37-abi3-win32.whl", hash = "sha256:01b0c0d2262a9e28e8484a278c7e1b5d650e3ac8cf2683d2967e25899f208bdf", size = 174499, upload-time = "2026-09-30T04:38:47.999Z" }, { url = "https://files.pythonhosted.org/packages/9d/8a/b618149cc5207943a0242068d7a27897f56a62947b5a039085f2a22029f8/charset_normalizer-3.5.2-cp37-abi3-win_amd64.whl", hash = "sha256:9f56f72050826f63dcee7a7f55b0a77168cb3bfc553fd405e7f8f9ece75a4036", size = 200092, upload-time = "2026-09-30T04:38:49.707Z" }, { url = "https://files.pythonhosted.org/packages/03/cf/4c66866fa9e2b1c78e3c911516d1de497a677b7ac60f1eceda74ce777ca3/charset_normalizer-3.5.2-cp37-abi3-win_arm64.whl", hash = "sha256:40ab6bffa02ae10a0581e6c198be7d2d8ca5c2a0c64e4ed3465d766df457573e", size = 294363, upload-time = "2026-09-30T04:38:51.312Z" }, { url = "https://files.pythonhosted.org/packages/fc/ad/d07d7862a62ffa6d79d68074d14823243dd235a77c45262acbf6adeb28bf/charset_normalizer-3.5.2-py3-none-any.whl", hash = "sha256:b6b751274acb69d77b3323d6b7dbaa3c7fdfc1eb829b7eb61d262f32e1af9685", size = 68872, upload-time = "2026-09-30T04:39:21.828Z" }, ] [[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 = "coverage" version = "7.16.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/2f/55/d1eaf3e73781174340a00dc1ba2aee8a65f82fadb18e2797b192b6b3925b/coverage-7.16.2.tar.gz", hash = "sha256:ca64d9f1f384f151b9511bec01126072acd2f313439f8ed015a22d8790aab6fa", size = 971999, upload-time = "2026-09-27T12:29:01.118Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/58/fa/ce3baf63d85b730398d92a7162f486f3a5e4e2cc3382a02488b3943725ba/coverage-7.16.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:732d950e51f3ba4fb6209c73250f3e8924fefca42953ee04a9e65d8c02414d7d", size = 223797, upload-time = "2026-09-27T12:25:54.756Z" }, { url = "https://files.pythonhosted.org/packages/7a/57/9ba29c2aac7f756d479f03d45762120060f0f988788001001bf36e0e6fca/coverage-7.16.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5dca0bb66b4c3d624ba047887bf70270030c150692d543cb501293dc38a9f4b5", size = 224303, upload-time = "2026-09-27T12:25:56.214Z" }, { url = "https://files.pythonhosted.org/packages/5d/7b/0d6d60906dca7d28cc1e3fce12a9861801c4fbb6cbf220ad78cd059c9467/coverage-7.16.2-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:af2a2a8c7c74de0559e0c368d94c8def9e16c58faaee33a0bf081057c4227e3b", size = 254715, upload-time = "2026-09-27T12:25:57.755Z" }, { url = "https://files.pythonhosted.org/packages/cd/b8/9198b865679379fb165c689c64f6e11105ef380f6bd1c7673e83f73d9f5c/coverage-7.16.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:db5f8394e17f877a625b257f2ba0ce8e728a499c2c1579ad66220272cd3df510", size = 256627, upload-time = "2026-09-27T12:25:59.131Z" }, { url = "https://files.pythonhosted.org/packages/98/79/9521462cb6072fe394701bc8974b74afd576c9c9355156c7844e1a86a42b/coverage-7.16.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5b3146d2317c75f70df2509066d979dadd941f7021cdf9b5db4bcd8568258e25", size = 258724, upload-time = "2026-09-27T12:26:00.691Z" }, { url = "https://files.pythonhosted.org/packages/a6/76/8d7d5d633db9fe0f3182fedc731bf09f9bcf2366055735152504ad614677/coverage-7.16.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9e1d0ced76318bab499693ff25f64faa343415187cb2e4d7befdfdd391a1cf6a", size = 260692, upload-time = "2026-09-27T12:26:02.083Z" }, { url = "https://files.pythonhosted.org/packages/4e/a7/76cb09c89ba46d74d37428bf93251fc14fb0bbe9e05cc2a5ef61773d318a/coverage-7.16.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:af98ad5ed9d6daaca956201e00bb429a7eb2b080426686f70a20353e0f9839f5", size = 254800, upload-time = "2026-09-27T12:26:03.369Z" }, { url = "https://files.pythonhosted.org/packages/72/b6/2351c1979aaeb5b4a8091a75b90ca997ad60de36e181ddba267cf61dac97/coverage-7.16.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d56e4d21c56d2046447733f8b118409597db48c01efe898ee9ac24e858ec2d6", size = 256423, upload-time = "2026-09-27T12:26:04.751Z" }, { url = "https://files.pythonhosted.org/packages/0f/f4/ad9a4f8b5cb2d494fa9452b546fe742ed2f9d3847cc14c05e36279a3e649/coverage-7.16.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1d5d0e3b660506fb84f995814e3118a21efdc0c8eb80127da1be627d90093c17", size = 254487, upload-time = "2026-09-27T12:26:06.082Z" }, { url = "https://files.pythonhosted.org/packages/6c/1f/a520470472f3e8b01169bf42162b1470c9ba992230432f62ca36269bf3a0/coverage-7.16.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:17228fbca0f22976f797be94e975dcd237799c657d49551c7de1e0654d1202e9", size = 258259, upload-time = "2026-09-27T12:26:07.513Z" }, { url = "https://files.pythonhosted.org/packages/09/d2/ff26d5938274745855fa61cfcba0245c88ccc10d98d2cbd96064f16cd5a7/coverage-7.16.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:bc0b0ac781d489304b741269857f1f8338b7a26b1b89c06c0344658001ec0035", size = 254216, upload-time = "2026-09-27T12:26:08.982Z" }, { url = "https://files.pythonhosted.org/packages/a4/1d/5d832d3b06785d9f53267e4f2724a9f60c312eee6ebed9063a461d0d3b45/coverage-7.16.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bf1bd822ec4e387ed245bed0d71151582cf7be9e5309bc4145eefe36083d5878", size = 255125, upload-time = "2026-09-27T12:26:10.35Z" }, { url = "https://files.pythonhosted.org/packages/55/4d/1d33edbc2fcf7d99e384e393e712aa5a2ebbbd8409825357815982207976/coverage-7.16.2-cp311-cp311-win32.whl", hash = "sha256:7ed238d227e23cc300c3d464babdaf9f6ddc740aa1b15a77ae96136e6a7c4516", size = 225898, upload-time = "2026-09-27T12:26:11.7Z" }, { url = "https://files.pythonhosted.org/packages/6f/7c/676df4882118756c4f8f560c954eddb93e166d84dda8c5f0b6a829689bde/coverage-7.16.2-cp311-cp311-win_amd64.whl", hash = "sha256:a90700f743e29aa3d75a6ff5f01953176a889c00e526194bc4d281731b88d99d", size = 226369, upload-time = "2026-09-27T12:26:13.375Z" }, { url = "https://files.pythonhosted.org/packages/7a/0e/a457f4a461b3c5610d845137fdd45fa465e011a64c25af440518ab1f4e41/coverage-7.16.2-cp311-cp311-win_arm64.whl", hash = "sha256:a336eec40e3520d369b8a6cdabb4f596e69a8b42927ca074aa1452fed943238a", size = 226344, upload-time = "2026-09-27T12:26:15.127Z" }, { url = "https://files.pythonhosted.org/packages/5e/2c/f8296c63c5d542f3d21aed685e56b7031a419037d155bb3382fc0940d249/coverage-7.16.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:218d742afca2b5ad5ca759e93eddedfbcc6eadf8322f080dcefc40b7bd4e2d48", size = 223969, upload-time = "2026-09-27T12:26:16.753Z" }, { url = "https://files.pythonhosted.org/packages/90/23/6f3dcb1423a0d43216e402ea1746e4a7c7c44f38896b97dd573790f56a40/coverage-7.16.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a9a638be322a8d76a41cdb17781c7f82aaee6a66493d8ffb7e2c09ee22423d99", size = 224328, upload-time = "2026-09-27T12:26:18.15Z" }, { url = "https://files.pythonhosted.org/packages/ac/7d/8f3b6dc920e3fc6732f7678785a2091db439f186afbec30dbf2214d9b1f7/coverage-7.16.2-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:724bd0f1e81856b35e59fc98cf7b4e544a3cb662e4e0864dca73d4326ee9d808", size = 255832, upload-time = "2026-09-27T12:26:19.799Z" }, { url = "https://files.pythonhosted.org/packages/d1/36/6c45f15be4eca4ac1062c6a55a323286494c99726a7e58951fe85967ac08/coverage-7.16.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5375ebd99038021b35e99dc88255022912c06565d316212f4a576e4b08d30f5d", size = 258571, upload-time = "2026-09-27T12:26:21.199Z" }, { url = "https://files.pythonhosted.org/packages/34/fb/b54cbeba3ad89082c2e441278681859e538322cc34b84b2af7ebff00080f/coverage-7.16.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a076277ca9f5750cc230f0f578ebd2620cec60255b25707361699fef6fb465c", size = 259680, upload-time = "2026-09-27T12:26:22.822Z" }, { url = "https://files.pythonhosted.org/packages/6e/a2/0dc65ec3d61930e1e4c2e371763b15eb4290896eb343a12d5d3091308116/coverage-7.16.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:58d4a54c6ea672afef66d49be922a2c69826c5ae1a42a9cd94f0c9c2bacdf800", size = 261945, upload-time = "2026-09-27T12:26:24.336Z" }, { url = "https://files.pythonhosted.org/packages/d6/93/5fad7a61f2c14e08e98946fc31c1c7ffc1195061bf3fdc351db3be77a863/coverage-7.16.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0dcbcfcc059117284c603ff8cb61a65872512882f84a8cf0339241f7f7c2f148", size = 256191, upload-time = "2026-09-27T12:26:25.89Z" }, { url = "https://files.pythonhosted.org/packages/2d/47/74e5de9227b939ece9f64e729645ddc4296bea10dbfa98721c1333c8be2e/coverage-7.16.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:afdf43b72ef3876c1fe66423b91466e37877c9e81e8cec70542b7e8525b9d1b7", size = 257610, upload-time = "2026-09-27T12:26:27.35Z" }, { url = "https://files.pythonhosted.org/packages/13/fe/2cf28d40b43645d1b72388fe3ee7f7c747533a6a9557bb8c24a7ae74fe1a/coverage-7.16.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9acc7f7ec4a1b5f89bd929fde5b8a714f6fafdc6cc18725413d510aa082b47ad", size = 255757, upload-time = "2026-09-27T12:26:28.949Z" }, { url = "https://files.pythonhosted.org/packages/d7/3d/7c149fd99fc8bbc39c80db5e688d1d39fd040be2ecb78b8335a51a55b9c0/coverage-7.16.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:80d3f7b48d43ee8fc5e8707a8adb43d743a5a1a85256c25a24f9d6d0e2238fa6", size = 259822, upload-time = "2026-09-27T12:26:30.515Z" }, { url = "https://files.pythonhosted.org/packages/e6/3f/b283fce09d5995e227bd8e513358dd7471bedc0f78abc85a925ebdb0a2f6/coverage-7.16.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:126d1af8804d7224421fe991ff65d3ce649081560df7a98b1a5ffff07f9923bd", size = 255325, upload-time = "2026-09-27T12:26:32.037Z" }, { url = "https://files.pythonhosted.org/packages/bf/91/f3325edf0c4223fb1fe1532b8dbef2a1d2f729459a9a7d1a44d073bae534/coverage-7.16.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c19cd6d025c1673f22afcd22c7df8a662d779e05d8e3fa6820c22afb895b0206", size = 257191, upload-time = "2026-09-27T12:26:33.525Z" }, { url = "https://files.pythonhosted.org/packages/c4/89/21eb5e83ecf2eed523c4eb3d65ae513cd082c8fd1b6deb34c4cb6c332f97/coverage-7.16.2-cp312-cp312-win32.whl", hash = "sha256:152877cdc8a07264882cfcd503ba56a3ef6cba56a70e8c70f6eb8ffd7384789a", size = 226034, upload-time = "2026-09-27T12:26:35.021Z" }, { url = "https://files.pythonhosted.org/packages/db/de/e3ad6d864c0833624b4f1f9b53f9e58e116c945e5e965c3f1e172c5e84cd/coverage-7.16.2-cp312-cp312-win_amd64.whl", hash = "sha256:e6c52d3307824ff93b39efd99e4185d557db40bd841452abfb32e5d9151ca162", size = 226569, upload-time = "2026-09-27T12:26:36.604Z" }, { url = "https://files.pythonhosted.org/packages/3e/c1/bccc58ebe5489cc70628f635c1932fd371f5d7da850dbcf960f95f4c4afc/coverage-7.16.2-cp312-cp312-win_arm64.whl", hash = "sha256:a678c0b6b22086ec2427359d22e37445d4a792f5fdbbc744112c7dade65cad02", size = 226372, upload-time = "2026-09-27T12:26:38.406Z" }, { url = "https://files.pythonhosted.org/packages/f0/f6/8eb4f220ef24f84fb27d852d4f9bf83e0c73ec1a4a08dd9a87e3f4529739/coverage-7.16.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1a37c6e478cf687e1aa30a593d19c92c02fad9d122b51ab73f51b8dc7a0c0fc9", size = 223993, upload-time = "2026-09-27T12:26:40.164Z" }, { url = "https://files.pythonhosted.org/packages/40/23/d4bbaf0c154e0b0c2b5264890dbf6ef098dcb50ec8f2469be9490d191660/coverage-7.16.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0993d0e90858c03943d3cb152e068a20dd4707924deec84dd2230261baae3b1b", size = 224368, upload-time = "2026-09-27T12:26:41.762Z" }, { url = "https://files.pythonhosted.org/packages/7f/48/fc1e88fd571ec5cb38150b7f89f7696ca1bdf9920e01432febb69774cc85/coverage-7.16.2-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bb2fc905bbf4e6b7f40806ea79e31515abf6349594cdf0adf27c4215f0463204", size = 255358, upload-time = "2026-09-27T12:26:43.442Z" }, { url = "https://files.pythonhosted.org/packages/1d/56/6785397d07c29c8e70fbb9a07e97d062b43c21ffc5f12385917847f09f63/coverage-7.16.2-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4358b9c8c0125b460407f3017c6cce8156e904b32772c5630d27112f52bdbfe5", size = 257955, upload-time = "2026-09-27T12:26:45.725Z" }, { url = "https://files.pythonhosted.org/packages/27/3b/c8cdd07721e5f99abd81cea970d971997f99bf158c0b85f51bd284179c8b/coverage-7.16.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f15254427c9b33eedac4f198eaf9e356eb4f6214551afb43da6194a2c088ad7", size = 259183, upload-time = "2026-09-27T12:26:47.208Z" }, { url = "https://files.pythonhosted.org/packages/9b/11/606b192fe43d32574ec6238549d48de588fdcc18485682a5ec0a8ac357f2/coverage-7.16.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9a75a4704ff640e46170042eec1f984385a121227c505d5a16ad8e495f452541", size = 261325, upload-time = "2026-09-27T12:26:49.084Z" }, { url = "https://files.pythonhosted.org/packages/67/90/eea481f8b0305ceeb33f081a5f47e298391dbd1b589de0c4b3b3aa50d3f2/coverage-7.16.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:14253fc7bb15749b849795a06f5d3b6d8bc3fb8a4b5ddc341faf7a89dce205fc", size = 255531, upload-time = "2026-09-27T12:26:50.509Z" }, { url = "https://files.pythonhosted.org/packages/6b/be/dedbf9aea1457b120c27ac10b8fc2a357f37fa2b54c3e7286d42980a0a2a/coverage-7.16.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:921415102a90637fcc2e3f169f61dad7699ecf690e8639fc21b813acbedc0967", size = 257329, upload-time = "2026-09-27T12:26:52.005Z" }, { url = "https://files.pythonhosted.org/packages/fa/cb/b25c19d5bb2bd0f2e4e27fe8e2ffcae80c7a91ae181c0dc749ed60e9b1a4/coverage-7.16.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cce2bc991293f15cc4084ca116827b5900c5f34e1a54dfe83f10ab5c43162eb7", size = 255294, upload-time = "2026-09-27T12:26:53.634Z" }, { url = "https://files.pythonhosted.org/packages/5f/a2/892c5c5f4ad44b7b2ca009aee705191f3f268f15052244f2f9e3539b2e35/coverage-7.16.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:e1fa594c887365b69745f25a416806e61085dd07b94c9eae68a6e20730629b23", size = 259444, upload-time = "2026-09-27T12:26:55.243Z" }, { url = "https://files.pythonhosted.org/packages/ed/99/a562537deba0a3e370182ae71c149be796c39d8087365f17a09188f27145/coverage-7.16.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:11e597173af1dc33d5f8a7332ada544199269a223af1ee1770ddd5e245ad0fe8", size = 255111, upload-time = "2026-09-27T12:26:56.851Z" }, { url = "https://files.pythonhosted.org/packages/2d/20/854ec68641a9b3362ff068a32dfa41637299761617ef253791dbade6fc76/coverage-7.16.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3e7f99698ba3a7d13988bdd984b7ebf13af4dbe2166dc8502eef90d77603b0a4", size = 256882, upload-time = "2026-09-27T12:26:58.41Z" }, { url = "https://files.pythonhosted.org/packages/db/0d/748e4518b0ac0f9ff2687c248a6e5f8c0737306e709372632a2556f84443/coverage-7.16.2-cp313-cp313-win32.whl", hash = "sha256:f80bd9f9633eafc73d0a913ba2645c96ba58bba1befc30590f7c0fbfde59d865", size = 226045, upload-time = "2026-09-27T12:26:59.983Z" }, { url = "https://files.pythonhosted.org/packages/31/fa/6e46edba66a183fe4d99d4bb52c173287e9b8dddabe0888d24cb8210e580/coverage-7.16.2-cp313-cp313-win_amd64.whl", hash = "sha256:8be099e979fc42559328a21828281b4578304191ae46ed4e80a407048a82eee6", size = 226581, upload-time = "2026-09-27T12:27:01.494Z" }, { url = "https://files.pythonhosted.org/packages/1b/d9/9ef6845367600b336ff75d000444a0d32497d6972c833141bd39356abf68/coverage-7.16.2-cp313-cp313-win_arm64.whl", hash = "sha256:28ff850182a67d117990fa2ce5ea1032836d8c9630dae867e8bdd3bff4533b79", size = 226409, upload-time = "2026-09-27T12:27:03.116Z" }, { url = "https://files.pythonhosted.org/packages/59/4c/577fc0803dab4155dcf808faffbdd7b159256781c0874a8586e17b81b149/coverage-7.16.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:4ee546b9e4872ffa194bf07ac87bfa1202ebb824d0795dc1ef22f175545ca90a", size = 224138, upload-time = "2026-09-27T12:27:05.141Z" }, { url = "https://files.pythonhosted.org/packages/75/9e/e3785ba3ecba2bd11efc74bfe2801ca4b78c4480b15a375648d809a59da3/coverage-7.16.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a2fac6895eb299a2e52d7bbb8fb3903502b9da8d3f5309ceb16ec40c646b58ee", size = 224445, upload-time = "2026-09-27T12:27:06.805Z" }, { url = "https://files.pythonhosted.org/packages/f0/d0/963ff22d3fd27117da3b8cc442f5bdc91196f783321e1a8ff0ec43476772/coverage-7.16.2-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:57ff3783f99d75a1e81dd56a9737eb5665e6736a5d93258ba596b6dcad8fd05b", size = 256112, upload-time = "2026-09-27T12:27:08.43Z" }, { url = "https://files.pythonhosted.org/packages/a8/d4/a306940c81c6ae759e82fff27d20b7fdc6896e422b821f51313cce212b6c/coverage-7.16.2-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:35f37886699cb9abd29958247d718628d5bc6f39e623dff66a09e546c42a7e03", size = 258727, upload-time = "2026-09-27T12:27:09.927Z" }, { url = "https://files.pythonhosted.org/packages/b9/a3/d3d99d93b02517087aa05bc0cf2d04d372956b849e5443e059079901429b/coverage-7.16.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0fd7a86fdda7cb6d616d178654bd0ad6bc0f3f33c2e478aa598500a1a9e34eda", size = 259909, upload-time = "2026-09-27T12:27:11.55Z" }, { url = "https://files.pythonhosted.org/packages/08/44/39dd599181726758dd185ae4dc0c0ab3aeabf7ca70e68e145060feeaaa16/coverage-7.16.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ac0f3b379c94acc2f7dce5f5f0b24d44fa1cc6a509717ef83dfee07450c2117c", size = 262481, upload-time = "2026-09-27T12:27:13.17Z" }, { url = "https://files.pythonhosted.org/packages/99/e8/91ee43f6ded411460c359d7e1aebde4d6fd8f00a2e5394182d9d212eb23c/coverage-7.16.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7d0732c83746bc24123c581a85d9dd96b70ddb538c9076020aa1a041790361e9", size = 256012, upload-time = "2026-09-27T12:27:14.91Z" }, { url = "https://files.pythonhosted.org/packages/11/8c/e9499ddc33197bd7eabcb1118ca81756fc874457b324e2b479a4804b2ad2/coverage-7.16.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7b451c68218c150f616bc9649783ec8de76a59792c759b43aa0c9c0466a465e4", size = 257898, upload-time = "2026-09-27T12:27:16.588Z" }, { url = "https://files.pythonhosted.org/packages/5f/6e/c081cb5991a0afba99f9c4ad6c74a5fce9513a38ddc64e3e6680c6fed9af/coverage-7.16.2-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a56ac4fa5a75c7e182e8f62600cfb4aff43c5ed7356a034f3557659c3bec1d90", size = 255938, upload-time = "2026-09-27T12:27:18.19Z" }, { url = "https://files.pythonhosted.org/packages/b2/42/1c3d819e8f9b6eb01c2fe90874d67a8882adb9507e0bbb09361ed131ea89/coverage-7.16.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:4cc4f73aa3fabc36e32046d6cd2971405948d8a903636508a3d3b2f9128b3a95", size = 260368, upload-time = "2026-09-27T12:27:19.903Z" }, { url = "https://files.pythonhosted.org/packages/19/4f/d70eac07901fd587b6ab05e659b52afe13959992aa5113bf6cce059cc572/coverage-7.16.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:723dcdab91357159b722935b500ee8abc0a66c8c432e1e9fabf4cc7598952de8", size = 255620, upload-time = "2026-09-27T12:27:21.621Z" }, { url = "https://files.pythonhosted.org/packages/34/5e/6d87af88317d3d9a9b18a9ca1bc1673eb516917f296e579d0d4a55cb3490/coverage-7.16.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5397e21a90dde0e9c6896b77ded8f0be26b66f8b22b33aed41f6043ed95d55e6", size = 257521, upload-time = "2026-09-27T12:27:23.358Z" }, { url = "https://files.pythonhosted.org/packages/79/bb/90c2641170d2fa1a6757b3f8450ba2740197317b0ddd749e9604b914e886/coverage-7.16.2-cp314-cp314-win32.whl", hash = "sha256:848893e1d361448c113dc2f0913503522a6f7be231d0e38333d2a22d9698a011", size = 226248, upload-time = "2026-09-27T12:27:25.153Z" }, { url = "https://files.pythonhosted.org/packages/30/08/d8d0478bb02c8eb0ae20a496fc80c40fcf4d3450bd184300d682ba2d28a6/coverage-7.16.2-cp314-cp314-win_amd64.whl", hash = "sha256:5a27b731c171e43dc8b5f32b76a5051dde2ec9b9366c87028f08a7088ebc2c7b", size = 226732, upload-time = "2026-09-27T12:27:26.907Z" }, { url = "https://files.pythonhosted.org/packages/32/3f/0001da22155b0a8ce063ec0f7e64ecbe17b373f306e7a74435f6d6accb72/coverage-7.16.2-cp314-cp314-win_arm64.whl", hash = "sha256:1c569a9fd25505f1cd6bea90588818f90373ce90e2632e2cacf19ddbd6e14fdb", size = 226645, upload-time = "2026-09-27T12:27:28.588Z" }, { url = "https://files.pythonhosted.org/packages/d7/85/6d8813aff9b8b8586691a9d33c43c5604f7227622574da7cdc3d91a86861/coverage-7.16.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d93db87adb6b1c1b408dce4763314b55d76a9f589e96783a84ac9e7689e48bdf", size = 224871, upload-time = "2026-09-27T12:27:30.32Z" }, { url = "https://files.pythonhosted.org/packages/5c/70/444f3a4981ac2cda40fdcf4cc9b56a4e1a33c222abeb33e51ed3e3eb2a6b/coverage-7.16.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:aa62c85046473959c13ba9edca9dc90a77d5c1095b1ba313556314d77fe5b036", size = 225123, upload-time = "2026-09-27T12:27:32.33Z" }, { url = "https://files.pythonhosted.org/packages/d0/c1/980681cd7b33eb66ac835044116ef0a92e11fcc7bdd866cc89d10b1130b9/coverage-7.16.2-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:db76506aa5416081f3e8974ae0f7965c58ada0bb0ef7339ac86099588dbb20d3", size = 265049, upload-time = "2026-09-27T12:27:34.085Z" }, { url = "https://files.pythonhosted.org/packages/b2/e3/87679875c33bb2191f0f05544a1cc9adcc940fe0c35443a10f2df753dde5/coverage-7.16.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a0f2285329dac10ab08f79cb11f5692c497018e6c7c511f95e6fd63a70b8f831", size = 267717, upload-time = "2026-09-27T12:27:36.025Z" }, { url = "https://files.pythonhosted.org/packages/76/64/5d372776d6eb523d4e93bafba2253f96984e3b18261c4cc56a50863c6d0d/coverage-7.16.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:382d3346d56b0eec1b793d53a4c88799c8053f516aa3a8d7c44315696954bacf", size = 270047, upload-time = "2026-09-27T12:27:37.96Z" }, { url = "https://files.pythonhosted.org/packages/be/c1/44082ff0cbf9f97d0043f57970a71204097ec7ba606361a9fd2065393669/coverage-7.16.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:648352b94507179d82637292e7ae8802508d95f78e2f00a705a50b6c48011681", size = 271360, upload-time = "2026-09-27T12:27:39.766Z" }, { url = "https://files.pythonhosted.org/packages/b8/17/9a215efe25b5e0ecc87c89dbe525c4a87d14d87c8c0c7316ef140a5f6f3e/coverage-7.16.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fb2bde05838fffae1a1bf75e5d411a6cac3e4e9bb97e6640fed8cd47888b33f0", size = 264736, upload-time = "2026-09-27T12:27:42.072Z" }, { url = "https://files.pythonhosted.org/packages/a2/da/7f0a31af8e448107d4d32844bd684757f51ea907bc0c68c8fd537b2123ff/coverage-7.16.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6a75180829efb8ae62b4aded25be6ddca1c888d138d2d82e21d93bfbd88f41cb", size = 267600, upload-time = "2026-09-27T12:27:43.85Z" }, { url = "https://files.pythonhosted.org/packages/dd/a4/3bfecbd3366b775bacdcb3330394d356cf384b5d8f5b2146ac4b14b252b5/coverage-7.16.2-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:99704f73721e23859112072d522076e11c31744fc96b5652e5dd2018aa4359f7", size = 264767, upload-time = "2026-09-27T12:27:45.768Z" }, { url = "https://files.pythonhosted.org/packages/b8/3f/5d62163732d87e4a0c4710a0eab30f0fd6a2d480112abe2029f014fe8c9d/coverage-7.16.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:29309ccc86b7f33df7db12813c299f215bbbc470ed6292d0bedd63ffae1ebf64", size = 269026, upload-time = "2026-09-27T12:27:47.787Z" }, { url = "https://files.pythonhosted.org/packages/49/4d/8e4579f225426535085a9be371cc75e3b026d058d679b80affbdfb4c3ef0/coverage-7.16.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:30c1b65d529e46569899fadca59e4a87c1faf2886923f1307ba61e654d4f3c20", size = 264147, upload-time = "2026-09-27T12:27:49.681Z" }, { url = "https://files.pythonhosted.org/packages/d1/36/ef1f77e2c3f7bb03c2b13b9a2006f88700fdd75535ef158d70049f425c1c/coverage-7.16.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:dcf4bc2aab4e16b1c4c0c2005918f23a7dd5d7821ddae82caed9e3342dc2fcce", size = 266376, upload-time = "2026-09-27T12:27:51.551Z" }, { url = "https://files.pythonhosted.org/packages/be/79/0cb2bf4428830dec971c718c2c841a039c084415c99e67281f5a72841aab/coverage-7.16.2-cp314-cp314t-win32.whl", hash = "sha256:a9cd3de0a5bfe7b0e21ee10e1a14e3d61bf52efc88217ab1d95d6ace6970bd46", size = 226585, upload-time = "2026-09-27T12:27:53.945Z" }, { url = "https://files.pythonhosted.org/packages/3c/f9/da17121c16667fd84998e972200ae226a41540f6ea4795776c6d99e8976f/coverage-7.16.2-cp314-cp314t-win_amd64.whl", hash = "sha256:611a44e5229a59d7483ce830160e1a0e85f700562c7a5651c7c63fb8f4eb528c", size = 227378, upload-time = "2026-09-27T12:27:55.778Z" }, { url = "https://files.pythonhosted.org/packages/74/89/01179c62d1b7e6e33bd5001566b02d7f778cf33d3ec1e81e94ca170c517f/coverage-7.16.2-cp314-cp314t-win_arm64.whl", hash = "sha256:22957cef43ce038641de78ba995de7568d2d6a37c6ddbf7fa0fd7d1ae2344d91", size = 227064, upload-time = "2026-09-27T12:27:57.496Z" }, { url = "https://files.pythonhosted.org/packages/4c/57/52935003c3f627ba6e5203d7179aad32448c10899663a30336aba8e81a2c/coverage-7.16.2-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:414c26dfdb96aac2d570a54e03008f001e32eb2d413705365503648c6bd361d8", size = 224140, upload-time = "2026-09-27T12:27:59.343Z" }, { url = "https://files.pythonhosted.org/packages/31/38/df472520f3e626524d7e2fc9d6da0afe7895a2f1489d36b48af8ca40bb41/coverage-7.16.2-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:00d3eb96e9988c45f50cccd1f1496571ac5c1f91386ac02c4d55516eeda19a24", size = 224449, upload-time = "2026-09-27T12:28:01.299Z" }, { url = "https://files.pythonhosted.org/packages/0c/aa/3be084d5b82e63ccdad4ed751e4acbae294673573e30481d29f8b7402eec/coverage-7.16.2-cp315-cp315-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4dbbd1155ca46e6e0b6b89d204428c56ef6a459af21333f365d135a2820e5a09", size = 256060, upload-time = "2026-09-27T12:28:03.185Z" }, { url = "https://files.pythonhosted.org/packages/de/29/48fca82a7ebf7ff7b2e35019cc9537e7f65e4d2aa1215cc5a8792c989251/coverage-7.16.2-cp315-cp315-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8fc15cc8d0d06e873c00ef18e1372d605f9aaf3de27d8c24e50782e75bc8b843", size = 259106, upload-time = "2026-09-27T12:28:05.15Z" }, { url = "https://files.pythonhosted.org/packages/06/3d/b2d5986f2dd53fe201aa1be2e4ab204fa1aed5101e67c0dbbb419b850aee/coverage-7.16.2-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c6afdd69218202bc1758c9a14b86b8cf1084f37ed2ca143e567a103772b16d1", size = 260674, upload-time = "2026-09-27T12:28:06.868Z" }, { url = "https://files.pythonhosted.org/packages/ce/7e/b50160be3506ead12e6480d14279af7f0f17627694300a2d1fd2c42d2ff5/coverage-7.16.2-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:aba5c63b7afdc749cc9eae943d5b868cba2b261a176378fa1c5a30bc8bc89982", size = 263139, upload-time = "2026-09-27T12:28:08.771Z" }, { url = "https://files.pythonhosted.org/packages/14/5e/7c805ac9a32606de1399bd7e9bd375aa2f973dc61b12680d9e6403c2e891/coverage-7.16.2-cp315-cp315-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9174f0af24e5eff248b9dbfe76ec5275a3d19d37edbc2810543f12cf97347a34", size = 256591, upload-time = "2026-09-27T12:28:10.842Z" }, { url = "https://files.pythonhosted.org/packages/ab/9e/76f1ed129a2daf658a3ea17122824cf2e3b91fea0460d8d3664fc5a61018/coverage-7.16.2-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:80e9fdb4c3d926b6ba721d4bf7435bdb869c3527ae7803290361d0ab73db13b6", size = 258708, upload-time = "2026-09-27T12:28:12.962Z" }, { url = "https://files.pythonhosted.org/packages/5a/b7/8d62e75f48b527619239a65294f842d4b7fd02a0839d43ae1de80184e2df/coverage-7.16.2-cp315-cp315-musllinux_1_2_i686.whl", hash = "sha256:7b3bce4a0d05401d70b7d0d5ca783e686bc9d30e81dbd7d980d532609bf809e4", size = 256562, upload-time = "2026-09-27T12:28:14.934Z" }, { url = "https://files.pythonhosted.org/packages/b8/8d/0a15f95c3afb78e947c52644786ba4bc9de259905687dd720d5e6fae2e76/coverage-7.16.2-cp315-cp315-musllinux_1_2_ppc64le.whl", hash = "sha256:44f21e407b278efdfc1ee5e481e00518bd1d500310a30a5fbf2bcbedfef4aaf0", size = 261077, upload-time = "2026-09-27T12:28:17.215Z" }, { url = "https://files.pythonhosted.org/packages/25/00/88389987305a47d732866c07c8a500000ab574df9505e3114ac69c8d027f/coverage-7.16.2-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:59c3926585e1cd1f2190f4b2ac9014de1bbeaf0d5d0587b0dc6b0aa90d17896a", size = 256034, upload-time = "2026-09-27T12:28:19.08Z" }, { url = "https://files.pythonhosted.org/packages/92/02/34d079d4952ad461bde037d353f9a6e037a7edc45fe0f9ee8781ff73f028/coverage-7.16.2-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:066429634299e14dd2d511e1e85f8f9cecc500781f6b41907c0dd6f1baea7e63", size = 258034, upload-time = "2026-09-27T12:28:21.242Z" }, { url = "https://files.pythonhosted.org/packages/f6/d8/3e59a62879285b464ec1b10fd824fbc1af9ce66e842cd39974f80a0becc4/coverage-7.16.2-cp315-cp315-win32.whl", hash = "sha256:893ea9cf86cb8d2546812ac93d973aaf2ee1fb45110a873b014214fd23e3725e", size = 226252, upload-time = "2026-09-27T12:28:23.102Z" }, { url = "https://files.pythonhosted.org/packages/f4/e1/128026e1b2836e9ad6b219207ba9edf1c5e0088a7869e23088aee7fbbe7a/coverage-7.16.2-cp315-cp315-win_amd64.whl", hash = "sha256:01c6908bc613b420c26c818fe948e1b97dfd041a53c98b01c63bd8321f5c9aae", size = 226728, upload-time = "2026-09-27T12:28:25.21Z" }, { url = "https://files.pythonhosted.org/packages/a8/f4/c9fa8e7cf525ca7748ac52b0ee89331d13fe09808e45c679830708782e90/coverage-7.16.2-cp315-cp315-win_arm64.whl", hash = "sha256:967d72c835d7a8cf0af99ec813a2d06e3db6df706402f1fe85b31b437645f495", size = 226648, upload-time = "2026-09-27T12:28:27.136Z" }, { url = "https://files.pythonhosted.org/packages/a2/13/e96b045447a856666f36f9c653e2a80bdaa732aaaf72412b19aa2c26a473/coverage-7.16.2-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:98d9c97f51b334b0adce7b964442a9af33c1a00c6ac856984cc5dc8d18f81c75", size = 224858, upload-time = "2026-09-27T12:28:29.169Z" }, { url = "https://files.pythonhosted.org/packages/23/90/087f6ad1bd3df059632ca3407a4e6552ed1053ee35354de0a771acf35423/coverage-7.16.2-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:3e861f1071dcc2fec1e88bef0920f6b1eaa66a143555b4f8ab79ba2b0f30ef55", size = 225139, upload-time = "2026-09-27T12:28:31.131Z" }, { url = "https://files.pythonhosted.org/packages/7e/8e/285dcef0184358044e7cbcd810a1bdc9566bc620f54702d605477155df4a/coverage-7.16.2-cp315-cp315t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:fb9d92ecfe2d5b494367c67f7446f8b75b68d8d0c8cf3bc3e6997478be25d9e2", size = 265090, upload-time = "2026-09-27T12:28:33.04Z" }, { url = "https://files.pythonhosted.org/packages/06/b2/cc83f3a6e5789a4e89059c69555bc641c2efcde568405a1c06fc702951ab/coverage-7.16.2-cp315-cp315t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:eb57acff4a74246ae513c142d4b36e18c389c3aed8661914a53f7cd0071031b2", size = 268254, upload-time = "2026-09-27T12:28:35.135Z" }, { url = "https://files.pythonhosted.org/packages/ac/41/f548c19530f5d66ac6e3c92bbcbc49da7261de3a458b9f3e54a3efb1a0b2/coverage-7.16.2-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:444889f7f66b74e4455c0a97e0e166dd41177f1dca8c0239a47cff25e05ba7e1", size = 270695, upload-time = "2026-09-27T12:28:36.959Z" }, { url = "https://files.pythonhosted.org/packages/94/61/4dc27cf82ef96434d2874110ad0cc10ea4621025705dc5049862bd3bd181/coverage-7.16.2-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a740ea6f083c6db7b926534d159508f80ba275ab35e722522de0d18d0f56e55f", size = 271853, upload-time = "2026-09-27T12:28:38.821Z" }, { url = "https://files.pythonhosted.org/packages/38/29/bf8072b1b8bd5f2de8b21460a404460b1a2b97e80a9464c78ec0271f6199/coverage-7.16.2-cp315-cp315t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8e209591f7c41ae4a9171335cf6156afda0b21de73b02f73f5aa95b2d5fbb08d", size = 265644, upload-time = "2026-09-27T12:28:40.815Z" }, { url = "https://files.pythonhosted.org/packages/7c/2f/0aecb8721be5cdeb8afd9d6d9f6b463f074e4d8d37f00f4c42442522709f/coverage-7.16.2-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:396bb16e04ce04efbb3df91456ae4e3da918e69ecdf67fb711b0a0fdf35ccce0", size = 268530, upload-time = "2026-09-27T12:28:42.725Z" }, { url = "https://files.pythonhosted.org/packages/ab/0b/92b4b7628268ee711249958e68fc0328779bd3d9a7ab4715379465aedb84/coverage-7.16.2-cp315-cp315t-musllinux_1_2_i686.whl", hash = "sha256:9cdf19874e0d247f32f03609200370343c3c7aa260b191d8c2bb251d36198283", size = 265154, upload-time = "2026-09-27T12:28:44.684Z" }, { url = "https://files.pythonhosted.org/packages/7b/d9/41c95c1ab29b3dcd357cd1227181d1c98185632aca41ce670ce671b23a43/coverage-7.16.2-cp315-cp315t-musllinux_1_2_ppc64le.whl", hash = "sha256:fd3d72233eb8b48acc94fa57d44e2d32ce8e7abed02882ccb6d855ccc4ed33ec", size = 269799, upload-time = "2026-09-27T12:28:46.672Z" }, { url = "https://files.pythonhosted.org/packages/80/07/ebeb259aa5362b033a137b86d7274ff4b109d59be8cc9913889b783bf75a/coverage-7.16.2-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:bb4ffe96aa663cee727659db5a2afeb38c95f8677b747d447b90d6d4874ea2c5", size = 265196, upload-time = "2026-09-27T12:28:48.996Z" }, { url = "https://files.pythonhosted.org/packages/b2/18/8437620f90d023680a072eee02f968055f3658bbfb7d386d0ea34cfb7f30/coverage-7.16.2-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:dba2edfb054f6d4a08df9d1637c39a5aa3865bca6617c13c86be21e45658a59c", size = 267266, upload-time = "2026-09-27T12:28:51.361Z" }, { url = "https://files.pythonhosted.org/packages/28/6c/f08e8ee4293e6434035424180bef4d45e028e8ecc006c61bf9453e74405e/coverage-7.16.2-cp315-cp315t-win32.whl", hash = "sha256:251aed777c47c77aba047096d4542889db089227655711dfc2b9c54ef0e15e35", size = 226583, upload-time = "2026-09-27T12:28:53.33Z" }, { url = "https://files.pythonhosted.org/packages/f7/fd/3f939c2847f4a72c20cff8b1ac33da78ea91a2d38d9b43336e60db719103/coverage-7.16.2-cp315-cp315t-win_amd64.whl", hash = "sha256:2aca0bdfa9e91621d5b09d815357bf63def4fc0e9cb66da67bf2cf93f3b1a6f5", size = 227374, upload-time = "2026-09-27T12:28:55.158Z" }, { url = "https://files.pythonhosted.org/packages/5a/35/b98cdc354c952402132e675a87f2cc3227fb68f959c84aaa491fbe15933d/coverage-7.16.2-cp315-cp315t-win_arm64.whl", hash = "sha256:b88841e654f09732804809e435b3e005a929ffd9998b872b7b213957b8759cb8", size = 227064, upload-time = "2026-09-27T12:28:57.075Z" }, { url = "https://files.pythonhosted.org/packages/3f/0c/7a64e1ac90541a8edf50daef0914848011fb057a5bf55284a4811e21939a/coverage-7.16.2-py3-none-any.whl", hash = "sha256:11d28e9123a9156cb405d8d27b44256c9a58fb5decc2073a8f17862057e3aa0f", size = 215754, upload-time = "2026-09-27T12:28:59.075Z" }, ] [package.optional-dependencies] toml = [ { name = "tomli", marker = "python_full_version <= '3.11'" }, ] [[package]] name = "cuda-bindings" version = "13.4.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cuda-pathfinder" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/a1/15/0277326dd1a2d619ea8a85b790fc9e43cb67897d3a3377eb783f5bc2a33a/cuda_bindings-13.4.4-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8b2e4235b552edb42cdbe39de7a9259ceec631e21c7344b76177db9cc6c58b4", size = 6494096, upload-time = "2026-10-14T12:35:11.314Z" }, { url = "https://files.pythonhosted.org/packages/97/36/3bfb7b74817a0a78f80340fae742a27d166e8fcdffa459b79d5be66e077a/cuda_bindings-13.4.4-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1cef1eaf5a08cc3bf3675ca9d3f97f3fc7085998556c848b4053e74ba4ba392", size = 7160763, upload-time = "2026-10-14T12:35:13.773Z" }, { url = "https://files.pythonhosted.org/packages/d7/38/87909f62598d02d9e5c536326aed1755f6bfa190285507b962bb601e0005/cuda_bindings-13.4.4-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b346bfe1dda49537537c06cc4727b2210d949d8aee883cb591bca46581629d00", size = 6488222, upload-time = "2026-10-14T12:35:20.703Z" }, { url = "https://files.pythonhosted.org/packages/c2/f8/332443cf969734551891cdbd93657eaeaf747ac2b7dd73feb3422701b02b/cuda_bindings-13.4.4-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:433efa31e33c2868621b5f6036bd3bf5de9c45c5546cb1361a5f6ff3415b8bb5", size = 7172184, upload-time = "2026-10-14T12:35:22.817Z" }, { url = "https://files.pythonhosted.org/packages/a7/97/7d75105a92ee18b7764f5cf60672d6a966842348a2a049e663fe690902ff/cuda_bindings-13.4.4-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c3f4cc887eac0d5edb5d7396cc78b336bee151a97e2ba7acf59e8b9380132d0", size = 6316532, upload-time = "2026-10-14T12:35:30.291Z" }, { url = "https://files.pythonhosted.org/packages/ba/8f/aedec367fea64267594a26ede3704f241e1bee465962f3a92d6186c774b7/cuda_bindings-13.4.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5d6adc44f098472d8ac2d6211923eea6081830521852dc77f8c9237bf9320a59", size = 6929120, upload-time = "2026-10-14T12:35:32.508Z" }, { url = "https://files.pythonhosted.org/packages/e6/f0/d71d1dd45caa358a39c6898dcc9f1bd22a9f22b92376b967835c047b50bc/cuda_bindings-13.4.4-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a429132f06d0c3a853aa419aabe4c0a7bfc3f3886fb4c336d81729f63754d31", size = 6407946, upload-time = "2026-10-14T12:35:39.826Z" }, { url = "https://files.pythonhosted.org/packages/15/65/0b8f2f2509e5f1a8e556a2e083ac0287fe4af79afdba3153454229306f39/cuda_bindings-13.4.4-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:680e70dcb8b61fdae16d3bb4876c41d55aadc9fe8b3825ea567f2f2c85606b0a", size = 6978954, upload-time = "2026-10-14T12:35:42.892Z" }, { url = "https://files.pythonhosted.org/packages/f1/dd/81903887199ffd90f9ee29eee8ecd497b734007e78b80689e0dd2f904bd8/cuda_bindings-13.4.4-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:03a8fd2a25530dbae26ecd4462d418156028e35b3f3b081440ff6368506e10eb", size = 6314269, upload-time = "2026-10-14T12:35:50.607Z" }, { url = "https://files.pythonhosted.org/packages/90/44/f6325a6061f1fc619e216dd6c7cbd9a0b475d3937bb32296c84cc27e6eeb/cuda_bindings-13.4.4-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0ce9208c7cf03a947ac11553b08ee2fca594ac63d34360639a9060980f546a62", size = 6865978, upload-time = "2026-10-14T12:35:52.874Z" }, { url = "https://files.pythonhosted.org/packages/c2/26/00d628420ac318a6a6d559fe6602e08a0156e7f4b5bf9dc6ea20c63789bc/cuda_bindings-13.4.4-cp315-cp315-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:50bc70ef3b225f4794f5b374773629836bbfdf4a21fc975ac25e7daad67494b8", size = 6414169, upload-time = "2026-10-14T14:12:29.952Z" }, { url = "https://files.pythonhosted.org/packages/63/88/5b50b13cef9ae8baadcca03a47cf0e9146c0b52ca6aeabaf50fc17e18445/cuda_bindings-13.4.4-cp315-cp315-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6781fe08ed5f4b5163a3c6577e079bc28955811382d35995c916bf052ee0994e", size = 7012626, upload-time = "2026-10-14T14:12:32.224Z" }, { url = "https://files.pythonhosted.org/packages/63/cb/013d9fd501dc1b05c3f467f28ad3adeed9e4d39318a4668a7a75fc5b19da/cuda_bindings-13.4.4-cp315-cp315t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a4c97f8430d7f7c4a4d0f245510d26647dd81ea3fc65941f7a815ad395cbc30e", size = 6302110, upload-time = "2026-10-14T14:12:39.47Z" }, { url = "https://files.pythonhosted.org/packages/c8/5d/ca0d5c1d9c09a9de15f474c1fa6abe801761e75cdc1be9a03431063f2af5/cuda_bindings-13.4.4-cp315-cp315t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:baa0f5f1f9a05032e7deb97051e85aa18b4e3c6db914f1c813bb2f02e5c72db4", size = 6878099, upload-time = "2026-10-14T14:12:41.504Z" }, ] [[package]] name = "cuda-pathfinder" version = "1.8.3" source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/b9/fb/f8e1890428f9f590b4beebd63b068aac1ce32a3331510c847b9f9a78f261/cuda_pathfinder-1.8.3-py3-none-any.whl", hash = "sha256:e29e59829c297a7a5233bd9cc71094fc5bddbd076951482670178f9eade39b1f", size = 62561, upload-time = "2026-10-02T03:20:23.712Z" }, ] [[package]] name = "cuda-toolkit" version = "13.0.3.0" source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/d1/c7/a79086a62c98befcdb8349656c6f114e2db3b8b2422f6e25c97a7f2a9a3c/cuda_toolkit-13.0.3.0-py2.py3-none-any.whl", hash = "sha256:d693caaa261214ddd7dbb60d68e71cbed884e68c2be7509778f3051da0b91c3f", size = 2512, upload-time = "2026-04-14T00:50:08.173Z" }, ] [package.optional-dependencies] cublas = [ { name = "nvidia-cublas", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" }, { name = "nvidia-cuda-nvrtc", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" }, ] cudart = [ { name = "nvidia-cuda-runtime", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" }, ] cufft = [ { name = "nvidia-cufft", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" }, { name = "nvidia-nvjitlink", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" }, ] cufile = [ { name = "nvidia-cufile", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" }, ] cupti = [ { name = "nvidia-cuda-cupti", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" }, ] curand = [ { name = "nvidia-curand", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" }, ] cusolver = [ { name = "nvidia-cublas", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" }, { name = "nvidia-cusolver", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" }, { name = "nvidia-cusparse", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" }, { name = "nvidia-nvjitlink", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" }, ] cusparse = [ { name = "nvidia-cusparse", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" }, { name = "nvidia-nvjitlink", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" }, ] nvjitlink = [ { name = "nvidia-nvjitlink", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" }, ] nvrtc = [ { name = "nvidia-cuda-nvrtc", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" }, ] nvtx = [ { name = "nvidia-nvtx", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" }, ] [[package]] name = "distlib" version = "0.4.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/68/bc/d36966de7304047a1001a7559fbf266c464bb5d8cc85464536ef8c9bcc32/distlib-0.4.4.tar.gz", hash = "sha256:ca4175b4ac7f71223cc30ed7248c45d2b38c2439d8ee6e498ab67ed63cf3508d", size = 621304, upload-time = "2026-10-16T13:56:34.203Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/c1/2b/238f02a4927fa2e27aa995371d240a468b52e42eae44a678434aff736b38/distlib-0.4.4-py2.py3-none-any.whl", hash = "sha256:cf09d55b1e85a89576b036aeb71550bfd68320f3f21761ca329eadadad918638", size = 472099, upload-time = "2026-10-16T13:56:32.053Z" }, ] [[package]] name = "dnspython" version = "2.9.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ef/4a/50822184bd67cc6493f0fb6a880749158fcd31ab3fa07409acfd91f9fc85/dnspython-2.9.0.tar.gz", hash = "sha256:b44dc6b18f07a8b1c56676a19fbfdb5209415b046a9cece286baafa87ff3f7f1", size = 423560, upload-time = "2026-10-09T00:07:24.352Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/10/02/cdcc9b7c051786a103c3b09e1003a82fa0c66bcb91ffbdabcfbf7b4163b9/dnspython-2.9.0-py3-none-any.whl", hash = "sha256:9a4aedb833c3c1b49214d04d44d3032ab7a9135f7c1d29a549b4ff78fd82fda9", size = 354822, upload-time = "2026-10-09T00:07:22.622Z" }, ] [[package]] name = "docutils" version = "0.22.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ae/b6/03bb70946330e88ffec97aefd3ea75ba575cb2e762061e0e62a213befee8/docutils-0.22.4.tar.gz", hash = "sha256:4db53b1fde9abecbb74d91230d32ab626d94f6badfc575d6db9194a49df29968", size = 2291750, upload-time = "2025-12-18T19:00:26.443Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/02/10/5da547df7a391dcde17f59520a231527b8571e6f46fc8efb02ccb370ab12/docutils-0.22.4-py3-none-any.whl", hash = "sha256:d0013f540772d1420576855455d050a2180186c91c15779301ac2ccb3eeb68de", size = 633196, upload-time = "2025-12-18T19:00:18.077Z" }, ] [[package]] name = "executing" version = "2.3.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/52/92/8a611141e42930c0f194f7504063ab87dfe970cf1a5af28e7703df448734/executing-2.3.0.tar.gz", hash = "sha256:15919cb5d667e5cb4e099511971d00d659573fff2dd5c4e6cd8b71636c7858d2", size = 1338003, upload-time = "2026-10-10T14:06:04.64Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/4d/dd/8bc67e7d5ffc1d88aa5af511189dfb76dc4e1e5b808fab186146ef2663e5/executing-2.3.0-py3-none-any.whl", hash = "sha256:736e859c9f8701f11fcf516856f26f562e04776387824b43a35a1dfe21c84122", size = 29393, upload-time = "2026-10-10T14:06:02.777Z" }, ] [[package]] name = "filelock" version = "4.2.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d8/28/3893324bcadf8f89b1616637468d766af3f625008c0735bf704fdfa86617/filelock-4.2.4.tar.gz", hash = "sha256:c6d8663535e1650ee430507b4ffbac7b464dd64b7647ea0112a9f406499d163d", size = 652444, upload-time = "2026-10-19T01:57:51.001Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/e0/1b/5e74289a1878e666bb4b65fe5805a04cafcac2aa5f519ef1ead67ef91c56/filelock-4.2.4-py3-none-any.whl", hash = "sha256:301241438c57936ef93f4243a94f2559022268bfcf9b375a9a72eb0f8db8358e", size = 162475, upload-time = "2026-10-19T01:57:49.419Z" }, ] [[package]] name = "flexcache" version = "0.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/55/b0/8a21e330561c65653d010ef112bf38f60890051d244ede197ddaa08e50c1/flexcache-0.3.tar.gz", hash = "sha256:18743bd5a0621bfe2cf8d519e4c3bfdf57a269c15d1ced3fb4b64e0ff4600656", size = 15816, upload-time = "2024-03-09T03:21:07.555Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/27/cd/c883e1a7c447479d6e13985565080e3fea88ab5a107c21684c813dba1875/flexcache-0.3-py3-none-any.whl", hash = "sha256:d43c9fea82336af6e0115e308d9d33a185390b8346a017564611f1466dcd2e32", size = 13263, upload-time = "2024-03-09T03:21:05.635Z" }, ] [[package]] name = "flexparser" version = "0.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/82/99/b4de7e39e8eaf8207ba1a8fa2241dd98b2ba72ae6e16960d8351736d8702/flexparser-0.4.tar.gz", hash = "sha256:266d98905595be2ccc5da964fe0a2c3526fbbffdc45b65b3146d75db992ef6b2", size = 31799, upload-time = "2024-11-07T02:00:56.249Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/fe/5e/3be305568fe5f34448807976dc82fc151d76c3e0e03958f34770286278c1/flexparser-0.4-py3-none-any.whl", hash = "sha256:3738b456192dcb3e15620f324c447721023c0293f6af9955b481e91d00179846", size = 27625, upload-time = "2024-11-07T02:00:54.523Z" }, ] [[package]] name = "fsspec" version = "2026.9.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/77/cd/9be253869fc42e764de7f3dedd6969af7d44ff9c3375214a3442a6f3fc08/fsspec-2026.9.0.tar.gz", hash = "sha256:0f08147951c8cb31d844c3547d631053b127863b60be04cf06e121333ee0e2fe", size = 333545, upload-time = "2026-09-18T17:50:42.825Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/6c/c0/a98505f18594f1bce828bb159cec0fcf9860562f1a2c85913409fc8f3d9e/fsspec-2026.9.0-py3-none-any.whl", hash = "sha256:8dd6e646e99ea382bd85f97a45e6b526a442d79423a7dc673f1e2756d05fcb5f", size = 221738, upload-time = "2026-09-18T17:50:41.341Z" }, ] [[package]] name = "identify" version = "2.6.20" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/53/35/d70c0006c7cee65999ea94a6273e60b2094f600a3d8b71b04318253fc643/identify-2.6.20.tar.gz", hash = "sha256:ad729860a923858d26917c2f4fb0a1d83d27a75b1e090c06440c573f048f3285", size = 99681, upload-time = "2026-09-26T20:29:07.187Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/fa/70/fffc9613501877c0a10a1ef73a165e6ded3e53f6e7502227fef56d973933/identify-2.6.20-py2.py3-none-any.whl", hash = "sha256:6a16b69b93187244e0548cbfd25b3e4a6f9a7a2ad784625c3bec2b8d27b81aaa", size = 99506, upload-time = "2026-09-26T20:29:06.054Z" }, ] [[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 = "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 = "iniconfig" version = "2.3.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/01/e1/2069291243c926a2ff1cd706c7f3eeb9b62144bf60f77c9fb9ff2fb26bd3/iniconfig-2.3.1.tar.gz", hash = "sha256:67f4b9c50da0dedf52af349e7749a80a9057a5031199791b906c3bb3ae878960", size = 21209, upload-time = "2026-10-06T22:48:38.076Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/56/43/4ca9e49d27a1fcf6bece6f6aec0ea46bb9112489b93d4b688fb415457bdb/iniconfig-2.3.1-py3-none-any.whl", hash = "sha256:9121e2c1fdb355232495be3194c8dfe87ccc2d5dee45947b78e68f499790d7a7", size = 7552, upload-time = "2026-10-06T22:48:36.959Z" }, ] [[package]] name = "invoke" version = "3.0.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/33/f6/227c48c5fe47fa178ccf1fda8f047d16c97ba926567b661e9ce2045c600c/invoke-3.0.3.tar.gz", hash = "sha256:437b6a622223824380bfb4e64f612711a6b648c795f565efc8625af66fb57f0c", size = 343419, upload-time = "2026-04-07T15:17:48.307Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/5a/de/bbc12563bbf979618d17625a4e753ff7a078523e28d870d3626daa97261a/invoke-3.0.3-py3-none-any.whl", hash = "sha256:f11327165e5cbb89b2ad1d88d3292b5113332c43b8553b494da435d6ec6f5053", size = 160958, upload-time = "2026-04-07T15:17:46.875Z" }, ] [[package]] name = "ipython" version = "9.17.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "ipython-pygments-lexers" }, { name = "jedi" }, { name = "matplotlib-inline" }, { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, { name = "prompt-toolkit" }, { name = "psutil", marker = "sys_platform != 'cygwin' and sys_platform != 'emscripten'" }, { name = "pygments" }, { name = "stack-data" }, { name = "traitlets" }, { name = "typing-extensions", marker = "python_full_version < '3.12'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b9/32/99451b1283ec5d92ad77073f12e1c667dc10775384d8f15c2914207149dd/ipython-9.17.1.tar.gz", hash = "sha256:8919be8c27f20a6f4423145028063f6637b42a03ce57665bb12015ee1f073529", size = 4539289, upload-time = "2026-09-01T08:29:32.6Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/2d/1e/65b59cf518c106aa755e7f7da3099027738687a862ec785060702a481320/ipython-9.17.1-py3-none-any.whl", hash = "sha256:6d1645743cfd1a07eb695d85aa2b5fa66721f8cbae9431d4049f7084bbf06509", size = 639038, upload-time = "2026-09-01T08:29:30.673Z" }, ] [[package]] name = "ipython-pygments-lexers" version = "1.1.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pygments" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" }, ] [[package]] name = "jedi" version = "0.20.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "parso" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a3/a4/4692ecd7fa700ac1066b1c1f6cadef60aa2e01e5e364710235137d823e0a/jedi-0.20.1.tar.gz", hash = "sha256:2f71208c3f9c1bca057c0e90d3f272aba44ace88fc4067d7587e9e069331b7e5", size = 3121738, upload-time = "2026-10-12T17:42:24.361Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/be/c7/71eb0d51cdcbb63b857c931aa4e9218b078b5d9f8ecd383b234f28fe7b0f/jedi-0.20.1-py2.py3-none-any.whl", hash = "sha256:0fb16d86c4a4c73c37ba518c77419975e30fcc620658a8d14fbb5720cdd34142", size = 4885980, upload-time = "2026-10-12T17:42:21.585Z" }, ] [[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 = "librt" version = "0.16.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/04/f5/9dc696772d241814bacac7880bac32f2930b5a6ebc1f85317b83161a011c/librt-0.16.0.tar.gz", hash = "sha256:ac38d6d8d66bf3d744148dbbc0b8e193e195a51e364ed55e224631f5721891fc", size = 219839, upload-time = "2026-09-29T00:55:32.891Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ba/0e/b04fd2d76b6a78a02286938251b2c119fb36ddece92c76cb4886ef7d44b8/librt-0.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fe4372c52d4849096c6cc1cda2817d293ec51440c890474ed59ef38d46556f18", size = 148058, upload-time = "2026-09-29T00:44:40.903Z" }, { url = "https://files.pythonhosted.org/packages/a3/fc/e1ed24aadb32d38603c0c07f579d739eb4d90e64e90d525b024e4a999b4d/librt-0.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c72c5295a84bd249526da9bdca38f2e176d15c31c13bb0063c5053f4ca023421", size = 153073, upload-time = "2026-09-29T00:44:42.165Z" }, { url = "https://files.pythonhosted.org/packages/be/38/133ab655409420e0c34a9a9836a7f4e5ae75fba758d7fe177099130d58ba/librt-0.16.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be56ba9c884143495b517f23fe794ae367d58cd89ea0fdd6d437e3c024a87f9f", size = 493052, upload-time = "2026-09-29T00:44:44.043Z" }, { url = "https://files.pythonhosted.org/packages/94/42/aaa663bc9421f5bf7bbbe9d3316d7219749698ec7688ac3b519770a89c04/librt-0.16.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:ef46c1a29ffb8c72e882e22618ec618778eacd0578fb22c6e7cf9c11d15f357b", size = 485506, upload-time = "2026-09-29T00:44:45.479Z" }, { url = "https://files.pythonhosted.org/packages/7b/59/83a6eb5087ba8b45b083859e2085256963e06d4c2531944cdd962670bfb5/librt-0.16.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d3c94211ee0c4f8d649ec06b7c115c0ec4eadb873a0e3154ca15cef3f814b071", size = 498708, upload-time = "2026-09-29T00:44:46.916Z" }, { url = "https://files.pythonhosted.org/packages/a0/e4/15a8d62b2bc12935080ec7277e2e0b9b233047781eb784a51d3e25af669a/librt-0.16.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:94aed6a8308818b91677957d1bd03188869cd7aeb23c5dba7912a6c0402f7602", size = 515981, upload-time = "2026-09-29T00:44:48.316Z" }, { url = "https://files.pythonhosted.org/packages/46/4f/287cc282ac5dd815204c0779e79401bb0a568c3a1335fb319bf0838fb566/librt-0.16.0-cp311-cp311-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:349c0bcb87ebd07481b6ff781e25cdc699723dbe2212e57dabb27f7a13b7b87d", size = 508670, upload-time = "2026-09-29T00:44:49.726Z" }, { url = "https://files.pythonhosted.org/packages/bf/5b/ab7292add898ade0d2b5b75d32a923aae315861671aa5c39f5491309f7ae/librt-0.16.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:001bfd59a7d45b17e3e75f2a8c6405280b35e7b84471792778e718c4f368950e", size = 530393, upload-time = "2026-09-29T00:44:51.356Z" }, { url = "https://files.pythonhosted.org/packages/7a/9e/8e6bcf027d4bcbc16a4e864b3d158a1d3e5f55ffa53af0238020cad89271/librt-0.16.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:28e038895b998d7a0c7798922ce8a1dc157675df5cf1c9ef0aca809ed804b7a1", size = 534302, upload-time = "2026-09-29T00:44:52.893Z" }, { url = "https://files.pythonhosted.org/packages/96/a4/8c5ab4f3b3a8e905ff8305d76976a2e666f52fe049edd398aed2402beb36/librt-0.16.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:0dbe4096a7ecc00fa835d24510ad8545a4efef738dac96e0e63516783ccde905", size = 536150, upload-time = "2026-09-29T00:44:54.421Z" }, { url = "https://files.pythonhosted.org/packages/ea/5e/7c4bc267e3cd4b8bd288de9f62d61fff203829c9cc649ea2aa12e9218cf0/librt-0.16.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:5cd5b092441053364af968ea12084692cb9d4a22f3ce9524e377880bf028761e", size = 514316, upload-time = "2026-09-29T00:44:55.998Z" }, { url = "https://files.pythonhosted.org/packages/e0/75/c8bc6b50f43c73819334233f5a3259c81216742cef56d2140c3dd377c3f0/librt-0.16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3ddeb3c9dedb461bb457c6c7d9aa7fbf35329da313d1a7543d00c8d0f3473c96", size = 557731, upload-time = "2026-09-29T00:44:57.581Z" }, { url = "https://files.pythonhosted.org/packages/93/fb/e241f91bc8de6c7ac1c6a20ea6dd381bc52312b44d711ffcd97140db1e57/librt-0.16.0-cp311-cp311-win32.whl", hash = "sha256:e05108e0849966f53a8d2d3112a7af881d0efaa479bc735bba91108f9f2350a7", size = 104922, upload-time = "2026-09-29T00:44:59.078Z" }, { url = "https://files.pythonhosted.org/packages/d1/38/c892383d2bb1a6a80b2ec8ede84970a265a792c56614a06282bf3008517c/librt-0.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:5f49cff01bd608ef7d97104cb035c75455e79c2d70bf4a506cf773338ac1860d", size = 125093, upload-time = "2026-09-29T00:49:01.621Z" }, { url = "https://files.pythonhosted.org/packages/e4/56/8bbde1ed0b21480163617648f638fdaec9374cf5e9c846ebcee34ec02a42/librt-0.16.0-cp311-cp311-win_arm64.whl", hash = "sha256:1d28ae980ae2218f9c5b95d191e947296f918c9bf0b400d467a9430275bbe678", size = 115910, upload-time = "2026-09-29T00:52:40.131Z" }, { url = "https://files.pythonhosted.org/packages/ad/76/bbdaeb87b7c47b5c7343e90222b9bfa4e4a8a83f647e02933ad0129225b1/librt-0.16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fe52bf4641069e7978a14253b036cb9002def1926317e710f2e249f8a8c47742", size = 151028, upload-time = "2026-09-29T00:52:41.508Z" }, { url = "https://files.pythonhosted.org/packages/fd/0c/ab8ed3dab0085931aec4a792c7eaac8dc6c5ff4691fda3a5360d9d8a9cd2/librt-0.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5bcc2c4726ced915b00de0c9856a4eeabfb3fddb93e10e0b8f735b7709358b6d", size = 155283, upload-time = "2026-09-29T00:52:42.873Z" }, { url = "https://files.pythonhosted.org/packages/eb/36/494e79d460c80c1f030661e8287c9eca5e1ad652dc2b2180b6cd42abce0a/librt-0.16.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff7baa55f8e7c69851419e50a666015d02a74198716fd45c0125a2112e0a389f", size = 503185, upload-time = "2026-09-29T00:52:44.638Z" }, { url = "https://files.pythonhosted.org/packages/9b/34/a8464038dd9db6e4381fa2b6eb73dc9a50888d77102c4c139304ac35cddc/librt-0.16.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:b95d5d92ab83d39e760a52091bb1baba664f3a2351e39b1e16801e5747c2f0e9", size = 496738, upload-time = "2026-09-29T00:52:46.441Z" }, { url = "https://files.pythonhosted.org/packages/6a/53/e0e5e334ef0c6ed27039d323819368b9ef6712be87d55ee2bf9799398afd/librt-0.16.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b6d085d70bce51d43c5c7c36d63490770180d8779e71c49305c87b4213918de7", size = 513818, upload-time = "2026-09-29T00:52:48.068Z" }, { url = "https://files.pythonhosted.org/packages/ad/f7/7ce72cbf19d0addd05090b339152fd0548a02562c2866a603e6e3b3da2df/librt-0.16.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:36e53948e99bbe3ffea257124cfcae1cfb01831555c9a9c903c9f9a72db7fd07", size = 531952, upload-time = "2026-09-29T00:52:49.816Z" }, { url = "https://files.pythonhosted.org/packages/83/22/0b1bcb6a8e723c8b4fd60dfc8ae8ec6461c54073fbc8685efeb8d900d407/librt-0.16.0-cp312-cp312-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:54d11f726aae9df5a6ffbbf0a03a52449bbac84a53ef03669cb41cdfd4ae41bf", size = 524465, upload-time = "2026-09-29T00:52:51.354Z" }, { url = "https://files.pythonhosted.org/packages/64/2e/e9c23b8b9df1813da1be205deca9606beb7ddd033972246cd426d05374a0/librt-0.16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4323193ac0cd025f85af531df8ba91bf24d1973b401697347a6282e8fd3fcf5e", size = 543191, upload-time = "2026-09-29T00:52:53.284Z" }, { url = "https://files.pythonhosted.org/packages/bc/e5/6a8b21b342c03ed7e230fa3afbfd2edc58e6e87ef1f0d11fa2b9a748c252/librt-0.16.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e42f8e098b9c5396fefa05fb1cc7e33b0e08fc51da106b5de4a45fd22aac6743", size = 546979, upload-time = "2026-09-29T00:52:54.932Z" }, { url = "https://files.pythonhosted.org/packages/84/9e/b5129023eced1be01e01c22757f53be551d463b1bb7264f787927404c1d6/librt-0.16.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:39ec1d5a14e37baf1450a6cabf03fe552340808bf1ad9d71824ab90117716459", size = 555317, upload-time = "2026-09-29T00:52:56.869Z" }, { url = "https://files.pythonhosted.org/packages/71/89/28bba5938c725fe91f06bf93f7fa6c6b150229df53a87b454b0d5c2a796e/librt-0.16.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d1aabe3925cbb4a08d15b7b20ba4011b53019da0c4173a25155139b7b1baed65", size = 535846, upload-time = "2026-09-29T00:52:58.475Z" }, { url = "https://files.pythonhosted.org/packages/22/92/63773026614f888c5d4e370e395ce42ca604b89f70b3acdfedbf94851b80/librt-0.16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:300c3ffdc459f4a779a8411ecb188e3ac0b1ff3a3a7b099642555dedae06c69b", size = 573700, upload-time = "2026-09-29T00:53:00.127Z" }, { url = "https://files.pythonhosted.org/packages/66/8f/347d4677eefb57cd9f8e01d95a1dcee9a91b4e44e664173c32ff6f3752e5/librt-0.16.0-cp312-cp312-win32.whl", hash = "sha256:c17194318e4c0c0348b36f36c2ec7534436fe0a4c15582403162a4f08c80797a", size = 106158, upload-time = "2026-09-29T00:53:02.031Z" }, { url = "https://files.pythonhosted.org/packages/f0/2c/5193dc81127cd5ddfad031391b046bf32dda219b38463ab872407ca30646/librt-0.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:25a58a19ea8d83b68209f04912df765e9260635ef77646542ed4b4abe6bc7940", size = 126176, upload-time = "2026-09-29T00:53:03.445Z" }, { url = "https://files.pythonhosted.org/packages/ff/3d/9668a400c8dd81d162eba38b33fa49fa6205f1a64493570a13fbb815c3ee/librt-0.16.0-cp312-cp312-win_arm64.whl", hash = "sha256:f7be7cf555bc30ec12622e9447299cc4a9b8ff307548b634794353db0c2065dc", size = 116572, upload-time = "2026-09-29T00:53:04.815Z" }, { url = "https://files.pythonhosted.org/packages/46/cd/ae5e0e9dba45d1399aa04a5395bcc0bead40d9fa06dc903634a7b4d7473d/librt-0.16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c5e6144e68b577f157519f2ba88ca20e3ed61c29b00e5cdfa76cd2d45acf059a", size = 151036, upload-time = "2026-09-29T00:53:06.284Z" }, { url = "https://files.pythonhosted.org/packages/41/5a/48a16e323c5f9447a94cce7b59babf60fa04e62c3365ecf060c77ed8b320/librt-0.16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:33f41443a1f4e1f099331b3d8120e409fbff84b9760bc1cc9ea496f37ddaa5cc", size = 155211, upload-time = "2026-09-29T00:53:07.72Z" }, { url = "https://files.pythonhosted.org/packages/3f/29/0f59299eb4251a409b2e690ad4b7d9f8a676db829d7817ec961f32b44f7e/librt-0.16.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7e510b7770bee609617a3374a96548eb114cae048023e3f049ee449e7ff2db32", size = 502587, upload-time = "2026-09-29T00:53:09.191Z" }, { url = "https://files.pythonhosted.org/packages/de/ba/d6fb4ef8d1537c396079d72289f16be7cd35a366e5065c51253fea2760b6/librt-0.16.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:efc49c462d4516b8a58b00b490078fa64689fd1fe66970cc190131d7afb8027e", size = 496146, upload-time = "2026-09-29T00:53:11.016Z" }, { url = "https://files.pythonhosted.org/packages/52/fc/8c50dd4d7cc97c0ee8f252c8a3104980f234391cf1519b554e8b9de08b60/librt-0.16.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:92caf82ebef5e12d21c72242b70d1e92536f1711cf2a727a4c276de4b4469087", size = 513336, upload-time = "2026-09-29T00:53:12.655Z" }, { url = "https://files.pythonhosted.org/packages/a9/59/16c409c56f708eda2db9a0553662845d45e3871c77d70a240dae3f3bdc56/librt-0.16.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:17bac7f7a16b328fff77e440287693eb017abde913595b5827ebccbc21ecd8a6", size = 531689, upload-time = "2026-09-29T00:53:14.39Z" }, { url = "https://files.pythonhosted.org/packages/88/82/d34772a6c29d1446dcca6e64d74062efd508523ab351aa16625a4689d5cc/librt-0.16.0-cp313-cp313-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5b976054553670829985ed767feb78fb6bcede0175327c4844dd5c281c1be659", size = 524537, upload-time = "2026-09-29T00:53:16.064Z" }, { url = "https://files.pythonhosted.org/packages/77/8f/24c5631313746131ccee53bc91fdc8374f9cf25e0082a1fee9c93bb98acc/librt-0.16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0058f9d68721094105917254c72ac0569117bb7b13b9769cf45d26d89f9d21cd", size = 543231, upload-time = "2026-09-29T00:53:17.939Z" }, { url = "https://files.pythonhosted.org/packages/f2/cb/5f8e0d41dbd8b499c2265e939c31acc9ba59845565bf99539ad1c06aebcf/librt-0.16.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:30b7beaf3f4487b7d8adef1f158b49067cb4d5a19fa7a3bf31a4e7a820e435c5", size = 546499, upload-time = "2026-09-29T00:53:19.666Z" }, { url = "https://files.pythonhosted.org/packages/be/61/063052de441d1385f59cea4223f184bf9e5d125de1ae3239b490aa1e486e/librt-0.16.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:468df902df016a06eb0e40b0747dc8d14e47d7a38b18b63b1fb167d85cb94d63", size = 555261, upload-time = "2026-09-29T00:53:21.292Z" }, { url = "https://files.pythonhosted.org/packages/14/11/a2ada0529372268d6401afa9d457a095b68cd7753532b6f7f33049a19b43/librt-0.16.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:aea7b1f2b125dad5de85f049136651bff256c883c65e6b9209b2da0a1ac3cdef", size = 536029, upload-time = "2026-09-29T00:53:23.07Z" }, { url = "https://files.pythonhosted.org/packages/23/9d/5bb6d38853382986dca702fc7e06c8256d30f5fa0676d882773b744610dc/librt-0.16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a8afb6557920860b7a3a596eb804cf37e09e7cf8a803db2478c202acc72d8c2e", size = 573748, upload-time = "2026-09-29T00:53:24.696Z" }, { url = "https://files.pythonhosted.org/packages/99/f6/0025cde35ff7f607684dc775a2b2d732cce2561cec050a6ee1fb2e1fc6fe/librt-0.16.0-cp313-cp313-pyemscripten_2025_0_wasm32.whl", hash = "sha256:77c7a2b4fe2c1369e0d5aa1cade26740a7b14be32fbc9a5535d617d20065c39d", size = 79861, upload-time = "2026-09-29T00:53:26.089Z" }, { url = "https://files.pythonhosted.org/packages/93/93/303b8592909bd583f83f02818ffbea3f7647ca1e22b1cd5465d04b8145fe/librt-0.16.0-cp313-cp313-win32.whl", hash = "sha256:02d89c813d5ff74b17df72d3a34819d132cd168e56b81bf755b809bd9e46b8c4", size = 106236, upload-time = "2026-09-29T00:53:27.43Z" }, { url = "https://files.pythonhosted.org/packages/cf/24/80bbb463c60ed18e29cb26aba386ddb76609580e4e7160710e550587018c/librt-0.16.0-cp313-cp313-win_amd64.whl", hash = "sha256:14ed6ebe3e4f85f326d7920011ad30ff49ed9334e62cf88caef9ba973d9e3a92", size = 126180, upload-time = "2026-09-29T00:53:28.7Z" }, { url = "https://files.pythonhosted.org/packages/43/80/b1a6fbdd7da825cdd55c71aa81eb6cfa82c513c360774152eacb50b4a771/librt-0.16.0-cp313-cp313-win_arm64.whl", hash = "sha256:83d4041a3d9b2fd053a8a4e1f22878b3e5833e2712956382d5c048d791454e91", size = 116557, upload-time = "2026-09-29T00:53:30.012Z" }, { url = "https://files.pythonhosted.org/packages/1e/93/9e0cf7da129a93c3dc7f45bc3cd4a660f2aaa995aa8a6f95c2583ef41239/librt-0.16.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:931a0bb0fcac88f263e269e46eb30ba8e21402cd3c62ca40cb97034c0693fab1", size = 149844, upload-time = "2026-09-29T00:53:31.391Z" }, { url = "https://files.pythonhosted.org/packages/8f/26/8a90d2a8f2b2e471bb486b7aec117b8ae622715ed6c39853aec48ea20073/librt-0.16.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1bc17e54e5305f8d40b7ca203671ff5a9e59c1d0f8ea0f625dcca53a3984de11", size = 154111, upload-time = "2026-09-29T00:53:32.718Z" }, { url = "https://files.pythonhosted.org/packages/35/ce/67abb46258da4d3e42ff5b141db6f38c59357bef84c7979f183b22f924f1/librt-0.16.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:877698bf6bca5721d8be345f2fe09778e40ecadea8b58c73075f2b1a53666bf2", size = 494234, upload-time = "2026-09-29T00:53:34.466Z" }, { url = "https://files.pythonhosted.org/packages/12/f9/ea7162414a16f8f1bbd3b493ad6d22b926c5471916e078350bdbca8c4e5f/librt-0.16.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:5981c011b306781ce561e18e14230a14524a3d8109b97553666c942c18f31a96", size = 491173, upload-time = "2026-09-29T00:53:36.124Z" }, { url = "https://files.pythonhosted.org/packages/b1/09/9b3e869060dd33f9989b80ba4fea306f6db8cecefcdfe6d7346ef0603f65/librt-0.16.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:afced3dfc17cd805ecf7a3d77996a71cf5f2c75aa66eb0c21a9930f4fc992f86", size = 505547, upload-time = "2026-09-29T00:53:37.686Z" }, { url = "https://files.pythonhosted.org/packages/50/07/79007d2165f649ea93e08c0962d1d62c70af9cde77965255095bf9d96f9a/librt-0.16.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ca8052401c55d7511dda6760719fda7618067e83535d7d0010096d216c34b667", size = 523057, upload-time = "2026-09-29T00:53:39.301Z" }, { url = "https://files.pythonhosted.org/packages/61/0c/8fbaff66d0ba376d8864653f5acce1569bae27e89648671f26f7eca67ab8/librt-0.16.0-cp314-cp314-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1e511762a074005bb0aa569166779834e75e438370226930d0ce1866d4b6a33b", size = 515158, upload-time = "2026-09-29T00:53:41.012Z" }, { url = "https://files.pythonhosted.org/packages/df/2e/23ff0dece76f07a4124413a57682efa0bbeb5765ac0122bc0955513f82ca/librt-0.16.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f1e8591bd8a5a628cd7f07954c6a1592359a878bf032957a8e9057a41d644311", size = 534183, upload-time = "2026-09-29T00:53:42.451Z" }, { url = "https://files.pythonhosted.org/packages/26/c4/e11dea21d9a29486eba78887380374189d472734fa32cc50cb37ca44d3d0/librt-0.16.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a4aaefb4ba6c07e1aeebb2795c8958148f1d6f9af3b555b53d23d766edb6d67a", size = 540663, upload-time = "2026-09-29T00:53:44.272Z" }, { url = "https://files.pythonhosted.org/packages/44/75/e873ae158a8b7f5359be33e7fd6c1fbe02d9a78a3e89a77de6b0e837f476/librt-0.16.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:d92db7a0f6aee44f1baee94750457e8d2d1c6ccea41842de6268d34e8dc7eddd", size = 545908, upload-time = "2026-09-29T00:53:45.812Z" }, { url = "https://files.pythonhosted.org/packages/ba/36/8939d3f6a93e11bd9592e6fe28d2b44f1c2dc4bed6e22e72359a91e18ffb/librt-0.16.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:378dfaffb38e59c24a87cde5713cd865d51ff7383fa12947f3907f306ea1ca55", size = 523302, upload-time = "2026-09-29T00:53:47.596Z" }, { url = "https://files.pythonhosted.org/packages/71/14/35309f44a077f0f42ade0e2e7cd88c0cea760c661af205c01ea90d3c0e1f/librt-0.16.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3e0c39bdc85370422e8b637be76eb1fd07d30967551b03e62267dd156f553152", size = 565911, upload-time = "2026-09-29T00:53:49.278Z" }, { url = "https://files.pythonhosted.org/packages/78/0c/df6255b94967f3159ebc46f08d8e783c12da6ee269ddb74b2efed63c640c/librt-0.16.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:1b384b90ab79a7bc30b566895809a636e0666f21f3cf12b54823d025b7e83839", size = 79119, upload-time = "2026-09-29T00:53:50.938Z" }, { url = "https://files.pythonhosted.org/packages/6b/44/d30d5a5461378c9d33f36736c6791c3b4c4ba4b1ffe0da7350aedcb2c9a0/librt-0.16.0-cp314-cp314-win32.whl", hash = "sha256:52327da75a94012e7f932f913d20d3876bed3c102be00e6c3e8600ff7bdd58a7", size = 100140, upload-time = "2026-09-29T00:53:52.205Z" }, { url = "https://files.pythonhosted.org/packages/c2/98/769712f356a1e897df3581bb0c3100375d054a000de26099360ea65b5111/librt-0.16.0-cp314-cp314-win_amd64.whl", hash = "sha256:3f0b8114c44b2ac06ff5dacd08e07e8e807ff4f46083f2a1602685122559be41", size = 120464, upload-time = "2026-09-29T00:53:53.495Z" }, { url = "https://files.pythonhosted.org/packages/bf/d3/ae2abccc8bdc8b063c1613a77686e17b74e9d3d60cfe6f12c63fa2821b9f/librt-0.16.0-cp314-cp314-win_arm64.whl", hash = "sha256:8caf96a4ef8fb27d0ac0d1ad8337d26a240acd4a02fe4345d0a8f264753e8f99", size = 110889, upload-time = "2026-09-29T00:53:54.817Z" }, { url = "https://files.pythonhosted.org/packages/e4/26/0737d4be058dd6376eade7dd8b380d4b869b6394cee929393a5a431c45bb/librt-0.16.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:953107e2f68d0f3512c48f898b0dbf0ce5cc52bba0f318d847c985dc555ee4cc", size = 159838, upload-time = "2026-09-29T00:53:56.22Z" }, { url = "https://files.pythonhosted.org/packages/01/96/9bc96531d7c620e9949af904470f02e3fa8f35129ab8e8f281c51eaa3788/librt-0.16.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ad37d5b9abd49c9a655dcda7ea52a8a752884062ef1ee71ae17c2f2a0f81fe6a", size = 162018, upload-time = "2026-09-29T00:53:57.532Z" }, { url = "https://files.pythonhosted.org/packages/0e/fa/b0289dcb186eb3f97221ba00da5f4bd3ba7fa5e99752d48aa8d336615334/librt-0.16.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c4aa329c17bd1aaea4f6e89335d8ccd494b3a5830b6654462273e50e11023f0", size = 703983, upload-time = "2026-09-29T00:53:59.024Z" }, { url = "https://files.pythonhosted.org/packages/d9/ab/05ebbbde7530fc5eeb58fbd1581522a9f64f132fa703c4c595eed6e14760/librt-0.16.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:0ead24d2562a49473dddd9efef8581f020007eb0054389c3ee3ffad38b1ca4c9", size = 683847, upload-time = "2026-09-29T00:54:00.671Z" }, { url = "https://files.pythonhosted.org/packages/a3/75/f52aeecd4dbadbddf80725ba7de126d8bd5d0eb66247eae17a81ed90dd4d/librt-0.16.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:02118f56a9c36ddd07dfd9b919d9ecc117ba20a90987d56aa4c429fa34509188", size = 698045, upload-time = "2026-09-29T00:54:02.247Z" }, { url = "https://files.pythonhosted.org/packages/e6/55/fa277a835cd6eb42380591ceb85f48c5b4d2b2d7e2cb9869e1e17d24d237/librt-0.16.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4e29522c62e28595ff7e324c6834ade51127707f0e255b18d1c1cf03d39c1048", size = 724640, upload-time = "2026-09-29T00:54:04.078Z" }, { url = "https://files.pythonhosted.org/packages/25/e4/2cf64354f3fde8ebd591b3b48f96510bee24ac5f7d1e567adbbe210abdbd/librt-0.16.0-cp314-cp314t-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3ff4b2367926b69c6215635902cccb04048e73094e9862900d27cb2c6bbff143", size = 731748, upload-time = "2026-09-29T00:54:05.741Z" }, { url = "https://files.pythonhosted.org/packages/f8/c9/c180af3e94e01aa529fa93d7733fec2abc47f222345400cf21d5481d5f8a/librt-0.16.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c6f1b27bf1632a7e016af9f145f82be95e1edd7721a646505c21059257cb5a04", size = 754960, upload-time = "2026-09-29T00:54:07.38Z" }, { url = "https://files.pythonhosted.org/packages/95/d6/01073aa78c58f356b10d9c57b3fe9abb143df338142bcd316df417b89db0/librt-0.16.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:5696d7f52e7b37217cb3a8f92c744fe835942602fdd4c1a8bc4741d3bfdce15e", size = 747000, upload-time = "2026-09-29T00:54:09.06Z" }, { url = "https://files.pythonhosted.org/packages/f7/d8/1de3783908658d697a8cfc00582f61299ffba7796d7260c112e4700b1109/librt-0.16.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:6072e92dd876ff6ceeb6cf371e35e51f479349837391341f479b08df4564242b", size = 749569, upload-time = "2026-09-29T00:54:10.702Z" }, { url = "https://files.pythonhosted.org/packages/b7/32/e817f66c96d6caa8bb8435ff93c4c220624d59efc506be59ab98fcd01d0c/librt-0.16.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:39ca4f2f2fe05de8e63493da592d84311adabe5bef52b193851981da9816b302", size = 729483, upload-time = "2026-09-29T00:54:12.25Z" }, { url = "https://files.pythonhosted.org/packages/7c/c9/23992ccd2b9d22798fdd0f61353183a47414e651da782ad83eb680f50833/librt-0.16.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f9807485a908f00355820f18e91e045ffdcdc5adb68aaec40a1e2b88c5f7bba1", size = 776584, upload-time = "2026-09-29T00:54:13.837Z" }, { url = "https://files.pythonhosted.org/packages/67/3b/e8af957f08e6e2e8e566b099e43d2748418aa565df6ee1d9d3331209fdfe/librt-0.16.0-cp314-cp314t-win32.whl", hash = "sha256:94be5cb7bca4df6201f4183e9e4fa2086c655283d20b38cd84500a69057575a7", size = 104402, upload-time = "2026-09-29T00:54:15.568Z" }, { url = "https://files.pythonhosted.org/packages/ca/1c/946e6443d7cd32347a086043395e421e52fd603c9163d2ec970ceab8eed6/librt-0.16.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d46ca272b251d033dd4527b0dec5f261a28a52bd5fa0f99c117b0a1f8588cc2d", size = 126227, upload-time = "2026-09-29T00:54:17.165Z" }, { url = "https://files.pythonhosted.org/packages/c2/a3/bc4f9959d3c62bcbf9e5fd3470a8bbd8bf33224ed4c25d7fba173201b8ac/librt-0.16.0-cp314-cp314t-win_arm64.whl", hash = "sha256:b9d6d4b14e92d876f8026b54c20c445f36425214c1081dc76f74e40db386b82b", size = 116493, upload-time = "2026-09-29T00:54:18.567Z" }, { url = "https://files.pythonhosted.org/packages/b6/4b/10fdb42dfab4c1533e1570e686b18e86ff4328b406361b39fb3016667638/librt-0.16.0-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:6fe436af2eaf630474f491af5d032cbe45f93fcff5c3b9fe4ab194a7255b20ff", size = 149829, upload-time = "2026-09-29T00:54:19.933Z" }, { url = "https://files.pythonhosted.org/packages/8e/30/a90ca13f1d3d91af1680000a4038536907018fbd51764767287a05d28b8b/librt-0.16.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:8ff5d26c529336be9bd7ae04483235d77778ee7d6444a95353102b542601ce81", size = 154522, upload-time = "2026-09-29T00:54:21.306Z" }, { url = "https://files.pythonhosted.org/packages/5c/dd/bcf364eacfa070bb1fc88d503111ae7177914197ba1fa717c748926e7930/librt-0.16.0-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:909d8e3c1faee44cb762b1c519ff8613dcc5ceae5c99987a00917b5a31fd1d6a", size = 497593, upload-time = "2026-09-29T00:54:22.798Z" }, { url = "https://files.pythonhosted.org/packages/18/c1/2c4e81e347bdabfe8346bfc6dc37ae5e154d61c88e30848ec0606025a5e0/librt-0.16.0-cp315-cp315-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:6d4a64283ee61824b5790de882bc68e2d9d7a5143537cb7a966f7354f71646d4", size = 480459, upload-time = "2026-09-29T00:54:24.364Z" }, { url = "https://files.pythonhosted.org/packages/ab/d7/fef2a3cb8400701be496f6e459876f650b3451f407e30cb243de571ae615/librt-0.16.0-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5810ba811297fdf37a1531a57667cb8ace0842013ca8606bf9eb7c24cf4be154", size = 507814, upload-time = "2026-09-29T00:54:25.997Z" }, { url = "https://files.pythonhosted.org/packages/e1/6f/53762927a32e9dc9eb1d1c1f3528da281290c86d96929a8af652f671266e/librt-0.16.0-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e56aaf8c167548dc8e5d6f3bd0f48dcdd299a23c73be3f744aab79d99e9c7f5d", size = 525114, upload-time = "2026-09-29T00:54:27.747Z" }, { url = "https://files.pythonhosted.org/packages/6c/67/0b9d031f303c4e8c691a9a8ef9d272f13b530c11cc563b819df621b6a348/librt-0.16.0-cp315-cp315-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8f36c58e33b304b525c6c9c5076399c6ebf1109e17b9051a05a407b091b9215b", size = 520465, upload-time = "2026-09-29T00:54:29.331Z" }, { url = "https://files.pythonhosted.org/packages/ae/d5/2056a3a85864e882eb17a203a10ddb26fa748bc9718ec67e79059ab46cae/librt-0.16.0-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:242e00b3d4fa37c3d3c1ca5f5c9adb7d909ddb1eac9c41f2787320d00caa0af2", size = 537257, upload-time = "2026-09-29T00:54:30.915Z" }, { url = "https://files.pythonhosted.org/packages/54/57/e0d79790c163cbc0909e209a6f62e30bb713b647f905a176cdc64848fd4d/librt-0.16.0-cp315-cp315-musllinux_1_2_i686.whl", hash = "sha256:0253721561787b8df8443eb347b7a6461015354e5bdd37ee38a41fef220d2bb0", size = 527442, upload-time = "2026-09-29T00:54:32.478Z" }, { url = "https://files.pythonhosted.org/packages/aa/50/1c0c95aba7af51f4752ea34fbf2eb79b36e7cae3a72536248e8c735de735/librt-0.16.0-cp315-cp315-musllinux_1_2_ppc64le.whl", hash = "sha256:3e483a8d69ede8067db70c0e83007423b6925de6fd53afed01d66160f2e9398c", size = 548139, upload-time = "2026-09-29T00:54:34.183Z" }, { url = "https://files.pythonhosted.org/packages/98/91/a8a43dd5138d4f55f88846b8f0c85454a4fad69952cebfcff9948f831290/librt-0.16.0-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:69ba927445cfaaffb4081003ef5224c55a5c2ab67ef956f416ef744916e44121", size = 529708, upload-time = "2026-09-29T00:54:35.761Z" }, { url = "https://files.pythonhosted.org/packages/2d/41/d5226881ab2b7c20d9d587b37bdd4a0ec8775a96d00ca87ac9f385587db4/librt-0.16.0-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:d6a365f2ab45a984d0e00eee0dd17f599ceab8cadab6ea07b6111c8132fc0e42", size = 567781, upload-time = "2026-09-29T00:54:37.409Z" }, { url = "https://files.pythonhosted.org/packages/bb/bf/2345ba57a626e8c78c4ddcc724636a8df5a593fe46c1ee76bbf477e32b0d/librt-0.16.0-cp315-cp315-pyemscripten_2026_5_wasm32.whl", hash = "sha256:f01f3805f2dae4781c0c34b440e31740d082950bdaf89a6f601ad589a28af57a", size = 79177, upload-time = "2026-09-29T00:54:38.792Z" }, { url = "https://files.pythonhosted.org/packages/1e/40/99e77936cc9207f629b077bf7cbc5e2f0827cddd7c29792f04ef881bd2c3/librt-0.16.0-cp315-cp315-win32.whl", hash = "sha256:b0e3e721c75d2e79a76d4422c79d7ba705fe1bbafec907037fe7a657a480a0e3", size = 100127, upload-time = "2026-09-29T00:54:40.251Z" }, { url = "https://files.pythonhosted.org/packages/56/1e/801fe26bc622061b9dfd010e166d94142cb774b733217e6d98d1c0cf2638/librt-0.16.0-cp315-cp315-win_amd64.whl", hash = "sha256:bc02954b1295de798bbdb0b4e2d8a28c2117de8b5c73dcbeb27dc32572dfb971", size = 120480, upload-time = "2026-09-29T00:54:41.722Z" }, { url = "https://files.pythonhosted.org/packages/bb/a9/d533983055bd36e112627384c2c038845d1df882540b8bcefb566475640b/librt-0.16.0-cp315-cp315-win_arm64.whl", hash = "sha256:c5db585d43449a5f54303d4b2774e45e1babd975cfe1630a3d708c0b80c3e560", size = 110915, upload-time = "2026-09-29T00:54:43.052Z" }, { url = "https://files.pythonhosted.org/packages/55/fe/d62238fa9c653b0e0613290349467cb65711b5800e8e474f45e942a0ad95/librt-0.16.0-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:f06c689cb14afd9b612727553a5ec5a40febf113ca41c4413a2b0b334285884b", size = 159714, upload-time = "2026-09-29T00:54:44.497Z" }, { url = "https://files.pythonhosted.org/packages/f3/ac/f31efe7818700be72ba4f9af8a80fa67c39808c8d26dacc55dc1f6f35172/librt-0.16.0-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:13b4e8aba90b0b1c82474e9844aa9ffe7ad3faa484350e1da64cb8188d903134", size = 162086, upload-time = "2026-09-29T00:54:45.968Z" }, { url = "https://files.pythonhosted.org/packages/d9/16/4d7487bf86a9d7e8e18f37ba5538789233ea693637379b75701bd35ec9de/librt-0.16.0-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5a269c46ae327d8e6f8c1f85f7516cb52c0fa48127565a1105a4f4a05ff2a0b4", size = 712727, upload-time = "2026-09-29T00:54:47.486Z" }, { url = "https://files.pythonhosted.org/packages/77/74/50cd550ccc1a517b9ed62347625c01ddf8c4afad66490312677c011458f6/librt-0.16.0-cp315-cp315t-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:a33e0dae1f8592146a4764d54ce842b278732d21a84e17c3bbe6b1bc158a2248", size = 681106, upload-time = "2026-09-29T00:54:49.126Z" }, { url = "https://files.pythonhosted.org/packages/df/5d/7293f712975ee6fdd2251411fd9ef1c62bc99c7b83ecbe62dbc999b1fab7/librt-0.16.0-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:47ada6ea32636492c61aa8ad27ae3b9404bfe7a97e3ba946d1984236cc741da0", size = 705921, upload-time = "2026-09-29T00:54:50.905Z" }, { url = "https://files.pythonhosted.org/packages/67/f7/8aab946f11d59d1bece9ffc65d994b200c789a8ca5a95c17e17e609f912a/librt-0.16.0-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c43bd6e642d8a248c114327f98dd25ac5a7cb5aa168ef02f0559b91874df16b8", size = 731786, upload-time = "2026-09-29T00:54:52.584Z" }, { url = "https://files.pythonhosted.org/packages/43/76/1c42ab31e7cb8384ebf6d3af607213c495222474f4940443ae7639ab7685/librt-0.16.0-cp315-cp315t-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c3d1bb7841a816ace6449bb26d3f9560dbfa20e71c568d23f0f62bf1e68f50b1", size = 744964, upload-time = "2026-09-29T00:54:54.217Z" }, { url = "https://files.pythonhosted.org/packages/6f/2e/4b19982d933d2dfced671e840b219e4c1cd3f507df6e6dabb51bbd4e3850/librt-0.16.0-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:3931f7a3db322e7f44e02a280e3949326ce9579ad388ee8d691dc7c76da9fb70", size = 765305, upload-time = "2026-09-29T00:54:55.815Z" }, { url = "https://files.pythonhosted.org/packages/b8/1b/e872583de2dcb3ac7746e7a2321aeeb168274f3952a87dc66e05ddb29faf/librt-0.16.0-cp315-cp315t-musllinux_1_2_i686.whl", hash = "sha256:f4462528b6000afe8f16907b5c7c2553abf1df005ba5140e6eb394541c3624c3", size = 744959, upload-time = "2026-09-29T00:54:57.532Z" }, { url = "https://files.pythonhosted.org/packages/10/de/a18c6bcfb297af2674233e90b3c3661c3a0af0f1434a0c966d2ef708a835/librt-0.16.0-cp315-cp315t-musllinux_1_2_ppc64le.whl", hash = "sha256:80039ba9b6a7d5f1a0175a4cca6bbefead87bd854c80abad1cb30afe47a830db", size = 758138, upload-time = "2026-09-29T00:54:59.484Z" }, { url = "https://files.pythonhosted.org/packages/22/1c/0df1d732539c297bb1a093e1fe3204d2faf76a9022cf4e1d1c2fce059790/librt-0.16.0-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:7a1d272724b581bb6bc769dfdafed6da2ecc9886ba2450311de55a4ac2e1e9cd", size = 744268, upload-time = "2026-09-29T00:55:01.179Z" }, { url = "https://files.pythonhosted.org/packages/a2/f7/ccaf31331f20c91a5bd9bd48ffc3f743f9c81bb5720cc7b2a720ca204f0a/librt-0.16.0-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:fbe4fb8c5445f7496d7f7f6bb0807875d09d47e6771ffa175fb2df2895fb86ba", size = 785783, upload-time = "2026-09-29T00:55:02.938Z" }, { url = "https://files.pythonhosted.org/packages/c1/ea/7421d9e6db894cd6cd788b604b3394a163ded6b942052b6f96c23ccf08e1/librt-0.16.0-cp315-cp315t-win32.whl", hash = "sha256:375bfe6b572a8f6cfc398709356046173bf27e64c4c5edaf5f7062f051fb4bf9", size = 104355, upload-time = "2026-09-29T00:55:04.533Z" }, { url = "https://files.pythonhosted.org/packages/85/6d/7c31a506eb847bc58aeb2402d58e17605e821f68ab5df5e66fe274a6df41/librt-0.16.0-cp315-cp315t-win_amd64.whl", hash = "sha256:bd3150023d3dc2bc70f3784e59ffa1140d56ddba3d8125b3d6f9f85221279bfc", size = 126134, upload-time = "2026-09-29T00:55:06.017Z" }, { url = "https://files.pythonhosted.org/packages/36/69/7a5d10ac409c4da0355e054a14371871da9b5557fcc42772cd00181c6cce/librt-0.16.0-cp315-cp315t-win_arm64.whl", hash = "sha256:8ceafb70f2a4f0826f11031942e59c0728fd98da112dc346d4352bde1e486866", size = 116391, upload-time = "2026-09-29T00:55:07.484Z" }, ] [[package]] name = "markdown-it-py" version = "4.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mdurl" }, ] sdist = { url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49", size = 82454, upload-time = "2026-05-07T12:08:28.36Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl", hash = "sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a", size = 91687, upload-time = "2026-05-07T12:08:27.182Z" }, ] [[package]] name = "markupsafe" version = "3.0.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/38/9b/e422a865e1d5d57d0e509b4e0bf1c1a70a7f6382c29a5aa428df994c8bc8/markupsafe-3.0.4.tar.gz", hash = "sha256:2e9ad7dd851bf45fab9f75cbff4cb493fee9979e8d8c7c9c3ee119022518edd6", size = 153777, upload-time = "2026-10-02T23:07:22.29Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/32/55/18dbb4778b30ada5ce071608503cc3edc9e14e13d868c17a6d178fc30f7a/markupsafe-3.0.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9e25feb9e330b63edb0278a0acdf85e50d0cb0fbf49c3084abbe4e24ae195346", size = 11520, upload-time = "2026-10-02T23:04:36.299Z" }, { url = "https://files.pythonhosted.org/packages/6c/14/0b05f79b4733e264a18d08fe08fa1df7347630ff32a6cb82180d9dccec55/markupsafe-3.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7d3391b2188d18737cb2fa147028b1096236eaa7e156446c650a489fa2cadc91", size = 12063, upload-time = "2026-10-02T23:04:37.291Z" }, { url = "https://files.pythonhosted.org/packages/ca/3a/63ba10b6c1463216b3e4df669a9f0e5a3b0c3071557d2e8229e3968c79fb/markupsafe-3.0.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:849dd2bb0e5e4ab2b71c7191726a4a8d5aa8a610daa584728cbee0b710ddc4ef", size = 24321, upload-time = "2026-10-02T23:04:38.262Z" }, { url = "https://files.pythonhosted.org/packages/1a/2e/5f015261b76ad633d187ef6f388b413aedd64a8773c4df59e530a0be5525/markupsafe-3.0.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:befb4158af32106b9a93db8d6d1d1cbbd418c0d5aca0cabb7b1780abf0c89169", size = 28845, upload-time = "2026-10-02T23:04:39.295Z" }, { url = "https://files.pythonhosted.org/packages/33/cf/26e594b26be40c2f1fec63ccf8a8b99d0335a5b2cbe84835c7d82a994375/markupsafe-3.0.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:71f88e749ea29f67f21f3b36433c1dc54c7729ed2a6d9e2da2e0d9e0d7b224eb", size = 24701, upload-time = "2026-10-02T23:04:40.348Z" }, { url = "https://files.pythonhosted.org/packages/81/a5/a513b76c139a3915b43404324e55c0b7979ae4f0d39eb6f075b0282e90a8/markupsafe-3.0.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6da83a088f8ef93b2d483a8232a4dbf4d69d3d8496b568a03c56becac43e1808", size = 22961, upload-time = "2026-10-02T23:04:41.372Z" }, { url = "https://files.pythonhosted.org/packages/46/cf/4c66192c100b4542bcbe392ae06696b670f66927be3ac38a213234778ff9/markupsafe-3.0.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8f0fac8b13d14bb06c68195f849371924ae53dd7b1c00fed24650f704383b692", size = 21920, upload-time = "2026-10-02T23:04:42.429Z" }, { url = "https://files.pythonhosted.org/packages/cb/17/ac3662678bfbad649893117ada2ba44dc30bf56884e84f13154a792b10f1/markupsafe-3.0.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4a7cdc2a420ca01058182da4253329764d4bfa055564d1eced90e6ba1e8b1d3d", size = 23726, upload-time = "2026-10-02T23:04:43.531Z" }, { url = "https://files.pythonhosted.org/packages/f7/af/fe47cee339180a69ebca3c57fb3483d0f5cbd1e8337d1871fb1d9c1aebee/markupsafe-3.0.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:83b3944fea42a8400edf92fd1770fb8d0d4f7de651353bd2d8525a92dba69a21", size = 22539, upload-time = "2026-10-02T23:04:44.618Z" }, { url = "https://files.pythonhosted.org/packages/12/32/d55440ba140442800e02d799c9cb5ab597bf6ebdb1177b5ea39a11f797bd/markupsafe-3.0.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:8138eb83940ec7299024d92d4dee45f601b9e6c5ffde9d25f4e35e326203c707", size = 23963, upload-time = "2026-10-02T23:04:45.656Z" }, { url = "https://files.pythonhosted.org/packages/50/9d/9c86042cb364c2ad4c971e6d1247929effd25f714cd7ee11b05e6316445b/markupsafe-3.0.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:811d02d5122171c1941357efd8f9bf4ffe907b7f0a1a4e729a880e4be3f46e3e", size = 21506, upload-time = "2026-10-02T23:04:46.671Z" }, { url = "https://files.pythonhosted.org/packages/75/ef/5b824f03ba40c3b3652b6272d083d2fc4fcdd440de519a3a39ba2c3e7262/markupsafe-3.0.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:50b5bedc9ed8a94fc8857a42ef4f84a81ea88f8d4f05dc8705fb23ee6d8dcca7", size = 22955, upload-time = "2026-10-02T23:04:47.698Z" }, { url = "https://files.pythonhosted.org/packages/1e/e8/44cfcb5ea40e5e43cec7793ef90704ed0c475280839076c4345757eb8e59/markupsafe-3.0.4-cp311-cp311-win32.whl", hash = "sha256:2e5a7cd7fdd14fcb1ae5d7d8bf23d24fbd1daefd1fbca2580132e1ea75f098b5", size = 14094, upload-time = "2026-10-02T23:04:48.788Z" }, { url = "https://files.pythonhosted.org/packages/91/89/f2b509f7bf79352e40117824c1070dbeafd4df67031d3fa98165a3134228/markupsafe-3.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:fdb4ca07ab75ffadab4a8b135ad59cdbb3156b99310f3d565370da74a15d6bd3", size = 14328, upload-time = "2026-10-02T23:04:49.801Z" }, { url = "https://files.pythonhosted.org/packages/2b/5a/ccf22672a0f64dc682306e288f0dabcb06c7a201f3bb6e6cbf86d9e8ad03/markupsafe-3.0.4-cp311-cp311-win_arm64.whl", hash = "sha256:569d65055d367e3dcdf30c3f41119467b73d9ee9faf332bdf40402644f5ac08e", size = 14188, upload-time = "2026-10-02T23:04:50.847Z" }, { url = "https://files.pythonhosted.org/packages/81/09/4c59d56b8461ae8eb0d8ba34bb25b7e618547044679d58a82ef9b2479fc1/markupsafe-3.0.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:61631e08084be9e21a8967ec3139c7616ed7c5e9368e05c86d1b39562c8a57b6", size = 11658, upload-time = "2026-10-02T23:04:51.876Z" }, { url = "https://files.pythonhosted.org/packages/a2/f0/d6613774d86fbf6d145751d43c59875e47a6f9f17daee0aef173bd36d90e/markupsafe-3.0.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0930db9bdc62d22944e10b066448bb65dc9abe9112880c7cab8da54db4284d5f", size = 12050, upload-time = "2026-10-02T23:04:52.931Z" }, { url = "https://files.pythonhosted.org/packages/0d/f2/8f18e0b806eb13c1f8d07d917a720831ead54253a6dec011fbc78098a6f8/markupsafe-3.0.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6a45c3d514f2436064db00d7fc8778d888f0236ebfed649b53d13a59e69ad51b", size = 24363, upload-time = "2026-10-02T23:04:53.895Z" }, { url = "https://files.pythonhosted.org/packages/60/ce/fa07dbe8a5675558fa36dea033e19995bc783de2dec5f540ccb9030b06aa/markupsafe-3.0.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:1e1451fab512d1bcc3dc26988ec1edb0b82c2db909132872cd9356070a6b63df", size = 28525, upload-time = "2026-10-02T23:04:54.905Z" }, { url = "https://files.pythonhosted.org/packages/85/40/be87c01f3868ec217f8a2015089d71c22c8c5a75324822e5ed1cdd87210d/markupsafe-3.0.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bd3ce56ae2cbae3ba82b683bc425cd7e48d2ed8b10f3e818186b6f5646d9271c", size = 24733, upload-time = "2026-10-02T23:04:56.229Z" }, { url = "https://files.pythonhosted.org/packages/4f/a7/aeedb5140afa41fc74c225e9184ab96723a6e873b6ee1c9fede7283456d8/markupsafe-3.0.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e124f974786f831d6043728e38296969d3579db8896fe004682f5758e613581", size = 22985, upload-time = "2026-10-02T23:04:57.521Z" }, { url = "https://files.pythonhosted.org/packages/c3/fc/e91352bb08c6a59da3ef0909d457bf95a5f5908fbf151b30a06d9dbcfbb4/markupsafe-3.0.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c02e8f18bdedba082cef725942ac823b9b60656db07f7e265cb31618dfd00d77", size = 22001, upload-time = "2026-10-02T23:04:58.597Z" }, { url = "https://files.pythonhosted.org/packages/5d/f8/bffee5e7d2a3deb59748a797650a48af7e672025cf641a79344a771ad106/markupsafe-3.0.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9f098115c247e11d138ab83a28fa0323c77015007ea2df73ba5fd714dfefd67c", size = 23793, upload-time = "2026-10-02T23:04:59.686Z" }, { url = "https://files.pythonhosted.org/packages/ed/59/b853d6628ecb4d658e1d637224846d5e9bb4adf4f8df97f3be9f29dce2ec/markupsafe-3.0.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d5f93ebbeb8032d47e349328ec8662d973d9b05a70b3c35df1f91fe419b84749", size = 22640, upload-time = "2026-10-02T23:05:00.768Z" }, { url = "https://files.pythonhosted.org/packages/09/b2/1506df394f0f075797c418d0301498f49e43be194e3ffcb49e6fe6ccf022/markupsafe-3.0.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:64511c54db4e4987aef4c41923235927428729e8174c5dba488429be70a998ed", size = 24074, upload-time = "2026-10-02T23:05:01.813Z" }, { url = "https://files.pythonhosted.org/packages/c7/81/5ed69cda630ac69ef60d06c09ba5a7f84ff66a2e28cf986fd5614ab3c6e6/markupsafe-3.0.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:e1a622f13970d81f95d0c72f9dc090dce9085fccfa4c9f2174377ee32bd15786", size = 21563, upload-time = "2026-10-02T23:05:03.239Z" }, { url = "https://files.pythonhosted.org/packages/0c/fe/fb1e79be0fea60aa32602ebefc9c35a82bb42b4df157285ab7dfec12341a/markupsafe-3.0.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c9a7f43c0b202b334cc9184af09bb8f21d3a209e038efaf106936fb69e6b026e", size = 23048, upload-time = "2026-10-02T23:05:04.479Z" }, { url = "https://files.pythonhosted.org/packages/c8/52/7632a53360671a9b750cdbabaf9cdd89f18b42248b8e4cb42c0b0296e459/markupsafe-3.0.4-cp312-cp312-win32.whl", hash = "sha256:f0ec3b750b59375eab5b0fb2b9254810c00a3375be6d789899f1055a1d556237", size = 14108, upload-time = "2026-10-02T23:05:05.513Z" }, { url = "https://files.pythonhosted.org/packages/3f/bf/62495e180b7000aaf30000fff849e933f74264638057176cf46852500adc/markupsafe-3.0.4-cp312-cp312-win_amd64.whl", hash = "sha256:11935df9bf455ed0c04eb87bcd720f02b1fe5e02128a9430f23aed6f93336fc7", size = 14303, upload-time = "2026-10-02T23:05:06.538Z" }, { url = "https://files.pythonhosted.org/packages/c5/8e/4c24208776a65878d656996945aacfbfe010d3720d1a98fc0eb8491fc03b/markupsafe-3.0.4-cp312-cp312-win_arm64.whl", hash = "sha256:a4bbd2d87dd233b9fc5812160c3d0ffbe42edc22a26ce0469f58479ede633fe9", size = 14174, upload-time = "2026-10-02T23:05:07.617Z" }, { url = "https://files.pythonhosted.org/packages/6d/18/4bc5ba32499e87bb2b0ef5b3a9bb9c00a131fa961ddf0be548cb550f548b/markupsafe-3.0.4-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:de8b364c423ef0a4bad9069657d617f9a5d2b2062457a89b1fa16ee199c399c1", size = 12786, upload-time = "2026-10-02T23:05:08.709Z" }, { url = "https://files.pythonhosted.org/packages/4e/6f/17f0c099bf25f3e31e63cc19244d9f6af861a9a4ab778c203997903cfdd0/markupsafe-3.0.4-cp313-cp313-android_24_x86_64.whl", hash = "sha256:34bdde374c5932765d7dc685c4a1d191a3207852d67e8e0a9eb6ea85156181f1", size = 12510, upload-time = "2026-10-02T23:05:09.93Z" }, { url = "https://files.pythonhosted.org/packages/11/af/1a141081b905036ee904ec4bd945e1f70b4e1b32d33c4e59e8cf1d58b247/markupsafe-3.0.4-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:6bd9e1788e15bfcf6a9082de42e30387e7b85d211ab21e57a939bb8cfaaf8d96", size = 11583, upload-time = "2026-10-02T23:05:10.884Z" }, { url = "https://files.pythonhosted.org/packages/e7/0a/a89385ae590232622a03e091805cff12f24fabe6c11e0e8bae096cece81c/markupsafe-3.0.4-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:5066b244f576f91afc8ee3ba029a89f99d39c79b1853fe9d39bea9f0afbec148", size = 11801, upload-time = "2026-10-02T23:05:11.913Z" }, { url = "https://files.pythonhosted.org/packages/ed/85/ea548dc013962eb73653124bc595635fbf9e0fa41d1f181a967ccb784dfb/markupsafe-3.0.4-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7a83aa6e4805df46fed18e989d3d16f86ef60cb50bbc8d9ce3a6be89165fbf6e", size = 11443, upload-time = "2026-10-02T23:05:12.887Z" }, { url = "https://files.pythonhosted.org/packages/cc/72/15f2e5ec9cf2eb00d5cdfe968d94e4156a7bd7303832c3f3b2c403a36839/markupsafe-3.0.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2d1b7d9308288661f56672b1b157d75fc536714d3638487bbea17b6318a78248", size = 11665, upload-time = "2026-10-02T23:05:13.829Z" }, { url = "https://files.pythonhosted.org/packages/ca/e0/4030bea613677e333c8a2c901fd405055f657f9d06acba5b7357984b6ef7/markupsafe-3.0.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:73e77980c7207854f00fc4e71fb1626868d5740ab4012623d55c7a99ad122a72", size = 12061, upload-time = "2026-10-02T23:05:14.807Z" }, { url = "https://files.pythonhosted.org/packages/f3/a5/28b76a7449eb702966b88bef599e2360b411fbb3afeee8fe560939be06ec/markupsafe-3.0.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7018d4af1cd272e847aa5917983ab5e83e4f6579f9dbfecd4a79c0ca80b144c2", size = 24395, upload-time = "2026-10-02T23:05:15.909Z" }, { url = "https://files.pythonhosted.org/packages/07/6c/21232811afc3a063b5e934b1ae2efda52f46154ec382f585149c020e61fe/markupsafe-3.0.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c90d5b3d4e944e065a301d741b3c1d784f6bd1f503aa68b4967e32b2ba313d85", size = 27183, upload-time = "2026-10-02T23:05:16.976Z" }, { url = "https://files.pythonhosted.org/packages/14/38/6ccdfa5b59049cb36fb80cbc80aee9cf1fc9bb77d1335ad435f2070b08cf/markupsafe-3.0.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:18a801868a884f216e784d7d14db2a4077143ce7610440aee2ce8f734e7cfcde", size = 24772, upload-time = "2026-10-02T23:05:18.209Z" }, { url = "https://files.pythonhosted.org/packages/63/e0/cec6865dfe88cb48fedd4b20aed6af5158e41092adcbf3e028bcc6ec2108/markupsafe-3.0.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:434139499bb20b502ed3baa1f169e618f924a97e7a777fea1a49446d80106cf6", size = 23017, upload-time = "2026-10-02T23:05:19.286Z" }, { url = "https://files.pythonhosted.org/packages/ee/76/6ed4940bb7648a9aac457c14f870cfdd5105f139a0fb1f29cd61fafa47d1/markupsafe-3.0.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9e227f3dbe6bde7491cf0a9965d00b88c6b1a4a95d11480ddf88bb96d397c19f", size = 22036, upload-time = "2026-10-02T23:05:20.352Z" }, { url = "https://files.pythonhosted.org/packages/a1/4f/ed476226d4fe46a09090a36025bf319296810028df55eb12f1253b540f3a/markupsafe-3.0.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b8cd1f918b26fd7b1832ece557cc18f2d8747309ff8b3f0ef9d4250c5ad67a39", size = 23786, upload-time = "2026-10-02T23:05:21.576Z" }, { url = "https://files.pythonhosted.org/packages/9a/35/66ff30450e35ef5fba9ebc930c9411747e537fd9447b65e44f5007e2b84d/markupsafe-3.0.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a5fcffb37e602b0b3c1638a97746b9b96125caa9bcf6fa41d337a9261de231ee", size = 22672, upload-time = "2026-10-02T23:05:22.922Z" }, { url = "https://files.pythonhosted.org/packages/32/0b/72f45ce4b4efcbca4b80cf1b06703eff0be8d37e82abb78f66c85a7ead1e/markupsafe-3.0.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5989cb26b2e1efc6a42216a9f6b5ee495ce5ace2e5b352a9af489976b32d1ee2", size = 24107, upload-time = "2026-10-02T23:05:24.175Z" }, { url = "https://files.pythonhosted.org/packages/d2/03/71776e5fdcba04614b384cc102e8a4198208579d896fd1394cb7cb9aa900/markupsafe-3.0.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:add96447a86d205ab616665d53b2950ee81083757f56e6ea833c8b2917646b46", size = 21615, upload-time = "2026-10-02T23:05:25.215Z" }, { url = "https://files.pythonhosted.org/packages/ab/5f/801ce02a02e7aee0f784b1ec7843026178f6adeb9c93ac67eb1992a9a84d/markupsafe-3.0.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2628d3a8cb648ecebb3c5d6b0a1052d400e4d8b7ac0fb786be8d285b50040d17", size = 23076, upload-time = "2026-10-02T23:05:26.423Z" }, { url = "https://files.pythonhosted.org/packages/4a/85/c43776625428f3bb4a61e8633940400e3efe6409e3c6f5bff26de5e45618/markupsafe-3.0.4-cp313-cp313-win32.whl", hash = "sha256:672d207103e6b16ca098611b0f9efad6bc00afd47c03d6ef62186495ca677dc0", size = 14118, upload-time = "2026-10-02T23:05:27.716Z" }, { url = "https://files.pythonhosted.org/packages/6f/36/163da64de88a13db79214ef75fa041be7fa13bdb42261cf5b7484de14bfb/markupsafe-3.0.4-cp313-cp313-win_amd64.whl", hash = "sha256:1f1f9477e174582b0a1b583d60b66e1f2cf5d3fe12cee985e4aedf44766600e5", size = 14313, upload-time = "2026-10-02T23:05:28.749Z" }, { url = "https://files.pythonhosted.org/packages/9f/a8/9b662783ffaa1149221432a923cee562f78b9cbbb8baa3df9b3753e63e1e/markupsafe-3.0.4-cp313-cp313-win_arm64.whl", hash = "sha256:06de8ef6331f6e822c28d577dc8bf43fe398800477c49498f38fc38b67ff33fc", size = 14189, upload-time = "2026-10-02T23:05:29.917Z" }, { url = "https://files.pythonhosted.org/packages/5c/c3/a944f3b0df22bd129e96915b9f4e98d2eeca6516687d7618304a966c3c74/markupsafe-3.0.4-cp314-cp314-android_24_arm64_v8a.whl", hash = "sha256:4ed644d75aa94a2baf7ec3a96eaa160ea58c742eb9d27c6506053c5c40fc84ed", size = 12787, upload-time = "2026-10-02T23:05:30.971Z" }, { url = "https://files.pythonhosted.org/packages/d4/d6/a44863f69d88b6c7e27889108f70d47aed259edf89d5df3c5fca1eac87d6/markupsafe-3.0.4-cp314-cp314-android_24_x86_64.whl", hash = "sha256:6d2a9efe686f9de00d0d1ea32a4a5a86d558a2277501bd78d964214eab625e59", size = 12525, upload-time = "2026-10-02T23:05:32.263Z" }, { url = "https://files.pythonhosted.org/packages/17/8f/168ba80e532dd6a93f96f8f706f1ad41d7990b6e1aeedc1cc0d211a33497/markupsafe-3.0.4-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:8781a792a070cf2bd1b86d3aa943894115faaba6e88122a7bf32d62072742453", size = 11589, upload-time = "2026-10-02T23:05:33.251Z" }, { url = "https://files.pythonhosted.org/packages/32/b3/aa2c95a574d3af39403a469b295886eb9b6d448da568cbebb5a2cbfdc2e5/markupsafe-3.0.4-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:971a3bbb75d97ae4e2e8f7d4834236f86f85f0c85e04ab2e191db1123b04f80b", size = 11801, upload-time = "2026-10-02T23:05:34.315Z" }, { url = "https://files.pythonhosted.org/packages/60/d0/34b810107d83840e768bf485de795893ebbae35b26ab061b487adfa0a692/markupsafe-3.0.4-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:8909c2f1c6dd65e054ac4b573a91c8384d1492281e55d82d159d653f7a13adf6", size = 11447, upload-time = "2026-10-02T23:05:35.302Z" }, { url = "https://files.pythonhosted.org/packages/6c/ab/2f8488f0f817a39fca068d2b17daf446bf5cdb3eae28c3720af534d873b4/markupsafe-3.0.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:4cf3468d5ec187ffffcaca8e61929a37448f215dafc1386a12c750a72fe53634", size = 11722, upload-time = "2026-10-02T23:05:36.363Z" }, { url = "https://files.pythonhosted.org/packages/ad/40/e2d117b048d47282ade906fbfd92814cbee5647afc13fda88a3406039372/markupsafe-3.0.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:52704c5d36eb6dda8866493decd61111fff86244c9b1ad225ca01b9e91e5970f", size = 12061, upload-time = "2026-10-02T23:05:37.397Z" }, { url = "https://files.pythonhosted.org/packages/9a/a8/73a81135e85ba66217f5af7facb03bbb386807e1a729ab64532e4c802652/markupsafe-3.0.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1caa2fa5a6184fb233153b35f654e6687bd555476f6170f29d8ee9be1a8b0af9", size = 24434, upload-time = "2026-10-02T23:05:38.407Z" }, { url = "https://files.pythonhosted.org/packages/ac/ca/fa9216dd01efee2dfdacafe7df32b4d0170fbac694b0c258a193d6e53999/markupsafe-3.0.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:387d8cd30e69b3f0a72877b9ae717033396404e19095b17fe89753a981fda44f", size = 27183, upload-time = "2026-10-02T23:05:39.581Z" }, { url = "https://files.pythonhosted.org/packages/fa/4e/a469509e538d37af51103b17b073126973f2b1cbf197ff32c7ddf025cfe5/markupsafe-3.0.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:051417f74bcaaefa316276e0ff723f541616ca51043d070da00249d9bddd3e3c", size = 24813, upload-time = "2026-10-02T23:05:40.671Z" }, { url = "https://files.pythonhosted.org/packages/8f/db/d7282caf7ab03af44d5d6fdbaa019b35c7d7f1c90588b839c07cba640d6a/markupsafe-3.0.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8e9f292fcda89b324f2f5c91d13f1424a153e40fc2756f38ee23b15835ff300", size = 23049, upload-time = "2026-10-02T23:05:41.864Z" }, { url = "https://files.pythonhosted.org/packages/30/f3/b6a425206e6964efda6acee544d0eb01d1501784d0b8e2dcc74986f33b17/markupsafe-3.0.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:df1ae86ff54725a01fa1a0510b914ca53a161b7050be74f6204e24aded5971d0", size = 22088, upload-time = "2026-10-02T23:05:43.014Z" }, { url = "https://files.pythonhosted.org/packages/ea/8a/84d3582fc1f0d5bd466cdf2eebf175e172158a6e70701aacec1de1b35430/markupsafe-3.0.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8965520ac587c94a4ac48b729be3d8b8de00af39699b17585dfb599babe77977", size = 23846, upload-time = "2026-10-02T23:05:44.098Z" }, { url = "https://files.pythonhosted.org/packages/1c/65/db101cce51b7ba4864ac491a9859d297dd1adf0e55b103fee9db9c47c527/markupsafe-3.0.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:340cbb1957ba99929cbf19a75626d36ba1ae21d1730b287d1cf7f824a20c4fc7", size = 22674, upload-time = "2026-10-02T23:05:45.23Z" }, { url = "https://files.pythonhosted.org/packages/e0/49/ddee9813d71db0c7a5c9d97c832125e6758a0c844777f1cf076569bb0e22/markupsafe-3.0.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:3a93d9616ddecfb393727a0041a562cf0b15a244e20f2bd25efc7949be4c4f17", size = 24104, upload-time = "2026-10-02T23:05:46.398Z" }, { url = "https://files.pythonhosted.org/packages/aa/0e/7d8518d726726870a2399d69fd30d0fa36c5e57a2132c336b58d7c491073/markupsafe-3.0.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:d2e56fd3b00222722abfb3f5f0759ddbae4b90811b5ad4343c64030ad1bde70c", size = 21637, upload-time = "2026-10-02T23:05:47.48Z" }, { url = "https://files.pythonhosted.org/packages/b4/b0/b505e8a361ba557dbf3b3aa7331ea39b00d2022a26e925ff8463b9714bb3/markupsafe-3.0.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:0d9c47709875fdb321452056622e930c52afbc07a7d780762fbb8b4d91ce6fa4", size = 23081, upload-time = "2026-10-02T23:05:48.611Z" }, { url = "https://files.pythonhosted.org/packages/1c/ea/9cc3cea873f980c75cbdb6f4277ce30ee955de38be0b3d02f14c108e0698/markupsafe-3.0.4-cp314-cp314-win32.whl", hash = "sha256:38fc55594dab834470b6733dead2ee9e3f657fb0608c769dcafa0ba5ab52f45c", size = 14272, upload-time = "2026-10-02T23:05:49.707Z" }, { url = "https://files.pythonhosted.org/packages/80/f0/5792ff768a410f93ee3f84fc19345295ffc352d2c936b424cb37e514714c/markupsafe-3.0.4-cp314-cp314-win_amd64.whl", hash = "sha256:c1bc67752d5f21013cfe430df4062441714eab79f65a6a05e01505957e9c35fe", size = 14501, upload-time = "2026-10-02T23:05:50.788Z" }, { url = "https://files.pythonhosted.org/packages/5f/cf/3d074a8edffcc6899355232ff2543ae8d929733239596423b7db79698bc9/markupsafe-3.0.4-cp314-cp314-win_arm64.whl", hash = "sha256:7e1636da3d8dfc220b6dd10264db5f2b165e4888c4518594898fbe381049af8a", size = 14364, upload-time = "2026-10-02T23:05:51.857Z" }, { url = "https://files.pythonhosted.org/packages/d9/31/87ce42159aae2163cf3bbbd0c44bc87780510eecab1ea3859099aed95dcb/markupsafe-3.0.4-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:805c8b84534fa10891890f0e4be39f3a99e94615d93e8836bf9fa1fdca2feeb2", size = 11759, upload-time = "2026-10-02T23:05:52.951Z" }, { url = "https://files.pythonhosted.org/packages/5f/53/b047207eeb7752e960aca3eb1df5fb7eefa7dd4c62ac49bb156456c8a702/markupsafe-3.0.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:fa95848c929b6a75f6848d3c9793e59db365ee436776e57db835cdbfa79ba977", size = 12096, upload-time = "2026-10-02T23:05:54.066Z" }, { url = "https://files.pythonhosted.org/packages/ee/51/4326c88a13c7b755657d44b4bb986f8c3d9843ecba7e22d98661d87f9a57/markupsafe-3.0.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e916035e3e9930cbdfdd10abf48861340221857f45509565898e012263f7b289", size = 25699, upload-time = "2026-10-02T23:05:55.15Z" }, { url = "https://files.pythonhosted.org/packages/f2/bb/990581b7474bfcf2cf34bed6ba5ea23bd87adb9d671213d68e88620e7a6b/markupsafe-3.0.4-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b4d12837e0203bbace818ff4a7461afdcd78bcd782351cea148139180d7bcffe", size = 27804, upload-time = "2026-10-02T23:05:56.29Z" }, { url = "https://files.pythonhosted.org/packages/6b/89/89491878c28e8291f5aa2fffe2c2d57230d10ae366d55dd810b840513d78/markupsafe-3.0.4-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5086f9975abb1ab531ee6afca1761e4b59a19b446f3f6522ed776963228cfe5a", size = 25912, upload-time = "2026-10-02T23:05:57.416Z" }, { url = "https://files.pythonhosted.org/packages/30/77/680998b54efdea06fc114565cd739b6d059f826a0279219b218dfa750d29/markupsafe-3.0.4-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b4a635a0487774f841cb1fb62e907e7195cc95bc761e053184b8acc3ceb20733", size = 23623, upload-time = "2026-10-02T23:05:58.557Z" }, { url = "https://files.pythonhosted.org/packages/ae/75/2709f5ac5de9467b40b10e2bb8f89cc63dfb74582e09aa734b1124a217de/markupsafe-3.0.4-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb96e6e088d6cf71c1ea977510948320234824cf226e32f6f6e044f7a9c82b34", size = 23301, upload-time = "2026-10-02T23:05:59.94Z" }, { url = "https://files.pythonhosted.org/packages/a0/c8/39eadc6c5b14c9c7679bfb98f4d4c6a97863b5beb91839aca4d2d6e16e55/markupsafe-3.0.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8b5d563170ff8ba3181caa967c99a3c804d1dedb702c7cb93a6a7c32247da978", size = 24950, upload-time = "2026-10-02T23:06:01.289Z" }, { url = "https://files.pythonhosted.org/packages/1a/5e/01037f8a43e8ccb0bffb4fbdc5212db05bf080fdd7286cd392332d58128a/markupsafe-3.0.4-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:396ec4e65cc889f69786b3b89478b471cee5a3bcf468b9d9bb03e1a30fb291fc", size = 23330, upload-time = "2026-10-02T23:06:02.441Z" }, { url = "https://files.pythonhosted.org/packages/d4/f4/23e83ce0596bb0cbe670502d31df8f757bbd01a392aa486fa3b40d1ed399/markupsafe-3.0.4-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:15ba9e28640feef770374b116a6f019c21f52404aeabe516aa7f800587b98cfc", size = 25239, upload-time = "2026-10-02T23:06:03.579Z" }, { url = "https://files.pythonhosted.org/packages/88/5b/3708897368073cc683d524750474f41a77d2986152c380dcc55b20fdf340/markupsafe-3.0.4-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:d920abdfa61279ba1a2ef9484aab07bf03331f8c08a10120fa332353d06e6932", size = 22767, upload-time = "2026-10-02T23:06:04.699Z" }, { url = "https://files.pythonhosted.org/packages/c6/61/ebda1307864b409e6b3115757a3d4a09cca46cfb6cc65191b5de226b424b/markupsafe-3.0.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a9f54054101545a9a9cccefddf54316aa6e4491611fcbef9e91b3b6bebec04f6", size = 23668, upload-time = "2026-10-02T23:06:05.9Z" }, { url = "https://files.pythonhosted.org/packages/09/15/98075cceac3b5ba0dbb8e4762a847be967d2befc349a2cf2d0ac77f62c9d/markupsafe-3.0.4-cp314-cp314t-win32.whl", hash = "sha256:12a606a492de952afcb43b59a14aaaaad120e708d3663dd0fdf2d738d427a691", size = 14301, upload-time = "2026-10-02T23:06:07.109Z" }, { url = "https://files.pythonhosted.org/packages/0b/a3/768b560fcc4156685cb563d922b217810cfa7bc135773367f62f1f9d2078/markupsafe-3.0.4-cp314-cp314t-win_amd64.whl", hash = "sha256:a18f38cafc329bac5e3c2b96c765b4c96d3d103421ed22ab7988c1e3fce27464", size = 14526, upload-time = "2026-10-02T23:06:08.276Z" }, { url = "https://files.pythonhosted.org/packages/93/63/da554b4c97a6b0ea3229ca7fe8cbfb620be81613d517f482e85958550537/markupsafe-3.0.4-cp314-cp314t-win_arm64.whl", hash = "sha256:eba154571c16e032112afac0dc2dfe9e63c2ceb7aedd07bb7eecf2ce26d4dd4c", size = 14421, upload-time = "2026-10-02T23:06:09.402Z" }, { url = "https://files.pythonhosted.org/packages/a9/30/54d11c8ca027114898cab97421fb39e4ffd9ddf47cdbc44df2ec76722da9/markupsafe-3.0.4-cp315-cp315-android_24_arm64_v8a.whl", hash = "sha256:737c9c3981998eba27f11786f84fddcbabc74068b72a4a1f454ea02094b57b65", size = 12791, upload-time = "2026-10-02T23:06:10.485Z" }, { url = "https://files.pythonhosted.org/packages/10/6d/97c913e253a14bd3cd0e15a5c56d13203b823fa7ee32498342896a072dc4/markupsafe-3.0.4-cp315-cp315-android_24_x86_64.whl", hash = "sha256:489505b03f692c3f376394e49194fa7a7f9e8558d6e293a7056a0032b0c38163", size = 12527, upload-time = "2026-10-02T23:06:11.834Z" }, { url = "https://files.pythonhosted.org/packages/26/f9/b86d032042a4d597d9e1997f0e5f63a3eedaf11258e0a05760b0a0a826ea/markupsafe-3.0.4-cp315-cp315-ios_13_0_arm64_iphoneos.whl", hash = "sha256:077293e425f28ec737dbcad442a71752e28f8ae27cde3d68acd1fb212091cd92", size = 11602, upload-time = "2026-10-02T23:06:13.122Z" }, { url = "https://files.pythonhosted.org/packages/f2/dc/73c14c1eedf0ac5fa3292ba43435e6c49d2c2050f33cebde541f8f4807f1/markupsafe-3.0.4-cp315-cp315-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:9348cbb300d224fe3b89793262cb093504d4ae927004468463f745188a193e4a", size = 11817, upload-time = "2026-10-02T23:06:14.227Z" }, { url = "https://files.pythonhosted.org/packages/8f/69/2c2fcaa5fcee22d72c7819c0d536fd181c74a688e6143845419579cd2863/markupsafe-3.0.4-cp315-cp315-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:b807e598953730f82e4eae3bd30f6a122cf6b31c398c6b504c0e04c13c170429", size = 11446, upload-time = "2026-10-02T23:06:15.574Z" }, { url = "https://files.pythonhosted.org/packages/88/54/9e5ec76c62e6e2834d5a93623018c943e8b3bb41d663e3fd4c03303b9b85/markupsafe-3.0.4-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:799c39bdf5e2f1292fedd3009f7b3c9e760f10b2420cb9638d56920840ff6db8", size = 11719, upload-time = "2026-10-02T23:06:16.701Z" }, { url = "https://files.pythonhosted.org/packages/96/24/3ec292b44064c16229e064d770b2625bd8ea941aa61f44905a9fa44942c0/markupsafe-3.0.4-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:ae9dcb8fbe244cb82f8a6458b455b927a03685e383d9bacf1ea5ce180b96dc97", size = 12075, upload-time = "2026-10-02T23:06:17.855Z" }, { url = "https://files.pythonhosted.org/packages/aa/85/b64fdb1f304848518742136983c24e96d967bfb59a0ea160e92736901ab0/markupsafe-3.0.4-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bced6e2a6dba6a28f7dd3c6ce14df1b2dd495923f16ea484cad03decd463b2b", size = 24656, upload-time = "2026-10-02T23:06:18.963Z" }, { url = "https://files.pythonhosted.org/packages/9c/18/23997d4c65b355da6390d61cd56e0ab3befd6ba8dda25cb40c602bd0fa6b/markupsafe-3.0.4-cp315-cp315-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3882fb412298575bae3b9c46868251f15cc69307359f87bb1b382e53d6e5a2c9", size = 27737, upload-time = "2026-10-02T23:06:20.117Z" }, { url = "https://files.pythonhosted.org/packages/d4/36/35998dead3c6af88c38265a56e58100211f036234ab88eb2283fd4cbce44/markupsafe-3.0.4-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:04e7902ba80ee4bac1d50a549606527a1dcf0476cd81403db41099d3b60ec653", size = 25003, upload-time = "2026-10-02T23:06:21.284Z" }, { url = "https://files.pythonhosted.org/packages/82/96/ef49135ce260db4ca4a12b119ed468449cd248db6b1468e2112b546d7a2e/markupsafe-3.0.4-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:925f929d6b59a8b3f8b8c6ac363cd0af7eecc81efb3071770b3c6717c450a369", size = 23111, upload-time = "2026-10-02T23:06:22.524Z" }, { url = "https://files.pythonhosted.org/packages/50/7d/83126e338bd88c17a220668235368ad719fd4638e426739858cbb8508f77/markupsafe-3.0.4-cp315-cp315-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f68edfc67aabac33708941f26f22a7b8e9f81429bc0cf249fcf7d66b23af8d19", size = 22403, upload-time = "2026-10-02T23:06:23.785Z" }, { url = "https://files.pythonhosted.org/packages/83/dd/daf7e420de23c8206c365204e7b85e1251d8e19d34196a56336f316e5ed2/markupsafe-3.0.4-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:e5c802729725bd07e2bc3ab7b76dc7e0bbfc53129d8f1eb1c002c24cf774717e", size = 24083, upload-time = "2026-10-02T23:06:25.037Z" }, { url = "https://files.pythonhosted.org/packages/19/3c/11eecdc06bc44ad5570350085b572ebf049e8f9a38d1ece6d76640b739cd/markupsafe-3.0.4-cp315-cp315-musllinux_1_2_armv7l.whl", hash = "sha256:55ffd6ce583d97dc71dc92e930324c8c0d25aea7e3ade6ae54ef77cedb096811", size = 22931, upload-time = "2026-10-02T23:06:26.328Z" }, { url = "https://files.pythonhosted.org/packages/0d/9e/ac0fd77f2a726e56ecc3ca0235d095feace1358d1b822406c2a2ef26a4dc/markupsafe-3.0.4-cp315-cp315-musllinux_1_2_ppc64le.whl", hash = "sha256:2cb3dd71fc6be918ad4264346a8ed69485f9b7ed7bf35495d8e22807cd6b8bea", size = 24299, upload-time = "2026-10-02T23:06:27.742Z" }, { url = "https://files.pythonhosted.org/packages/d7/09/c6bd842ad58ff5b3bc76eeed7e9a42a6f11adc5d090ec697b72c9672731e/markupsafe-3.0.4-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:94f5407f7bc64fa6463906b896f9904beeeb7dd8dc116ee8e9056c8714ff9916", size = 21948, upload-time = "2026-10-02T23:06:29.274Z" }, { url = "https://files.pythonhosted.org/packages/a3/46/82f586711fed61e86faa1ee1bc317d68cd45a10c8bdbe3f7d1fdf9026ad8/markupsafe-3.0.4-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:2dad610540cb2e6272855c178f08ae9a1c7ac258a7fb71660553a5f104b42741", size = 23150, upload-time = "2026-10-02T23:06:30.583Z" }, { url = "https://files.pythonhosted.org/packages/19/2d/2dfdce99318abbfa26925195fbc17db188c46a1ec6457be121b6f9cfeb42/markupsafe-3.0.4-cp315-cp315-win32.whl", hash = "sha256:03470d1a8268e692ecf79ecd565593e59d44219377a7ead61f1f1b94c1f7ff6b", size = 14269, upload-time = "2026-10-02T23:06:31.949Z" }, { url = "https://files.pythonhosted.org/packages/5b/ec/6000fd82e8791e58fcd0456ec20f098957e2b03d5ed02eb73241a577c0ba/markupsafe-3.0.4-cp315-cp315-win_amd64.whl", hash = "sha256:d882a373d8093c2941e01291b7ced96e9cbe4781da9a7751ca7e6c70385e5214", size = 14496, upload-time = "2026-10-02T23:06:33.258Z" }, { url = "https://files.pythonhosted.org/packages/bc/66/e73bd5016421d5d6e2fb6de7dd609f9de020942ac8c626526bd8c6eeaf82/markupsafe-3.0.4-cp315-cp315-win_arm64.whl", hash = "sha256:353bd63081912ab8cfa6a0c7d185934cdf8426f04c618bba6bc4b394f2069b67", size = 14361, upload-time = "2026-10-02T23:06:34.539Z" }, { url = "https://files.pythonhosted.org/packages/90/df/cb8c3dc98d313a951df2f8968f44e4cb5643df6d3cab749a530ce2f7d972/markupsafe-3.0.4-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:c61750fadcd119d0825bcb7d7d675dd264dcc89cc05292aab5be68ebdbb374ad", size = 11760, upload-time = "2026-10-02T23:06:35.807Z" }, { url = "https://files.pythonhosted.org/packages/d6/bb/4af9b3ca0753d654ac75f9531d5bd741bb77ca6e696f36807c475ffc099a/markupsafe-3.0.4-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:1c0df495a977d10460a94941799c72d5b5ab03d3858d949b55b5a66c8f371c99", size = 12108, upload-time = "2026-10-02T23:06:37.089Z" }, { url = "https://files.pythonhosted.org/packages/3f/d4/b56429313aee5fd59b079c3df5615299959e25e7113eb6d8caadbdd7d38a/markupsafe-3.0.4-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:02fa4acbc6a3fc5c693c34d4dd8c1130b7fe99cc915181b0ddd6f72aeb296002", size = 25762, upload-time = "2026-10-02T23:06:38.419Z" }, { url = "https://files.pythonhosted.org/packages/65/f5/34c181e891aa4f7d59c918584672e0c5eb7fffe76c1387d1246008bf4081/markupsafe-3.0.4-cp315-cp315t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:05295589e619b9bed252a86b532b8e27350abc372d18ba89b59375325e91ec1e", size = 28400, upload-time = "2026-10-02T23:06:39.819Z" }, { url = "https://files.pythonhosted.org/packages/ce/b5/ad14694fd0ac9a5ce30bc6498f2999378f418583dd1679cca5a1b512957e/markupsafe-3.0.4-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:be6cb0c799abb0e2ba3e618e6d28ddddf7e485f6c2ce938dfa237daf3905072c", size = 25946, upload-time = "2026-10-02T23:06:41.381Z" }, { url = "https://files.pythonhosted.org/packages/d6/a8/26b606445387d0ceb1eb1f21840094b84e4e3c3c3983d80d10b89823b490/markupsafe-3.0.4-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:26e9867520db70d37f7fb421a7f0d8adb40171011fb84ce869afa1a83370dfa8", size = 23634, upload-time = "2026-10-02T23:06:42.748Z" }, { url = "https://files.pythonhosted.org/packages/39/a2/b8814de672f1f0094d498bf646f2fec9d6356b503d28ef500b71c5095377/markupsafe-3.0.4-cp315-cp315t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f03460ff076f70ab595bb45a0205ccea1971443575b6920c52e755dec2b3fbfe", size = 23488, upload-time = "2026-10-02T23:06:44.176Z" }, { url = "https://files.pythonhosted.org/packages/db/c7/287223376fb73335a3cc5d6eb22c6ab01358cf33945a9c39c06b9dac3f4b/markupsafe-3.0.4-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:436e3ffc6310d3c41878c601db29098102fe5d8a467c49da4a4125254e0980f2", size = 25037, upload-time = "2026-10-02T23:06:45.646Z" }, { url = "https://files.pythonhosted.org/packages/f9/29/4df8355e313426d19e62ba33e0253c009ca12a0894ee77d67fa67255361c/markupsafe-3.0.4-cp315-cp315t-musllinux_1_2_armv7l.whl", hash = "sha256:4e2c4809c14559aa7ef426f27fb35afbb38104c349a903bf8f3600456764bb38", size = 23543, upload-time = "2026-10-02T23:06:47.264Z" }, { url = "https://files.pythonhosted.org/packages/71/e5/8377731e8495668dcc768f645e717df18318c841edaf023a99395f6da9b4/markupsafe-3.0.4-cp315-cp315t-musllinux_1_2_ppc64le.whl", hash = "sha256:da2af0d7aebfc2074080d72efa6ab8317c62481ef1f896f65d9999c1c01f4494", size = 25282, upload-time = "2026-10-02T23:06:48.795Z" }, { url = "https://files.pythonhosted.org/packages/ed/5f/373456e37ceb1478d657d6fe769cbe0a39f0a8dfc1548eeb19c471eefdd9/markupsafe-3.0.4-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:aa2c838cc024642cc04c6854232f32b43e5e22833dd11119c1766c7873b8370d", size = 22993, upload-time = "2026-10-02T23:06:50.31Z" }, { url = "https://files.pythonhosted.org/packages/d7/93/2cbd5628435afb6f541bbaced4bce0c2edac4b09a142e6e928b8b0da9858/markupsafe-3.0.4-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:b91cc9d336957239ff200f30097e6fea2dc6d6fb3c81e853eaa09eac904fd894", size = 23712, upload-time = "2026-10-02T23:06:51.759Z" }, { url = "https://files.pythonhosted.org/packages/81/99/157e10966b033b363aeda5263e82596ee232a0b1d082fdbf90aa417ff083/markupsafe-3.0.4-cp315-cp315t-win32.whl", hash = "sha256:e49fb0d1ce92cfa0cb198cc5b1b11cdf9d0638658e2a2db2687e39db7c87fc78", size = 14300, upload-time = "2026-10-02T23:06:53.241Z" }, { url = "https://files.pythonhosted.org/packages/33/05/55884815414c9706a23deca150b72c25a62109e65b0b6ce232077802c719/markupsafe-3.0.4-cp315-cp315t-win_amd64.whl", hash = "sha256:4f6e0852a0283b1b1fd776eeb7b766a5f440b3e2bd31ab51af3b400585f3965c", size = 14522, upload-time = "2026-10-02T23:06:54.729Z" }, { url = "https://files.pythonhosted.org/packages/92/f9/ecbde7149e95b8a0f18e16d5d747f7dc06049d5da2e4f77f6f5e4a1f46a8/markupsafe-3.0.4-cp315-cp315t-win_arm64.whl", hash = "sha256:39dbacefc411633db5b4378b066a9aca70a3d7e2922c9e578d825f844026eeba", size = 14417, upload-time = "2026-10-02T23:06:56.246Z" }, ] [[package]] name = "matplotlib-inline" version = "0.2.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "traitlets" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bd/c0/9f7c9a46090390368a4d7bcb76bb87a4a36c421e4c0792cdb53486ffac7a/matplotlib_inline-0.2.2.tar.gz", hash = "sha256:72f3fe8fce36b70d4a5b612f899090cd0401deddc4ea90e1572b9f4bfb058c79", size = 8150, upload-time = "2026-05-08T17:33:33.49Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/41/09/5b161152e2d90f7b87f781c2e1267494aef9c32498df793f73ad0a0a494a/matplotlib_inline-0.2.2-py3-none-any.whl", hash = "sha256:3c821cf1c209f59fb2d2d64abbf5b23b67bcb2210d663f9918dd851c6da1fcf6", size = 9534, upload-time = "2026-05-08T17:33:32.055Z" }, ] [[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 = "monty" version = "2026.10.21" source = { editable = "." } default-groups = "all" dependencies = [ { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, { name = "numpy", version = "2.5.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, { name = "ruamel-yaml" }, ] [package.optional-dependencies] dev = [ { name = "ipython" }, ] json = [ { name = "orjson" }, { name = "pandas" }, { name = "pint", version = "0.25.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, { name = "pint", version = "0.26.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, { name = "pydantic" }, { name = "pymongo" }, { name = "torch" }, ] multiprocessing = [ { name = "tqdm" }, ] optional = [ { name = "ipython" }, { name = "msgpack" }, { name = "orjson" }, { name = "pandas" }, { name = "pint", version = "0.25.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, { name = "pint", version = "0.26.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, { name = "pydantic" }, { name = "pymongo" }, { name = "torch" }, { name = "tqdm" }, ] serialization = [ { name = "msgpack" }, ] [package.dev-dependencies] dev = [ { name = "coverage" }, { name = "pre-commit" }, { name = "pytest" }, { name = "pytest-benchmark" }, { name = "pytest-cov" }, ] lint = [ { name = "mypy" }, { name = "ruff" }, ] maintain = [ { name = "invoke" }, { name = "myst-parser" }, { name = "requests" }, { name = "roman-numerals" }, { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, { name = "sphinx", version = "9.1.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, { name = "sphinx-markdown-builder" }, { name = "sphinx-rtd-theme" }, ] [package.metadata] requires-dist = [ { name = "ipython", marker = "extra == 'dev'" }, { name = "monty", extras = ["dev", "json", "multiprocessing", "serialization"], marker = "extra == 'optional'" }, { name = "msgpack", marker = "extra == 'serialization'" }, { name = "numpy" }, { name = "orjson", marker = "extra == 'json'", specifier = ">=3.6.1" }, { name = "pandas", marker = "extra == 'json'" }, { name = "pint", marker = "extra == 'json'" }, { name = "pydantic", marker = "extra == 'json'" }, { name = "pymongo", marker = "extra == 'json'" }, { name = "ruamel-yaml" }, { name = "torch", marker = "extra == 'json'" }, { name = "tqdm", marker = "extra == 'multiprocessing'" }, ] provides-extras = ["dev", "json", "multiprocessing", "optional", "serialization"] [package.metadata.requires-dev] dev = [ { name = "coverage", specifier = ">=7.7.1" }, { name = "pre-commit", specifier = ">=4.2.0" }, { name = "pytest", specifier = ">=8.3.5" }, { name = "pytest-benchmark", specifier = ">=5.2.3" }, { name = "pytest-cov", specifier = ">=6.0.0" }, ] lint = [ { name = "mypy", specifier = ">=1.15.0" }, { name = "ruff", specifier = ">=0.11.2" }, ] maintain = [ { name = "invoke" }, { name = "myst-parser" }, { name = "requests" }, { name = "roman-numerals" }, { name = "sphinx", specifier = ">=7.4.7" }, { name = "sphinx-markdown-builder" }, { name = "sphinx-rtd-theme", specifier = ">=3.0.2" }, ] [[package]] name = "mpmath" version = "1.3.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" }, ] [[package]] name = "msgpack" version = "1.2.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/0a/e7/bb605a7bab2d8425a64b3fa762b39dc1bf1c7e3f11ba6fb5413d6db0ff8c/msgpack-1.2.3.tar.gz", hash = "sha256:32edb81a2b5eb7cd7c9d941b2bfbbb082fd2cd09e0e725930316af6b708db186", size = 196517, upload-time = "2026-09-29T02:33:52.276Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/2a/95/b9c651ccb9d720b2e2c8d537954dff528ab869a03bf89598145716db823c/msgpack-1.2.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ec90a9ae3e1169fa1171147340f0e97d941aa19fcd3b34e8339a55933ed042af", size = 90404, upload-time = "2026-09-29T02:31:44.826Z" }, { url = "https://files.pythonhosted.org/packages/50/cd/fc9e2e367e80f1493e2ec5f610dda558b344eeede296f88976db133e8f2c/msgpack-1.2.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9d7e9cbb0998bbfd363fd9a09c330520d5e9cb323c05b5a1a05865d23ccf2226", size = 89683, upload-time = "2026-09-29T02:31:46.413Z" }, { url = "https://files.pythonhosted.org/packages/19/9e/1028485c6886c1c117f777cc9b053e541eff0fedb3292dfb1da95040edb5/msgpack-1.2.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6707d2fa2aa1bb5424ea0b05f44ffc989b15ab41a73ff5855bff4944fec7c8ac", size = 465347, upload-time = "2026-09-29T02:31:47.934Z" }, { url = "https://files.pythonhosted.org/packages/aa/83/800570e6a22376eb8d599920f70aead4779a63611696f567477c4e85a70f/msgpack-1.2.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:382b219de3d436de3baba0f4b0c6d4336e8f5858d0eb047918b13b69a71c6c55", size = 477820, upload-time = "2026-09-29T02:31:49.479Z" }, { url = "https://files.pythonhosted.org/packages/ab/ff/817e4a2052f848d3fb67726908d6e4e7c19f68ee7c19553a82ce7b0ed415/msgpack-1.2.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:186e6c602b8a9968b8e864c67d622a69279f7d1e55ae25f40e3bff7e815b2b62", size = 436656, upload-time = "2026-09-29T02:31:51.18Z" }, { url = "https://files.pythonhosted.org/packages/3d/42/040cc55dde6a7d92057baac8d1fc9cfb9f4fd4162900e2ec16dc33917a7d/msgpack-1.2.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9276ba88891338f2617044429dfd080ae008c9868a25f6f1a7d004a35dc9ac0a", size = 460939, upload-time = "2026-09-29T02:31:53.026Z" }, { url = "https://files.pythonhosted.org/packages/09/93/4dc007bdef930eed247346773bc0189b710078961d3218d5ee7ba59f322c/msgpack-1.2.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:c942c21a93f36b3a69e828c8945bb72c94dc2ffe488a2086950c812f3edf046c", size = 433608, upload-time = "2026-09-29T02:31:54.981Z" }, { url = "https://files.pythonhosted.org/packages/c0/97/a1b944046f283ec89445cb2a982c42233b5b07cc630f9be739f4f1d469a3/msgpack-1.2.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:18a6ed513023001b28dcd3ba54966f6bb90a38274ba8d2640464bcab3a1b81d4", size = 477373, upload-time = "2026-09-29T02:31:56.713Z" }, { url = "https://files.pythonhosted.org/packages/59/79/ab411d0d172743732ab2503f4c32a22dd1a7d1436a6feecbb160e4b6376a/msgpack-1.2.3-cp311-cp311-win32.whl", hash = "sha256:d0238cd05dec9ffbe0de1071df685ba63e30a36ac155285b1a094e727c38cbe9", size = 67514, upload-time = "2026-09-29T02:31:58.267Z" }, { url = "https://files.pythonhosted.org/packages/63/8d/6f0cb2b84e484e96278455c26870196d025bb0cec312b226a663f1fa9000/msgpack-1.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:30e1522e4173230dca4d9ad896f038f73c0da6c1edd42f4dbad88ac583cf5d46", size = 75850, upload-time = "2026-09-29T02:31:59.449Z" }, { url = "https://files.pythonhosted.org/packages/aa/25/f99e13a2c1d3f5a1dcaa5aab27f474e8c4358188bbc68ad79fecb0d1aefe/msgpack-1.2.3-cp311-cp311-win_arm64.whl", hash = "sha256:8ca67f77938ea6a3663aa9bd22b3e031f6da84d665be850abab910ee90728dfd", size = 72338, upload-time = "2026-09-29T02:32:00.885Z" }, { url = "https://files.pythonhosted.org/packages/af/12/4d7c6d6203416d9fbf0f59ebaa805e70fb929b93a41b611bc821ec5964a0/msgpack-1.2.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:89c930aece4e972b208ba589c8410b4167b05e411a5ea2cb25fd96f8bc47ee43", size = 91577, upload-time = "2026-09-29T02:32:02.141Z" }, { url = "https://files.pythonhosted.org/packages/eb/c7/8576ad39f4ca42ddad26f68eb8621d2d0a60501193d480f504bd9d7f36c4/msgpack-1.2.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:905a189853d6bdb204c7ae5f4ab77fb857448abfff574d3d93c62e2815b24b4f", size = 90027, upload-time = "2026-09-29T02:32:03.508Z" }, { url = "https://files.pythonhosted.org/packages/0a/3a/aa9c580aea1314529a0f3562461479780b0d254b064f0880956bfbcc74a8/msgpack-1.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3d7b3d0018746b5997dd6b14a1870b07cc4c327d9101145d94a1fc264a51a06", size = 460343, upload-time = "2026-09-29T02:32:04.906Z" }, { url = "https://files.pythonhosted.org/packages/3a/cf/9c2e4d6c179529d5bf4a64cff76fa581486569e9fbdd35bd98f51cb624bf/msgpack-1.2.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ede33b2892ceb976283e009ad12fa1834cfdf1f9c43ee9c97849fc588d00a618", size = 472998, upload-time = "2026-09-29T02:32:06.69Z" }, { url = "https://files.pythonhosted.org/packages/7b/41/915c81fe6df2d3cbdb0dece4f1a5cd313e1cd2abd9f501d0f50c0582517e/msgpack-1.2.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:666ef5601ab0e6e345e47febc96aa81143cc932201543480cbb9499164f05ffb", size = 423216, upload-time = "2026-09-29T02:32:08.739Z" }, { url = "https://files.pythonhosted.org/packages/a2/e7/7dda8b1039abfd9bba4c5068172c67135c9e33089f503512db9226f23c24/msgpack-1.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:87cf2ef05ff2f2493ba29fcdaef27e960ca64dacfd13460ae29e6f92e0ed05bb", size = 451218, upload-time = "2026-09-29T02:32:10.517Z" }, { url = "https://files.pythonhosted.org/packages/16/5b/ce995c1ed4a0522b7f2d034bc2034fd63005f240b945961b70fb56fbaf3d/msgpack-1.2.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:b774ff994d844e541439ac5d2d49a14def4104830c3465e9394c153f86200ffb", size = 422453, upload-time = "2026-09-29T02:32:11.956Z" }, { url = "https://files.pythonhosted.org/packages/d2/3f/ce191fb87e2650d0166b34c437e499ee4a7f9db9c1eb164f41725eb6160e/msgpack-1.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eaf7e82249837e3aa97297b34a0bb9ff562027381631e057cea6e1367f10b438", size = 469003, upload-time = "2026-09-29T02:32:13.663Z" }, { url = "https://files.pythonhosted.org/packages/42/35/539123407fe200fb16609c835675496fbeb6017ace9fc93909f0613223ae/msgpack-1.2.3-cp312-cp312-win32.whl", hash = "sha256:7c047250096f9fc19dba26e3d1639b5e7a84114003605c94def667149a70ced1", size = 68303, upload-time = "2026-09-29T02:32:15.02Z" }, { url = "https://files.pythonhosted.org/packages/6f/4c/331b45f9b86fbda6b9e103244d189068e51f726d8c40021ed66e1f2c415e/msgpack-1.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:3ec409b0d6aa8e9eec6eaf881b893caa215dbe68c5319ca96e8a271d81bb111d", size = 76744, upload-time = "2026-09-29T02:32:16.344Z" }, { url = "https://files.pythonhosted.org/packages/13/9f/fb572dc42b9fac06c7ea848aaee6e140d84469743bd1402bc07089fc4566/msgpack-1.2.3-cp312-cp312-win_arm64.whl", hash = "sha256:59612b4ed48a04cf024584218e813562f3b30a3bafa5f55abe300b15da314751", size = 71580, upload-time = "2026-09-29T02:32:17.617Z" }, { url = "https://files.pythonhosted.org/packages/1f/8b/3824d65e912e925d09ce30d9130fa9970d6d2855d7888b13639a6604967f/msgpack-1.2.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:21bfa4d2aa0b04c1806ef778a1199e9e53ea2441bcbf284420a32083896320b8", size = 91728, upload-time = "2026-09-29T02:32:18.949Z" }, { url = "https://files.pythonhosted.org/packages/05/e6/df7f2c9ebb94760113debbcea2bd3afe5fdab88a4f7bec1b618755517460/msgpack-1.2.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:db84203b13aecc222f465061397fdd5b53b7ae73d2c95ffc1c8dc5be0153a709", size = 89955, upload-time = "2026-09-29T02:32:20.224Z" }, { url = "https://files.pythonhosted.org/packages/08/6a/e5fc57136e8bacccb2b39627dea2cd546540a06181e22fe6db90e15b3ae4/msgpack-1.2.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5e0d7950ca3c1bbae291d0552dd3bb2792fc680629c4c0d44e47e5bab969f3ca", size = 454930, upload-time = "2026-09-29T02:32:21.771Z" }, { url = "https://files.pythonhosted.org/packages/b0/30/c394d37898db9212d1693456cdf363c7e1a097d0b63e10664007f3df3ec1/msgpack-1.2.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:07c9733089d1b176c3dd2f7fa268452f9d5d784d076473499d754a58e8d1fbbb", size = 466866, upload-time = "2026-09-29T02:32:23.742Z" }, { url = "https://files.pythonhosted.org/packages/4a/c8/1e4ddf6f6b829b3ee6c530c79dfae89cb609d2b0eedb5e0ae716851c52d1/msgpack-1.2.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f24a43b3560e20f825b807fe1e874bd73d53abaf8bbdcf258a6eb152cddbc1f5", size = 418715, upload-time = "2026-09-29T02:32:25.262Z" }, { url = "https://files.pythonhosted.org/packages/11/a5/f460ba6d7a12d4301002f3efbb8f841e8bdc9c5fc98d771689677a352885/msgpack-1.2.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6576f348ed6cc4f31db6fd915a8e94245f042f50eae08d48732425e70638ea37", size = 446489, upload-time = "2026-09-29T02:32:26.988Z" }, { url = "https://files.pythonhosted.org/packages/49/23/adface88db909bed321c85dd673655152d4a514c67e1f0800eb51c777d07/msgpack-1.2.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:cd5a9f9f86a52c24713679aa2631956835f3842512964ff93f736ff76f1f530d", size = 416998, upload-time = "2026-09-29T02:32:28.606Z" }, { url = "https://files.pythonhosted.org/packages/36/00/5bb3a239ccfc3763c4d0fa49b13b1b7010b00182c499ab3c1fecfe6294bc/msgpack-1.2.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f9ddd28d3e9bbc602a9dced1591882c7fb9ab776eef8837da2c326fde19e2853", size = 463288, upload-time = "2026-09-29T02:32:30.375Z" }, { url = "https://files.pythonhosted.org/packages/29/8c/456df77f00d701df9d6980ffb80291bce6e4e2e112e25a4dfae216f0715a/msgpack-1.2.3-cp313-cp313-pyemscripten_2025_0_wasm32.whl", hash = "sha256:62cc1a4ef0e553bac32c8342e1f04834aca7de276b92744eb7307db77759b890", size = 53347, upload-time = "2026-09-29T02:32:31.867Z" }, { url = "https://files.pythonhosted.org/packages/9d/22/ce780be666f89b77cdb855daa9ec62e87bb7f69e9f403e4a5d83a2b2208f/msgpack-1.2.3-cp313-cp313-win32.whl", hash = "sha256:d2f9c4f85e47a44d26d5baf3b041eef23436e224d44eed273f01bd8a12048d9f", size = 68258, upload-time = "2026-09-29T02:32:33.163Z" }, { url = "https://files.pythonhosted.org/packages/51/06/c3def9bc4db283103c5901b302ee2a4305cb1e69729244f94d9bd8f8e8e7/msgpack-1.2.3-cp313-cp313-win_amd64.whl", hash = "sha256:bb89b5dc30469c84bbf8684826eb851d82412ca95690e111b9ac5e8fb343961a", size = 76569, upload-time = "2026-09-29T02:32:34.412Z" }, { url = "https://files.pythonhosted.org/packages/12/9f/cef344073858b80adb92d6ea342e20b0eae7a8f6fe70281b69cf03707270/msgpack-1.2.3-cp313-cp313-win_arm64.whl", hash = "sha256:471e12a6a42498a31490c206e0069e343b6a7c35db540be73a879eb06f5be047", size = 71530, upload-time = "2026-09-29T02:32:35.892Z" }, { url = "https://files.pythonhosted.org/packages/3f/8e/f777f74e38731c428857933c8011596f2d2f3160c821152f23b6ffba862f/msgpack-1.2.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:3a31905206722103a84c1f72633fe30692cff6732c9d262e09a27dbc468797c8", size = 92042, upload-time = "2026-09-29T02:32:37.464Z" }, { url = "https://files.pythonhosted.org/packages/a0/71/551608543ee5d590f7e8d522267665d6d9946866ad2a2a70a770f7c70793/msgpack-1.2.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3372475211a9ce1a23acefe512cb3e121d18c95dc74ed56cb1819ef40836ebf4", size = 90578, upload-time = "2026-09-29T02:32:38.883Z" }, { url = "https://files.pythonhosted.org/packages/ea/11/6d78ce5a9a58bf9ba7b1b6a8f649173b030e6770c8019cf330b91825ee5d/msgpack-1.2.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9324c54995641c3d1f92a9d55093c8cde0ffa2fbc87a467a688ef60428393220", size = 454352, upload-time = "2026-09-29T02:32:40.34Z" }, { url = "https://files.pythonhosted.org/packages/3d/08/feb9a196269ba7809f44f9117d9e4a601c41c313f6144fd0c337293a5488/msgpack-1.2.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d8ef3a66e4b52d2d7fdd90df2984670124b2ff7546d76bb25dcf68ef47f7df58", size = 462562, upload-time = "2026-09-29T02:32:42.176Z" }, { url = "https://files.pythonhosted.org/packages/f5/77/3a674f366def24140b103d1ffd4fd27b3d912a13e47da67422afa16bebb3/msgpack-1.2.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:902f3490db0e07a7d40b48536a85c9b28fbf1397e7e1658a45a55f958e303620", size = 418134, upload-time = "2026-09-29T02:32:43.693Z" }, { url = "https://files.pythonhosted.org/packages/48/82/944e71f280577490d99a3951cbce21aa4cbe04e7ab42cb373fd668af883c/msgpack-1.2.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8e51eca14fbb65c4e0a5a9657346962bd3dca78c08e04e3d4dee70ef48687d30", size = 445937, upload-time = "2026-09-29T02:32:45.739Z" }, { url = "https://files.pythonhosted.org/packages/b1/ec/feddd629c4a3edf1395313680450c525086cceab56dec0d4de9da9ccb618/msgpack-1.2.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:f42f146752eedb6765f07dcc04d72dab0a25779ec8d4a88c0085263ce114f22c", size = 416450, upload-time = "2026-09-29T02:32:47.558Z" }, { url = "https://files.pythonhosted.org/packages/e4/59/263a10f8c4613ba0713f48cbda7695ac8dd6d6fab2fcbc9168f03f23a94d/msgpack-1.2.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:0ed5823c4efc20fe87d3530665f40ec18a002be003114814c21235cc8d256207", size = 459546, upload-time = "2026-09-29T02:32:49.145Z" }, { url = "https://files.pythonhosted.org/packages/1e/21/addcfa1e583cfc8a22fbdc57526621b5decd7ad676ae12e9150b7be1be5d/msgpack-1.2.3-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:2487453ca1b6104442c6442f9a1a8fee1fe8f428a70d99d4cba799108b304150", size = 53462, upload-time = "2026-09-29T02:32:50.708Z" }, { url = "https://files.pythonhosted.org/packages/8d/2c/3cb5c8524a1335ee27ca952c7ab78d375a16fea8e18ae3767ba0c880416c/msgpack-1.2.3-cp314-cp314-win32.whl", hash = "sha256:6df430419f2338cb71e4a34d6e64f83c88ccd321f91f40ba4513400b36d864ec", size = 70294, upload-time = "2026-09-29T02:32:52.037Z" }, { url = "https://files.pythonhosted.org/packages/23/f9/9172ff3cdb85d160ad06df5e2708a5fce7682982a5eee8d31869b9f69d2e/msgpack-1.2.3-cp314-cp314-win_amd64.whl", hash = "sha256:84a6616d396ec1bc18a1e83e67c96a393ec35dfe5e17434a5be7b9aa0fe988ab", size = 77778, upload-time = "2026-09-29T02:32:53.429Z" }, { url = "https://files.pythonhosted.org/packages/04/e8/b4c23178bcf605ae17cec48a75530dd69d49b0a5a6f5f4df5c47d59f746e/msgpack-1.2.3-cp314-cp314-win_arm64.whl", hash = "sha256:7a003b02c6ee2eea6dfe0bb08818631e3597e69f0131f2a8250488a1cc553290", size = 73794, upload-time = "2026-09-29T02:32:54.763Z" }, { url = "https://files.pythonhosted.org/packages/66/b1/92704be352c4f428b7e0a0e0fb210cb1aa2b1c42c102b8dc22d34b82fac0/msgpack-1.2.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:ccea05b5542f6d283fef3f0a8e93a7f0be90af0ddeeef84c25c0216ba76dcae1", size = 93721, upload-time = "2026-09-29T02:32:56.342Z" }, { url = "https://files.pythonhosted.org/packages/49/78/9c91f1e86cadcbc100b3780fd429c3715648704032a612e77a00646ebe79/msgpack-1.2.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b1631e12fe572e181cd77e831f69335d6cd5278eac22e3db3f33cf264ac2ac18", size = 94256, upload-time = "2026-09-29T02:32:58.056Z" }, { url = "https://files.pythonhosted.org/packages/91/4d/270f9725921ae88a29d37a774a77ac24f0ef1411fc960a63f5a4665e81b4/msgpack-1.2.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e54394b7dbe2e12ab032d9d21feef7bb61a90a150a2623633ba3781ba69dcb1f", size = 471673, upload-time = "2026-09-29T02:32:59.886Z" }, { url = "https://files.pythonhosted.org/packages/48/b8/eaa8d930f72dc1d1dd79511dc2ccf965922b059f2f0ed3b30aebac8c4b11/msgpack-1.2.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63bb7448a1e9111319ae2430c09a5596140c160422830d6271bc75730ff2ff9a", size = 466257, upload-time = "2026-09-29T02:33:01.517Z" }, { url = "https://files.pythonhosted.org/packages/5b/5a/97adc805037bc7e24c4e2f711bbcd3b28be8ec9aea3e778f18208cfbdb46/msgpack-1.2.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:382bc88fe90f29f5ac8a0b65c7046ff255356f2f2f3186c30e370215736fa1dc", size = 418484, upload-time = "2026-09-29T02:33:03.402Z" }, { url = "https://files.pythonhosted.org/packages/0d/7e/1c53302606fe436ab48ba539ebafafe4a6a9efe12c4f04dc7eb36912d93e/msgpack-1.2.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c77e27790ad72989db783d5303825fba0b71550f00a490efba35cde7dc4b719f", size = 454064, upload-time = "2026-09-29T02:33:04.977Z" }, { url = "https://files.pythonhosted.org/packages/00/2d/9ee0170f638907b396c15c6cd26b3e54f869159efc6206683acfd8f696e1/msgpack-1.2.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:700bc0fc9e968a292b9137ee70e7a012f7e115bf0107ce45e3a88202788dfc1e", size = 417901, upload-time = "2026-09-29T02:33:06.489Z" }, { url = "https://files.pythonhosted.org/packages/cc/d2/905c84490a75cd15a27065407cd085d201f7d392e1e0411f49f03fd31ade/msgpack-1.2.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5bd5f91ea75c45cafcc5433ba8fae59b708b736ec178d2441c40c499e9e079db", size = 459896, upload-time = "2026-09-29T02:33:08.361Z" }, { url = "https://files.pythonhosted.org/packages/37/cd/4ce5809b9ab3b114d7cca64863e436820fa1614b49d55ccb93d49824ac2d/msgpack-1.2.3-cp314-cp314t-win32.whl", hash = "sha256:7995a7c6a62a1d6e7df211b4a16de513bd99fd053525050a319f80f44fb8015e", size = 75983, upload-time = "2026-09-29T02:33:10.023Z" }, { url = "https://files.pythonhosted.org/packages/8a/31/853bb580744c24be0dbd8b090c3e6987dce466a1fc840fe50c0ac2ef9044/msgpack-1.2.3-cp314-cp314t-win_amd64.whl", hash = "sha256:bfe7d5b62cbe7aa664f0b3e2c49077f10fcdd06183d3014f8271ff3c5edbfbf9", size = 83757, upload-time = "2026-09-29T02:33:11.441Z" }, { url = "https://files.pythonhosted.org/packages/0d/49/9f1b2ee484414eef9e21ee2b2b23b482bb71433ab9bac1da03cbda15ebf5/msgpack-1.2.3-cp314-cp314t-win_arm64.whl", hash = "sha256:1f585407f740a9eac04a3bb82c61d68a0ea78f90e29e670bfb086b9ce3a518dd", size = 78128, upload-time = "2026-09-29T02:33:13.063Z" }, { url = "https://files.pythonhosted.org/packages/47/b8/50db4235407c3802f622b4ccdf65c6fe1e48d3c3eab6981fa6a9a5e53f11/msgpack-1.2.3-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:13221a6c81ebb8e43ea63a7251c35d54e4175cea37ebf3a62e911bdf42562a3c", size = 92111, upload-time = "2026-09-29T02:33:14.476Z" }, { url = "https://files.pythonhosted.org/packages/15/56/50cf2a45c6163edafd737e2fd555103a26ce6748e1e241fb56ed445ea835/msgpack-1.2.3-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:0955b9000725573d1457c1676944b370dd9643c8d18f25bda5ac72913f850949", size = 90583, upload-time = "2026-09-29T02:33:15.924Z" }, { url = "https://files.pythonhosted.org/packages/2a/fd/8cc02f767c3bc94d2649c954d28dea935ce9398eb9c93ce2444bb9474cc1/msgpack-1.2.3-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c91762c48cd686dc9cf2b142c0bc544083952de32f5853d6624c956e54b85e5", size = 454751, upload-time = "2026-09-29T02:33:17.475Z" }, { url = "https://files.pythonhosted.org/packages/80/c9/ddb896767808e3e022453d8dfae26fd52ed404b0aa6fb7f752d39c040208/msgpack-1.2.3-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f4ae8bd4ad9ba085fde95e95d055a896d19210238a4199a771a3cf36dceed49", size = 463597, upload-time = "2026-09-29T02:33:19.309Z" }, { url = "https://files.pythonhosted.org/packages/4d/a5/e7c261abf75783c07dcac89951cb31dd0c123bf02fbdeda0c67303e698d8/msgpack-1.2.3-cp315-cp315-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7013534a7163aa4f213c4d9864f1a8a7555daac6fcd48f699a198e29b436bfab", size = 422661, upload-time = "2026-09-29T02:33:21.093Z" }, { url = "https://files.pythonhosted.org/packages/9d/8e/466d5133f9e1c2e232e15e304f715b62f6f0e28332d18e37d975fe174315/msgpack-1.2.3-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:6a834097144aabe948b8ca9020a833e8026f7d0abbd0ec54bc7e50f45a8ce012", size = 445188, upload-time = "2026-09-29T02:33:22.877Z" }, { url = "https://files.pythonhosted.org/packages/d4/b4/33e7ad987ee2f4b3d449a6cbf28f574ed222987ca7f65ad277072646ac5e/msgpack-1.2.3-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:d31864ba3933a589b6a00249f89c0eb422197f49128fc10da550e57e9cb0f377", size = 420451, upload-time = "2026-09-29T02:33:24.485Z" }, { url = "https://files.pythonhosted.org/packages/34/2c/9d8be0d6c16e7e6131cd7da20257dd3da65473e3e6df0c00572fb10a195c/msgpack-1.2.3-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:e15f70588f4db8cd10df0930145b186de70feb9db51710cd378b1399009655bd", size = 460624, upload-time = "2026-09-29T02:33:26.063Z" }, { url = "https://files.pythonhosted.org/packages/6a/e7/3a04783582c6f44f398cbfcf5f07a111192126ec4e63edf7f5640143bf64/msgpack-1.2.3-cp315-cp315-pyemscripten_2026_5_wasm32.whl", hash = "sha256:b949cc25e4a09252cbcc54e66e507de914d0e94a3a7039bd54c299bf7037c098", size = 53474, upload-time = "2026-09-29T02:33:27.83Z" }, { url = "https://files.pythonhosted.org/packages/68/fb/db07359851644e258609d84f8e4fe0030ef448c108e20afe73f2a3bf539c/msgpack-1.2.3-cp315-cp315-win32.whl", hash = "sha256:8ec7a1d49ca6c2569d722ab5ec86e90089b0713900aa31905b47b4c4d9e78ce0", size = 70344, upload-time = "2026-09-29T02:33:29.382Z" }, { url = "https://files.pythonhosted.org/packages/5b/e4/cf5584d2f2a2e4465d5896a855a3e75a34a20ab172360b3d42ad862dd1ce/msgpack-1.2.3-cp315-cp315-win_amd64.whl", hash = "sha256:79dfa38faf92f804aa61beec140d70b18418e1dde1778dbb77a87a4cce85aa8a", size = 77800, upload-time = "2026-09-29T02:33:30.941Z" }, { url = "https://files.pythonhosted.org/packages/63/f9/518ad4e8a580027b507eafdd26de7aae661a714e43d7c111c212482e4a1b/msgpack-1.2.3-cp315-cp315-win_arm64.whl", hash = "sha256:ed899d73a22f286a72bd9528d63f2ab3030dbad8bf1527fc249319a50d61fb9d", size = 73871, upload-time = "2026-09-29T02:33:32.406Z" }, { url = "https://files.pythonhosted.org/packages/a4/79/254d4c9ad642b2a3ba84e646787892b34cc815eb36c9976f67a1c4f38515/msgpack-1.2.3-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:f56fba61b2516be7917cb00151f0d060b5b21184e3499bb57f0f7d9259bea124", size = 93370, upload-time = "2026-09-29T02:33:33.87Z" }, { url = "https://files.pythonhosted.org/packages/3d/6f/5a2ba167646a25e84eaa8894e12935351e4331b80c28a9237ce6fe8d375f/msgpack-1.2.3-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:69ad12cedb674c73527bed869cddb42b742cac79a207a614202a4abaa24ea173", size = 93959, upload-time = "2026-09-29T02:33:35.503Z" }, { url = "https://files.pythonhosted.org/packages/e9/a1/2b44612e55f7cf5d5e4b580294959b4429bbbcb1991177888e3e18668137/msgpack-1.2.3-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:db9fb67a3a2e75247bae569d34ebb5ff61c0448a4f0d6dbf991dae68af39b007", size = 467921, upload-time = "2026-09-29T02:33:37.023Z" }, { url = "https://files.pythonhosted.org/packages/0b/6e/3309798ed1c11d7fcfdc7b946642685b0ff1588477925bc0d26bee7dcaae/msgpack-1.2.3-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2574ef81c1c8c38b10e330f3f9406fd09198a776b002030fafcf8e7647e9e06e", size = 467310, upload-time = "2026-09-29T02:33:38.799Z" }, { url = "https://files.pythonhosted.org/packages/6f/79/9c799f489fa4146de4e00cfe9fee17afe33d8012f88ddffffea94f7c4700/msgpack-1.2.3-cp315-cp315t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fafc3b8898b432b841d30a61082c599fa7f4d06885f9dc58ad72259e12059fa6", size = 420178, upload-time = "2026-09-29T02:33:40.781Z" }, { url = "https://files.pythonhosted.org/packages/94/c6/5850dc9cafcd2ea315692e65db0e222d20923dd55f44adf35061003de27e/msgpack-1.2.3-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:a393e428f6ffb0dcb73308c1fff5593041c16ff42da66e5bac8a83a6107a54b0", size = 450248, upload-time = "2026-09-29T02:33:42.366Z" }, { url = "https://files.pythonhosted.org/packages/a9/d2/b4c806e3497fe21f0b353568266aec14ff735d092aea672de7b2955db03f/msgpack-1.2.3-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:d1c1e8989a855b7f1f2a64ec4a80b23a631822903952770813857b2e4f460471", size = 418431, upload-time = "2026-09-29T02:33:44.178Z" }, { url = "https://files.pythonhosted.org/packages/b0/f5/f4ecc3ddac4d551bf2f3cdb283ec546dcc826fe7c500074be61aa273e08a/msgpack-1.2.3-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:e0bd394e999949c814f7912284243298de1b5a17b6a3dcb6cc8a79b156ffc4fa", size = 457543, upload-time = "2026-09-29T02:33:45.978Z" }, { url = "https://files.pythonhosted.org/packages/a4/69/1c821d8386fae5cecc5fcaacf3de3947ff0a23f16bb481b5532b5868372a/msgpack-1.2.3-cp315-cp315t-win32.whl", hash = "sha256:3d4c807ed050fe3ddbea5ba7e9f63d7136871ce42861be1f50ff739f0e91047a", size = 75820, upload-time = "2026-09-29T02:33:47.596Z" }, { url = "https://files.pythonhosted.org/packages/68/9e/41e2f7343a3764a9c1fb10c79f9a6a05db9df93dedd76401d1b511f5a685/msgpack-1.2.3-cp315-cp315t-win_amd64.whl", hash = "sha256:5f304123b90e8b2e49867981b7f6061612c39f50cca51ee88de007c084cf68d3", size = 83345, upload-time = "2026-09-29T02:33:49.325Z" }, { url = "https://files.pythonhosted.org/packages/80/cd/0c3aa439bc7a7bf24684fef3a0ad776cba170e18ed94445e723bce42fce7/msgpack-1.2.3-cp315-cp315t-win_arm64.whl", hash = "sha256:f41ca154b7737b11893cdce3c78c61d703398a1cd54d4297bdad908392338a8e", size = 77572, upload-time = "2026-09-29T02:33:50.729Z" }, ] [[package]] name = "mypy" version = "2.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ast-serialize" }, { name = "librt", marker = "platform_python_implementation != 'PyPy'" }, { name = "mypy-extensions" }, { name = "pathspec" }, { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/34/4e/64300736cf0a0373a27b94a91b664ee7382e36f77b0621bae6381da3e180/mypy-2.4.0.tar.gz", hash = "sha256:77bdaebd452f43fcfc4cc3ba94352a3ea537cd01e3f2d0879f48673d2ec00d6e", size = 4064425, upload-time = "2026-10-01T20:40:39.229Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/26/67/e53965e67d23d48e78dd603aa7525a8d77e7818c23954cc217ccde5cd5c0/mypy-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5d20e6c7c35fcbf2a0ebdd0eaeacfbc243009dfd33ab7822d54e213912e6dbbd", size = 14315745, upload-time = "2026-10-01T20:39:25.03Z" }, { url = "https://files.pythonhosted.org/packages/b1/5d/a588ccd57625822d8484d7aff4e9c70f88d042a91c2ec84324a2bc14b3f3/mypy-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3011537be6cf1de4511c0255a324362a812b58184bbe61e15f59c8b31033bd74", size = 14465652, upload-time = "2026-10-01T20:38:57.19Z" }, { url = "https://files.pythonhosted.org/packages/05/af/b4978a5566cb829ca563dc08e3ad8d944f116078786ad54ba3dff2bcb64d/mypy-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a96b07a49b7b1d025ce59c1b3acbcf24bead9a83da4523c4a6bde1bb94e7a0e1", size = 15419180, upload-time = "2026-10-01T20:40:27.808Z" }, { url = "https://files.pythonhosted.org/packages/b2/8c/52c71f31c54d0a749d832cc73b933c6e38c52d9b270d5503e031c73723dc/mypy-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7c4f8f8d1d1c0e2832d8ee7113dd08f6df6c7aad9e863fcbed9f25832be0b8c4", size = 15669212, upload-time = "2026-10-01T20:39:20.443Z" }, { url = "https://files.pythonhosted.org/packages/e8/55/ba63121494404fd7d3787ec176ccd02820d6ec125ac4e7c4c0b79f2cc6c7/mypy-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:ba05652540bf12828e52abae807b024b09ca144ff4f75e2450a81d69c376425b", size = 11299572, upload-time = "2026-10-01T20:40:03.627Z" }, { url = "https://files.pythonhosted.org/packages/9c/9c/385c81b5c0d3a2917f077c4da660d0493f9521ccfd4b058e33b860f72d02/mypy-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:6306086b87cf7f8a29aa618d9fd9bffb56c59247166b9660fdb54d86d7714ecd", size = 10869751, upload-time = "2026-10-01T20:40:25.483Z" }, { url = "https://files.pythonhosted.org/packages/68/ed/e5d7cf4017e74a1c1e1c4058ce8f614fc1e3e7606564f47166e22bfc9f95/mypy-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e05ff2925d8b37ad26c80c1b9dc43ae5d455da2df1e23c24c095a6425917c57e", size = 14378593, upload-time = "2026-10-01T20:38:48.222Z" }, { url = "https://files.pythonhosted.org/packages/30/7d/12d994886a922f0f1997becc9c6625198d61eeb5962558a886af7dd38d54/mypy-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:29243242cf72582b65f9582ad9e56e8cb281566ed3519f4cd70bb8b9f2977e90", size = 14464697, upload-time = "2026-10-01T20:39:11.059Z" }, { url = "https://files.pythonhosted.org/packages/f3/9e/bcc9af755425ad17790bf11d73c2ea7592914cf309ee1340997670f9d57a/mypy-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:29eb0b9427a6b11b992e452f6cceb8af724f4dceb47e779d0b35e405e996ea5e", size = 15552257, upload-time = "2026-10-01T20:39:56.269Z" }, { url = "https://files.pythonhosted.org/packages/af/0c/3343fc4525d6f00d75ad17a93a9f052d5163641cb8911840d4a12cb59ff2/mypy-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e3ebe2f72a2a1156065a9851570ffbf50c0a93cdccadef9c6e05c508a4fd10b1", size = 15800443, upload-time = "2026-10-01T20:38:54.815Z" }, { url = "https://files.pythonhosted.org/packages/8f/0e/69aac6b8159da7c53e6115a2be1bf48e85503402cadbf506dd708e8b2ad7/mypy-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:236e0d68f6941992b0811128e652590f590db444ab29ad8f1324765b9298b946", size = 11381574, upload-time = "2026-10-01T20:39:49.406Z" }, { url = "https://files.pythonhosted.org/packages/6e/d3/d32ce4feb5993eec09d2024bef16cedc9b93701b1446b86092f08b24491b/mypy-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:82d0f94c8587ccb472622ee7795280aaa38a06640d5f45b3f16909d6dd86a989", size = 10944729, upload-time = "2026-10-01T20:40:15.203Z" }, { url = "https://files.pythonhosted.org/packages/44/f2/eb15183c97c69d7cbfac990a6efd33a19ecfd97dab9e714c742fa78a784f/mypy-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7da85fbcff6dac1abcc636707bed38b45598131fb7a605d9719c70b5cc733af8", size = 14213395, upload-time = "2026-10-01T20:40:21.178Z" }, { url = "https://files.pythonhosted.org/packages/8c/b5/ba91b6ff65e4d6b6ff53b2b3b3ac5f1babf0c7c27d0b43a0196b1c967926/mypy-2.4.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4209da39d85cf240f762af622d8180fcdfcb4727d021f44ade62d613a1a43324", size = 14373009, upload-time = "2026-10-01T20:39:58.86Z" }, { url = "https://files.pythonhosted.org/packages/d5/c4/484275efc935c0003e55e4e8a33e4b8e99528ee956c12256ece4708f903f/mypy-2.4.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6be721bd4bd57576193653b75b4af3461c9d0bf7dd8b528f782e9be210dc75bb", size = 15465557, upload-time = "2026-10-01T20:39:01.794Z" }, { url = "https://files.pythonhosted.org/packages/50/30/66eb6fdd0875e3c9025a02f0bb0ea2e524b74274b658c37fde0068c4939d/mypy-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e1fde197ae65be856a034a91b70ed747a16562ca69577785f06c661548424bf1", size = 15728673, upload-time = "2026-10-01T20:38:43.724Z" }, { url = "https://files.pythonhosted.org/packages/58/bc/2aa98fd7f49c42dba8e9c065886fadffdd00f3c654cff3f2a7103a797ac8/mypy-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:295ecf2e57542cd836ca537486951289678c8c7d1ee6ad74ebe29b2168a003cf", size = 11389803, upload-time = "2026-10-01T20:39:37.547Z" }, { url = "https://files.pythonhosted.org/packages/49/41/17b60df2d946792ef6af43b89351f5c9ddabc69053206b2304945572a744/mypy-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:bc378bdad4e9f12b5bd96466083d1e71acf00594ec9c7b2bdb5e02816f77f303", size = 10951060, upload-time = "2026-10-01T20:39:04.015Z" }, { url = "https://files.pythonhosted.org/packages/e0/66/924be0b653372ed31ad5c48e26044cc00840e591943a56e61621cf05b60e/mypy-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:058165f564ccf559c68c70fec2091fca5891110480210c22594635e3f6683437", size = 14234230, upload-time = "2026-10-01T20:39:44.535Z" }, { url = "https://files.pythonhosted.org/packages/56/39/c4f176880a4177123576de6cec6309feea8f42fca2bf2f6584e88054f656/mypy-2.4.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9fa247e02b505a45a2775f69df38d360d197e3790bc60f717595db9eda358b6e", size = 14392944, upload-time = "2026-10-01T20:40:05.78Z" }, { url = "https://files.pythonhosted.org/packages/bc/1c/26e16977e25ef2494a74f8ffc872a76ec2c3aa43c3156057cbdf88f352c5/mypy-2.4.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20e9a5cd875837520c43db98dea0b6d0c2197833d95c30127d8f570fb9b1f00b", size = 15441463, upload-time = "2026-10-01T20:40:32.412Z" }, { url = "https://files.pythonhosted.org/packages/31/9c/9e4b049f0ecefbfd6817ca2a16eea55dd74a07950268edc6cffd29ccfe98/mypy-2.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9f03a7828cca2b0adcd6662aee8f2711ff8830e1027641fdea3ab0b787483566", size = 15705406, upload-time = "2026-10-01T20:40:34.844Z" }, { url = "https://files.pythonhosted.org/packages/4a/5e/e861b5f6c5ef9ee6cd24683aed1edecf82a26dbd536049f9b7850b586267/mypy-2.4.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:9279488933040b638c0ab739084c0ca100efeea6db581bf5d7628d8e89de53fe", size = 7897523, upload-time = "2026-10-01T20:39:39.861Z" }, { url = "https://files.pythonhosted.org/packages/3a/87/61ffee58b25a956532a6006fae84918a2de849ed25f397492b2e815fe7b3/mypy-2.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:2106b55105ba5ea9be4f53a24517fc5fa927ff1585edc9bc1a975abb72caef89", size = 11576345, upload-time = "2026-10-01T20:39:41.553Z" }, { url = "https://files.pythonhosted.org/packages/a1/88/a331c20698971c2ce8d1c30f317fd61b5be13a85b1f053e12dfa22ac6568/mypy-2.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:528c8744b8b5e3ecb8774f86af38d2376216816e9908317ad055f3c9c2d74799", size = 11172062, upload-time = "2026-10-01T20:38:59.534Z" }, { url = "https://files.pythonhosted.org/packages/47/c0/4f7daa73270dced8e86c6f4a911c68082d03a84e6c1ec9bd916028d66131/mypy-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0bb95cf34899e4619c61ab0a8667804e139e580b30d5df12af2102dfe44d0c97", size = 15711208, upload-time = "2026-10-01T20:39:30.597Z" }, { url = "https://files.pythonhosted.org/packages/2f/05/f1afa303c678be24cf7a266d38fb24b3de4599a024c2f9ba0d5905a3efa3/mypy-2.4.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:86d616fe84c6eab8026f8c50ab5bcb90db780d2ccd233d971e34e92bede9b359", size = 15935442, upload-time = "2026-10-01T20:39:22.781Z" }, { url = "https://files.pythonhosted.org/packages/9d/d6/6a1a45459b63716e0d035f4892a926d3054f0a8cbfa02551d228a9946083/mypy-2.4.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a3f86fd1313dd69d013e265f1fdcd12ea7a9d606f9875b2a3db946cd334555f3", size = 17240044, upload-time = "2026-10-01T20:39:32.95Z" }, { url = "https://files.pythonhosted.org/packages/87/85/ae33bee66c13f98d421964d87bf0888be941063bc75c1204a4cf142cf1cc/mypy-2.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:720434d48542ecfe84d32d287b727569d3fc8f5769acd39051130e490a5c295c", size = 17545856, upload-time = "2026-10-01T20:39:08.827Z" }, { url = "https://files.pythonhosted.org/packages/df/de/eeff209b65c3e267818d79333bb9f058da6e4e73761461bd94748a2eb628/mypy-2.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:a6e851b82c0661f69f1630fc16172c68787a6a9cf0991e7c6437d60976cdcd76", size = 12369342, upload-time = "2026-10-01T20:40:10.516Z" }, { url = "https://files.pythonhosted.org/packages/2b/43/e62d8d5c1dd737aa248968302ff7d6eabf997c3301773ed8bcb64932ca77/mypy-2.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:3bd0e340f0ebe65c548210f53be3fd8192e83964760caf0c28bef368e68b0d37", size = 11849099, upload-time = "2026-10-01T20:39:51.834Z" }, { url = "https://files.pythonhosted.org/packages/2e/5f/335b8980055118dc131355155883fb676bb2161a0d97e08658e479c776fb/mypy-2.4.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:afa89837d9be67e0cadfa33bca3bb7efdda98c3b07e74dc3b635ebfb1c8a926a", size = 14241302, upload-time = "2026-10-01T20:39:13.227Z" }, { url = "https://files.pythonhosted.org/packages/18/37/1482fdc49332b145828912b15f16eee0c4ca70a8bce0f6514ece79b14680/mypy-2.4.0-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fb443e81057896132d3642d6be219e6efd158691ac7883e3ba8fcb469865f05d", size = 14408200, upload-time = "2026-10-01T20:38:52.576Z" }, { url = "https://files.pythonhosted.org/packages/04/09/dce2e8f6c1b31053c430ef6963f6f7a38ccb49b90c5e01e37ed0129b7d5a/mypy-2.4.0-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7f38f57d344f8b6accb40e01c3d83cfc590498231724d16c07ffb7940f157818", size = 15444409, upload-time = "2026-10-01T20:39:18.1Z" }, { url = "https://files.pythonhosted.org/packages/43/c5/91b68306da4cd280cb15be35dbb5ffc343cabd67c4b121b6625bf2d13177/mypy-2.4.0-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:e76172710bd4e5eeae061abfd68347e5264632e02778be61784671ae3a2132f5", size = 15731186, upload-time = "2026-10-01T20:40:23.426Z" }, { url = "https://files.pythonhosted.org/packages/64/71/2d0340182a8f27352fb1e25531355951108b506097c433937e9eec452ffd/mypy-2.4.0-cp315-cp315-pyemscripten_2026_5_wasm32.whl", hash = "sha256:f83353e47ab520bf6fd4df8f5897d9fe081211f2fbc4b7d37736a3e3c166cbcf", size = 7897838, upload-time = "2026-10-01T20:38:50.779Z" }, { url = "https://files.pythonhosted.org/packages/3e/08/32703c117e134c02efa2a82705bb40cee91eaedea10b6530e20eba651b1f/mypy-2.4.0-cp315-cp315-win_amd64.whl", hash = "sha256:970b221ed5842213d98e3c480c08f795ace4b1f81fb21e1b126bd0476bce1c34", size = 11575700, upload-time = "2026-10-01T20:39:53.982Z" }, { url = "https://files.pythonhosted.org/packages/ab/08/08bb269feafdaad031046ee2d771528a64467e6a180f962afc28c4a3ccd8/mypy-2.4.0-cp315-cp315-win_arm64.whl", hash = "sha256:502b94b0b331f7dafe32fd6b151797ddbb4f32385b362e722c783a025e5954a3", size = 11172908, upload-time = "2026-10-01T20:40:12.91Z" }, { url = "https://files.pythonhosted.org/packages/fb/3f/c5c92626006ca92c7686adfbece47fc6a0daa0e54753952a9ad13ce0561c/mypy-2.4.0-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:c9de622fd397495695d0598ddc789222bfcfec9d7c9ec3a1e385c855e3bc5e01", size = 15705970, upload-time = "2026-10-01T20:40:17.79Z" }, { url = "https://files.pythonhosted.org/packages/10/f3/863365f7997a76a5a1dd42d7902ab05afa4124e8419089cbca1ce2554db1/mypy-2.4.0-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9f459f0b4f0596d9d51fe7716b404b35287b99e77da98a7af90a65dd5fd61141", size = 15942234, upload-time = "2026-10-01T20:40:37.243Z" }, { url = "https://files.pythonhosted.org/packages/f6/30/2f45b1f425a2c95dbe1a3f4d076bfd42b76e9615dba5906230703b14e4eb/mypy-2.4.0-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f9b028548b3af480e2b1ed8df14ccaac86f99c9f600d1580770ab7ba3dcd40f0", size = 17218364, upload-time = "2026-10-01T20:39:06.497Z" }, { url = "https://files.pythonhosted.org/packages/43/8b/5b2bbfc69e84800b78fa2dba16d995b003f93b573558e412c5490d6e6c37/mypy-2.4.0-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:cb734b2668c1f40d07ce093bbeb4407e9527c67901627b0e1679825be3f09975", size = 17557934, upload-time = "2026-10-01T20:38:46.077Z" }, { url = "https://files.pythonhosted.org/packages/df/c0/1a5dc601c22041a7bbfe1ff71cf097fbbd4fb49930867c6789baf5102106/mypy-2.4.0-cp315-cp315t-win_amd64.whl", hash = "sha256:172e30b8fea631fe310f0c665477f52d9ea40bb4e99e0c81dc30118563b13710", size = 12350955, upload-time = "2026-10-01T20:40:01.52Z" }, { url = "https://files.pythonhosted.org/packages/1c/bc/697e9e26fc2a86c094ad67ee1e419971b7f01ded66ee66231b09e9f3e12e/mypy-2.4.0-cp315-cp315t-win_arm64.whl", hash = "sha256:5786ef987b3767e51aaa53f20aec104c0252b42ecda7aef8e8b4cbae279b05c5", size = 11842738, upload-time = "2026-10-01T20:40:30.026Z" }, { url = "https://files.pythonhosted.org/packages/81/12/46ae8670c98a3cd0286ca5645c2f918f8f6be65edfed81b916010619f668/mypy-2.4.0-py3-none-any.whl", hash = "sha256:d01c5d26a352acc6d5cf3128225477e1e8465e8d3029d4c345807fbf7f3cf093", size = 2800734, upload-time = "2026-10-01T20:39:26.837Z" }, ] [[package]] name = "mypy-extensions" version = "1.1.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, ] [[package]] name = "myst-parser" version = "5.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "docutils" }, { name = "jinja2" }, { name = "markdown-it-py" }, { name = "mdit-py-plugins" }, { name = "pyyaml" }, { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, { name = "sphinx", version = "9.1.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/21/dc/603751677fff302f34396e206b610f556a59d7fe58b9a2145f54e96b48e8/myst_parser-5.1.0.tar.gz", hash = "sha256:ab69322dc6719dcc7f296479dbb70181b66df6ed315064f92dbc85c0e1bf2f02", size = 101182, upload-time = "2026-05-13T09:38:19.361Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/09/dc/f3dfb7488b770f3f67e6545085bf2abea5172e88f57b8ad25ef860ca704c/myst_parser-5.1.0-py3-none-any.whl", hash = "sha256:9c91c52b3cdb4d94a6506e4fab4e2f296c7623a0da0dcbe6de1565c3dad67a8a", size = 85817, upload-time = "2026-05-13T09:38:17.904Z" }, ] [[package]] name = "networkx" version = "3.6.1" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version < '3.12' and sys_platform == 'win32'", "python_full_version < '3.12' and sys_platform == 'emscripten'", "python_full_version < '3.12' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] sdist = { url = "https://files.pythonhosted.org/packages/6a/51/63fe664f3908c97be9d2e4f1158eb633317598cfa6e1fc14af5383f17512/networkx-3.6.1.tar.gz", hash = "sha256:26b7c357accc0c8cde558ad486283728b65b6a95d85ee1cd66bafab4c8168509", size = 2517025, upload-time = "2025-12-08T17:02:39.908Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl", hash = "sha256:d47fbf302e7d9cbbb9e2555a0d267983d2aa476bac30e90dfbe5669bd57f3762", size = 2068504, upload-time = "2025-12-08T17:02:38.159Z" }, ] [[package]] name = "networkx" version = "3.7" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.15' and sys_platform == 'win32'", "python_full_version >= '3.15' and sys_platform == 'emscripten'", "python_full_version >= '3.15' and sys_platform != 'emscripten' and sys_platform != 'win32'", "python_full_version == '3.14.*' and sys_platform == 'win32'", "python_full_version == '3.14.*' and sys_platform == 'emscripten'", "python_full_version == '3.14.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", "python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'win32'", "python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'emscripten'", "python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] sdist = { url = "https://files.pythonhosted.org/packages/dc/76/3af777226b63a5e64a6b36b1ec5855c14e2b94a37096d4760e595fc43511/networkx-3.7.tar.gz", hash = "sha256:fd77a511bd90f39f3d016351345b52cf5319b813bdca01de3f755d3cca62e96a", size = 1866482, upload-time = "2026-09-21T16:45:16.974Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/7e/cd/fe58041e9011f307c490e3e17dd48cc516448f7c698a3f2d9d9d65d7e6a8/networkx-3.7-py3-none-any.whl", hash = "sha256:e3fd2c13a7814cee3746340d8d7f8598a67f16a58bf47fb7f8793fab6efca1b0", size = 2142205, upload-time = "2026-09-21T16:45:14.609Z" }, ] [[package]] name = "nodeenv" version = "1.11.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/105de02c1322cfada6d9710d9146ef8026419d433c9d08359a2d35805811/nodeenv-1.11.0.tar.gz", hash = "sha256:3ce8fe5b71d16e8af7039ca65257354100bc772965d6bc549070649e53b1b146", size = 99301, upload-time = "2026-09-26T11:29:21.367Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/54/c8/12811c9b48fde162bb72b6f2e78fada9a247a09d7bb5be2050a5d099c77b/nodeenv-1.11.0-py2.py3-none-any.whl", hash = "sha256:edaa16e6c14d7cf395d75d4bbd5a26390f4dc06501a33b4e76282b02cc688a25", size = 34277, upload-time = "2026-09-26T11:29:19.933Z" }, ] [[package]] name = "numpy" version = "2.4.6" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version < '3.12' and sys_platform == 'win32'", "python_full_version < '3.12' and sys_platform == 'emscripten'", "python_full_version < '3.12' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] sdist = { url = "https://files.pythonhosted.org/packages/d0/ad/fed0499ce6a338d2a03ebae59cd15093910c8875328855781952abf6c2fe/numpy-2.4.6.tar.gz", hash = "sha256:f3a3570c4a2a16746ac2c31a7c7c7b0c186b95ce902e33db6f28094ed7387dda", size = 20735807, upload-time = "2026-05-18T23:37:14.07Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/b3/49/ec46835a70be8fa6446c495126ac84fdb28cb2558e1620ffb87a10c8b64c/numpy-2.4.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0280e0356c0829a18d9de1cb7eee50ec22ca639878d7240307ca0943d73cd2c4", size = 16969194, upload-time = "2026-05-18T23:33:13.503Z" }, { url = "https://files.pythonhosted.org/packages/0e/0d/f5957185c0ee2f3e12f78715aa9e3b353fd83633316c8532b38faa37e3f6/numpy-2.4.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:110f8b71aacb688ec69062bb7f6938a0f8acb01b7c1c4beb453c65b6d234584d", size = 14964111, upload-time = "2026-05-18T23:33:17.795Z" }, { url = "https://files.pythonhosted.org/packages/ad/40/40a40ee0ddf7ceb782c49af278894b686e586d65d8c1889c8b5da01a3d7d/numpy-2.4.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:4cfe66903cc32a9921a6733d96b19bb6abf310397581bbad89c228f5abaf0ee8", size = 5469159, upload-time = "2026-05-18T23:33:20.654Z" }, { url = "https://files.pythonhosted.org/packages/63/13/f9a8046535cb21deae82f8d03de9617e08882d274fad2539630761888228/numpy-2.4.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8155154c7c691289fe18f510b5d4657c68c67989f293f0535a91360392ff6538", size = 6798936, upload-time = "2026-05-18T23:33:22.987Z" }, { url = "https://files.pythonhosted.org/packages/33/a8/6fa8c1a345a8c85dbb21932c447bee07c30a2c2a3f31e369c0a84b300147/numpy-2.4.6-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ab0a9c4ffb1a6d95ef519fe4247dba8eb6b18ad93999f76b7f657039acabd47", size = 15966692, upload-time = "2026-05-18T23:33:26.62Z" }, { url = "https://files.pythonhosted.org/packages/02/03/74fe2a4cb3817d94d86402f2506554130a2f01414e299b5a843e5a8a957f/numpy-2.4.6-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:89cd468399cfd2504718f0ba50e410dca55a170b61a02ad92bb18c8a65186e93", size = 16918164, upload-time = "2026-05-18T23:33:29.955Z" }, { url = "https://files.pythonhosted.org/packages/c5/80/3615be3313f7e7696609bc194b9f0101da809df79e859bdb84e0cd043f46/numpy-2.4.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c2d37ab77531417474168eb79d6d80b14f821a966818505d03013d0833edb7a8", size = 17322877, upload-time = "2026-05-18T23:33:34.724Z" }, { url = "https://files.pythonhosted.org/packages/ca/ac/a691e0fe2675e370d0e08ff905adc49a1c8830e8cae03efe4477e92cd55d/numpy-2.4.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f407cb6b8e9d6d8c626bc73c945db1706035af8fd632295547bf1c9e46d092d6", size = 18651487, upload-time = "2026-05-18T23:33:38.217Z" }, { url = "https://files.pythonhosted.org/packages/15/a7/9bc1cd626d7bf6869bfedf27b91b6ab5dd607758bf8e959d6fa80c6a59cb/numpy-2.4.6-cp311-cp311-win32.whl", hash = "sha256:ddea102b48f9e339f3948bf22040944184627a30fdf7f858667673b9c5f033c8", size = 6233945, upload-time = "2026-05-18T23:33:41.331Z" }, { url = "https://files.pythonhosted.org/packages/c5/31/7fc6239c12bce7e931463251cca4426c465e1876ba3cc785402ef4dd8f4e/numpy-2.4.6-cp311-cp311-win_amd64.whl", hash = "sha256:1e254a00cdf42b1e4d5b3d68d33af63268d41340d8885df2ab6470f2e1500147", size = 12608406, upload-time = "2026-05-18T23:33:44.131Z" }, { url = "https://files.pythonhosted.org/packages/27/83/140f85a466595a16382996a1bf06b2b54bcd597488921b0c9daaeeda72af/numpy-2.4.6-cp311-cp311-win_arm64.whl", hash = "sha256:ed9749eef4cbd126da3dc1d6bcb3a57f5eb7ac6a6484146bdbf743f552dfc577", size = 10479528, upload-time = "2026-05-18T23:33:50.725Z" }, { url = "https://files.pythonhosted.org/packages/95/2a/3d7b5ac8aac24feaf9ad7ed58f45b0bbc06d37e4338ae84c9f2298b570f9/numpy-2.4.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:001fbb8e08d942dd57599e781f2472269ee7f2755fae407b4f67b2f0b17da3f1", size = 16689119, upload-time = "2026-05-18T23:33:54.065Z" }, { url = "https://files.pythonhosted.org/packages/ea/12/92c4c131527599e8288d6918e888d88726f84d805d784b771f32408aeaef/numpy-2.4.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ebfb099f8dcf083deef3ac1ca4c1503f387cf76296fcb3816b66f5ecb5f54fdb", size = 14699246, upload-time = "2026-05-18T23:33:57.621Z" }, { url = "https://files.pythonhosted.org/packages/ad/fe/c0a6b7b2ca128a8fb228575147073b660656734b8ebe4d76c8fd748dcc79/numpy-2.4.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:3213d622a0283a39a93d188f3cf72b26862df52fbb4ca3697f51705016523d41", size = 5204410, upload-time = "2026-05-18T23:34:00.302Z" }, { url = "https://files.pythonhosted.org/packages/f3/d4/9770d14ba719432bb90a421bfd443872ed0f70f7264b64bec12ea363d5fd/numpy-2.4.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:357cc07a6d7b0b182ff02249616a03742827ebb1277546b5c7cd7f7620a45698", size = 6551240, upload-time = "2026-05-18T23:34:02.852Z" }, { url = "https://files.pythonhosted.org/packages/c9/c6/50a46a6205feba2343f1d6d17438107c5dc491ed1c736e6ea68689fd906b/numpy-2.4.6-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f9fb9157b4ce2971008323afe46053787b526ef624fea915b261468a8421a0f", size = 15671012, upload-time = "2026-05-18T23:34:05.485Z" }, { url = "https://files.pythonhosted.org/packages/99/60/14115e6364fa676c5397c2ad3004e527e9aa487abf5d0706ec81bbd08529/numpy-2.4.6-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90f9849678c75fe7afa2d348ac842c168b0a4d3d61919687216dfc547976d853", size = 16645538, upload-time = "2026-05-18T23:34:09.265Z" }, { url = "https://files.pythonhosted.org/packages/ae/c5/693cbe59e57db94d2231fa519ca3978dc9e19da5a8f088588f5c6e947ff2/numpy-2.4.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c1a2af6c6ef86344a6b0db6b97834208bf598db514f2b155042439b62605601a", size = 17020706, upload-time = "2026-05-18T23:34:13.053Z" }, { url = "https://files.pythonhosted.org/packages/ef/fc/85b7c4eff9b4966ade25c2273cf7e7012e92366c032058653934b37de044/numpy-2.4.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e5805d5a22fd19c8ccff10a9561f9df94436b0545619ea579db2d3c35294bce2", size = 18368541, upload-time = "2026-05-18T23:34:17.024Z" }, { url = "https://files.pythonhosted.org/packages/f6/81/e1b27545deedce7f4a0b348618c6b62d74e36a4dc9ccd42f3eb2f85eee32/numpy-2.4.6-cp312-cp312-win32.whl", hash = "sha256:e3eeb0aabd6bd5ce64faae67e9935203a6991b4bc2a485a767fbafb2c5125f45", size = 5962825, upload-time = "2026-05-18T23:34:20.3Z" }, { url = "https://files.pythonhosted.org/packages/ab/ca/feab00bd44aa5fe1ad2c18f08b4d3bb92e26484b0b1d1443897809ed528c/numpy-2.4.6-cp312-cp312-win_amd64.whl", hash = "sha256:d8e8286dd7cea7895157318d1b91cdacac64c479f3cbc8dce548331728484751", size = 12321687, upload-time = "2026-05-18T23:34:23.095Z" }, { url = "https://files.pythonhosted.org/packages/63/cf/5a6d34850a39d1093558564f77ee8e8e0bee5061151b8f05a55711001ec7/numpy-2.4.6-cp312-cp312-win_arm64.whl", hash = "sha256:4081eb135ac24158bd51cdfbef16f1c64df7063b1143f24731387137c092bec8", size = 10221482, upload-time = "2026-05-18T23:34:25.876Z" }, { url = "https://files.pythonhosted.org/packages/fb/82/bdab26d7438c6791ca31b7c024ca37c1eab8b726ba236129005cd4a06e45/numpy-2.4.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:511dbaf848decaaaf4b4ca48032619fb3138710c4bf7da7617765edad1ef96b0", size = 16684648, upload-time = "2026-05-18T23:34:29.41Z" }, { url = "https://files.pythonhosted.org/packages/1b/30/a80189bcc7f5e4258b3fbc3968d909d1756f54d023299ecc39ad6fdb9ef8/numpy-2.4.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bf162abab1c1a736333192707cef898e735a5ca00f38f27eeedf44b39d9e85eb", size = 14693902, upload-time = "2026-05-18T23:34:33.013Z" }, { url = "https://files.pythonhosted.org/packages/97/12/70b5d0d7c15e1ebb8a6a84a8caa1d19e181d84fb58bb6d70aca29099dec1/numpy-2.4.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:043191bfa8eab18c776647b62723ac9dddece59743b13f49b2016094129c2b3f", size = 5198992, upload-time = "2026-05-18T23:34:36.132Z" }, { url = "https://files.pythonhosted.org/packages/ba/8c/ebd2a8f8a83541f8d38cc5667e8c2b69cecfd30da6e45693e8158857d44b/numpy-2.4.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:6180d8b35af935aed8ece3a85e0a43f87393ae0ac87c8d2c8bd2c993f7270ef3", size = 6546944, upload-time = "2026-05-18T23:34:38.484Z" }, { url = "https://files.pythonhosted.org/packages/bb/c5/7b863a97a91671a0338f4253bd3b5a3d3852f0692dae91711c9f4a10e787/numpy-2.4.6-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72fbe16c6fac95aedf5937fa873445cec2110be35d8a4e9433d7501fd98dae6b", size = 15669392, upload-time = "2026-05-18T23:34:41.257Z" }, { url = "https://files.pythonhosted.org/packages/a5/9d/3584b9984ca4c047aea75214ce1a4c4c73d849bd71b604264b7f5653f8a8/numpy-2.4.6-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a7830bab239b79cda9c08c2da014761cafb48da6150e1da17ac06283f43b6089", size = 16633220, upload-time = "2026-05-18T23:34:45.075Z" }, { url = "https://files.pythonhosted.org/packages/05/ae/7c67fba23bd98caec7c99261f3a16072ade14813486b0282cb29846de832/numpy-2.4.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ef4aea96ce4d3b074422cb4f2f64e216bf9e213004bb58ecfdf50ea02ea8eb9a", size = 17020800, upload-time = "2026-05-18T23:34:49.065Z" }, { url = "https://files.pythonhosted.org/packages/d9/5d/3b6725cb31d983c5e66916f5d36f6d7e5521129e4c4404d64f918292a5b6/numpy-2.4.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dfa20cc6ca228e6b155b11da03825975ce66aea520985dbbddf0f2a5a495c605", size = 18357600, upload-time = "2026-05-18T23:34:52.709Z" }, { url = "https://files.pythonhosted.org/packages/f7/da/2ccc6c2fe8898dee01d90c75c5f5f914a23daf99e3e0f59516a08760c8b5/numpy-2.4.6-cp313-cp313-win32.whl", hash = "sha256:56b39e5e0622a09a25bf5baf62f4bcf0cb8a41ae6e2819cf49bbc5a74c083f91", size = 5961134, upload-time = "2026-05-18T23:34:55.618Z" }, { url = "https://files.pythonhosted.org/packages/b5/cd/9cc4dc876fb065d5c220aae4d5e14826b2715331bb7618ce1fb07a679d99/numpy-2.4.6-cp313-cp313-win_amd64.whl", hash = "sha256:c4fc99836233ea196540b17ab0983aff60ed07941751930f5f4d05bc3b3b7359", size = 12318598, upload-time = "2026-05-18T23:34:58.928Z" }, { url = "https://files.pythonhosted.org/packages/39/1e/c0bcba1f8694116485fe28fd1be698c278fcda4141c5b0e53a2aed8b12a8/numpy-2.4.6-cp313-cp313-win_arm64.whl", hash = "sha256:a7c711e21628b52034bb5ab8d1bce291f752fcc5e92accc615778acee1ff4778", size = 10222272, upload-time = "2026-05-18T23:35:02.167Z" }, { url = "https://files.pythonhosted.org/packages/63/6d/cc5619247c8f4204e507f5883528372e4ac4bb189e579fb859a12e480b1f/numpy-2.4.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:112b06a867b235ef466ed3508ddf0238050df9c727cafb5301ac385b899189a1", size = 14821197, upload-time = "2026-05-18T23:35:05.468Z" }, { url = "https://files.pythonhosted.org/packages/00/58/f1c39161c87d9e9bed660f1ed4bafc0e403d5ec9650b6dd77aead07d489b/numpy-2.4.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:eaf7fa2de5c0be8ae6ff8e9bea2ccd725e980541244521d8d4b5f3354a27babe", size = 5326287, upload-time = "2026-05-18T23:35:08.693Z" }, { url = "https://files.pythonhosted.org/packages/af/57/3917ab0fd97f271a8694513581b8a36c655f111c446852c302f04ccdb6fc/numpy-2.4.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:7265a2f3d436e54ef9f2b52b5c937e6be778781bd97a590319d7348f1c1ca997", size = 6646763, upload-time = "2026-05-18T23:35:11.459Z" }, { url = "https://files.pythonhosted.org/packages/eb/0f/037e64c494b67581ae18193d770adef354c41f3f2c8ebf865602d949bf8f/numpy-2.4.6-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f74a575920ab21fe304421a3fc28793d82e299cae9eccb37084e9fc7f3617c20", size = 15728070, upload-time = "2026-05-18T23:35:14.79Z" }, { url = "https://files.pythonhosted.org/packages/21/a6/5d2bae9c9542eb4df16dc9c46dc79c186e9bad53805dfa5399a6023c6db0/numpy-2.4.6-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ede83e07a75dd06bc501566c1eca2afc0d61677c1472ac9ad93fdee6e638a48d", size = 16681752, upload-time = "2026-05-18T23:35:18.836Z" }, { url = "https://files.pythonhosted.org/packages/92/14/23d1dfb410ae362cd59ce53e936b1513d545eb40db3949ced632e19a459e/numpy-2.4.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:68bb27509ac1b9a3443094260f6326150663b06abe40b73a2f81160623da5b67", size = 17086024, upload-time = "2026-05-18T23:35:22.52Z" }, { url = "https://files.pythonhosted.org/packages/4b/6e/23595a2c642cdf3bc567877064bdd7f91c8b0038a4453cf2daf7248eafe9/numpy-2.4.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a0df0043bdb289bde1f62da130d20df23d58b45429f752bc7a8fc5325a225ecd", size = 18403398, upload-time = "2026-05-18T23:35:26.398Z" }, { url = "https://files.pythonhosted.org/packages/8a/90/0ac3bc947217e66dec77e7cbc6a1979d1af70b6461b82f620d3bccd5e4c8/numpy-2.4.6-cp313-cp313t-win32.whl", hash = "sha256:29a287e0cf63ff528da061de6b9f64a4618da591ca1046aafc54062e40ca7eab", size = 6084971, upload-time = "2026-05-18T23:35:29.387Z" }, { url = "https://files.pythonhosted.org/packages/77/71/5673e351671a1d2bd6063b91b44f70c0affea7d1516fa7a6572941ba4aa1/numpy-2.4.6-cp313-cp313t-win_amd64.whl", hash = "sha256:25c692919ac5a01f170a3bfcd62d745b24fd095c353d50812637d6fcab442e75", size = 12458532, upload-time = "2026-05-18T23:35:32.175Z" }, { url = "https://files.pythonhosted.org/packages/3f/88/19d3503c5046e688f049274b27a3ef3d771152fa80d3ba3d01a3dff61abe/numpy-2.4.6-cp313-cp313t-win_arm64.whl", hash = "sha256:1e978ec1e8bd0e0e4de6bb75de9d30cbb74db6b6a2bb727618613703ca0167dd", size = 10291881, upload-time = "2026-05-18T23:35:35.465Z" }, { url = "https://files.pythonhosted.org/packages/f8/91/3ab2044d05fd16d343c5ac2e69b127f1b2854040dd20b193257c78028bd3/numpy-2.4.6-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:06ca2f61ec4385a07a6977c55ba998a4466c123642b4a32694d3128fce18c079", size = 16683458, upload-time = "2026-05-18T23:35:38.353Z" }, { url = "https://files.pythonhosted.org/packages/8e/62/764ce66fa4147ae6d73071a3abf804ffe606f174618697c571acdf26a7c9/numpy-2.4.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:38efbc8de75c7a0fc1ac190162d892787f3f47b57cc291231aafee36b80982b7", size = 14704559, upload-time = "2026-05-18T23:35:42.14Z" }, { url = "https://files.pythonhosted.org/packages/60/61/23f27c172f022e04025b7dc2367f4d63c1a398120607ec896228649a6f48/numpy-2.4.6-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:d581b735e177fdcdce6fed8e7e8880a3fb6ee4e3653a3ac6af01c6f4c03effc5", size = 5209716, upload-time = "2026-05-18T23:35:45.377Z" }, { url = "https://files.pythonhosted.org/packages/03/71/21cf70dc6ea3e3acb95fc53a265b2fc248b981f0194ceb5b475271b8809d/numpy-2.4.6-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:0a041d3d761dc3c35cc56ce0351506a02bcbc25f7b169f652435141a17db9096", size = 6543947, upload-time = "2026-05-18T23:35:47.926Z" }, { url = "https://files.pythonhosted.org/packages/d5/91/64288395ee1799bd2e0b04a305dce9666da90c961e1f3fe982a05ee1c036/numpy-2.4.6-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:40fdc1ae7125e518ea98e53e69a4ebc27e1fd50510c47b7ea130cf21e5e1d42b", size = 15685197, upload-time = "2026-05-18T23:35:50.863Z" }, { url = "https://files.pythonhosted.org/packages/f3/eb/ebffaa97dc55502df69584a8f0dcf07f69a3e0b3e2323670a2722db9aa39/numpy-2.4.6-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a2c306dea656c12c68f51f4cea133cbe78ca7435eb28c735eac1d3ebe73be6e8", size = 16638245, upload-time = "2026-05-18T23:35:54.752Z" }, { url = "https://files.pythonhosted.org/packages/b8/0b/54f9da33128d7e350fab89c7455902eeae70349ee52bddb448dc4a576f45/numpy-2.4.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:33111801a01c12a8a1e3721f0a9232f8cfc8ae2c6b7098167e6f623c6073f402", size = 17036587, upload-time = "2026-05-18T23:35:58.355Z" }, { url = "https://files.pythonhosted.org/packages/b6/f0/fdebc1052db1cc37c64beb22072d67cd6d1c71adca1299f53dec2b5e20d3/numpy-2.4.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ae506e6902902557576a26ff33eda8695e7ecb3cb36c3b573a0765dee114ebdb", size = 18363226, upload-time = "2026-05-18T23:36:02.845Z" }, { url = "https://files.pythonhosted.org/packages/aa/b4/298628d98c72b57e57f7165ae6a481a1deaf6f3c28262a6e4c739c275930/numpy-2.4.6-cp314-cp314-win32.whl", hash = "sha256:aaf159caa35993cb1f56fb9b8e4610d35758e7ca005412eb1daa856a78c9c4b1", size = 6010196, upload-time = "2026-05-18T23:36:05.92Z" }, { url = "https://files.pythonhosted.org/packages/df/ac/46de6dda46478f7942f839e094970be2d4a861e005c4b3bf07c92e291a09/numpy-2.4.6-cp314-cp314-win_amd64.whl", hash = "sha256:b507f5c4c1d508876d1819b6bf9a49d365b96320b5d4993426b33a23ca4b8261", size = 12450334, upload-time = "2026-05-18T23:36:09.107Z" }, { url = "https://files.pythonhosted.org/packages/78/92/b8b798ac784102c0da830d2257d59358e3d3d90d1e2b3f2575dad976c5cf/numpy-2.4.6-cp314-cp314-win_arm64.whl", hash = "sha256:6f41ae150c4e32db4f3310cdaf64b1593a03dbabe29eec77fc9b50fe64061df6", size = 10495678, upload-time = "2026-05-18T23:36:12.766Z" }, { url = "https://files.pythonhosted.org/packages/30/34/ec28d1aa8115971537c01469ab2011ee96827930f0a124de1000cc2a7ed7/numpy-2.4.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ece3d2cfe132e7d51f44a832b303895e6f2d499c5e74dfbdb06ee246147a304a", size = 14823672, upload-time = "2026-05-18T23:36:16.473Z" }, { url = "https://files.pythonhosted.org/packages/16/bd/f6d1fede4e54e8042a7ff97bb495510f3c220f94bcd9e8b228e87c92cc0d/numpy-2.4.6-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:e3e5193ef5a3dc73bceee50f7fdc2c90dbb76c42df8d8fae3d1067a583df579e", size = 5328731, upload-time = "2026-05-18T23:36:19.767Z" }, { url = "https://files.pythonhosted.org/packages/f4/f0/e105b9e2fd728a9910103884decd6951d9dd73896b914a98d9a231de02ee/numpy-2.4.6-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:17f9ade344e7d9b464a084d69bcf18fc691cb1db67c62ed80820bf4926d78f0e", size = 6649805, upload-time = "2026-05-18T23:36:22.266Z" }, { url = "https://files.pythonhosted.org/packages/82/dd/1206a7ca6ab15e3f02069707ca96222e202af681bb73756da7527f3cb837/numpy-2.4.6-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9cd5ffd25db4e7ba6a375693b3fc0fc1791ec636c17db3720da19bde7180ec43", size = 15730496, upload-time = "2026-05-18T23:36:25.713Z" }, { url = "https://files.pythonhosted.org/packages/51/e7/38d3ea825dcab85a591734decb2f6c67caa7c8367d374df1a1c3842f9b07/numpy-2.4.6-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d92c3819208a60205a12a245c91ad70cb0a85336659b19b834205573ac8456e", size = 16679616, upload-time = "2026-05-18T23:36:29.652Z" }, { url = "https://files.pythonhosted.org/packages/93/b7/caabfdf53edf663e0b4eb74d7d405d83baef09eb5e83bcd32d601d72b93e/numpy-2.4.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e85b752a1e912b70eaad4fafbd4d1238007ab221de2009b9a2f5ae7461239895", size = 17085145, upload-time = "2026-05-18T23:36:33.449Z" }, { url = "https://files.pythonhosted.org/packages/f9/45/68d7c33a6bcf3e5aa3bdbd57a367e6f615286dfd6482f97e8ffeb734306e/numpy-2.4.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:29cb7f67d10b479ff07c17d33e39f78c07f71c40ef30d63c153d340e96cd3fb4", size = 18403813, upload-time = "2026-05-18T23:36:37.369Z" }, { url = "https://files.pythonhosted.org/packages/9c/50/0753655aa844c99cd9e018aacf76f130f1bd81d881bb74bc0aef5d73a8ba/numpy-2.4.6-cp314-cp314t-win32.whl", hash = "sha256:260a5d70215b61ab4fadf5c7baacd64821842975eea312125ed3c39a6391b063", size = 6156982, upload-time = "2026-05-18T23:36:40.817Z" }, { url = "https://files.pythonhosted.org/packages/b2/d4/7c67becf668f973cb490cec3e98dfd799d866f9c989a54d355672cfa0db6/numpy-2.4.6-cp314-cp314t-win_amd64.whl", hash = "sha256:81a1cca95ed5bb92aa8b10dd2cdc9a0d3853a50fad926c28b5d7e8ea54389627", size = 12638908, upload-time = "2026-05-18T23:36:43.996Z" }, { url = "https://files.pythonhosted.org/packages/43/bb/e1c71a4295b1b1d1393d50dbb4f2a36283c6859d9d3892e84f00ec5a91d5/numpy-2.4.6-cp314-cp314t-win_arm64.whl", hash = "sha256:0c9136e14ed34a9e343a31c533d78a9813a69a3148332bce5e9821cb2f996e66", size = 10565867, upload-time = "2026-05-18T23:36:47.114Z" }, { url = "https://files.pythonhosted.org/packages/de/12/b422cc84439adc0d00de605bf4a308890ae5c26f2c71fbd73e5d08fbb0dd/numpy-2.4.6-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:55cced7c52e981362f708ad635198e97a752dfba412cc03c23bbf3bd8d5cd662", size = 16847511, upload-time = "2026-05-18T23:36:50.673Z" }, { url = "https://files.pythonhosted.org/packages/44/53/f481bef68011740f8849418d82db07230e825013f31f4eef5ba5b805316a/numpy-2.4.6-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d6da64deb6b8ed903e7560180a92f2d804ee1ba5eeb849ac2748b8c1aba1f6d7", size = 14889064, upload-time = "2026-05-18T23:36:53.879Z" }, { url = "https://files.pythonhosted.org/packages/7f/57/42ed575c10ced8af951d426bc4e1f8aff16fd851db33f067036215a7f860/numpy-2.4.6-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:68a5124b13fa6cc2086764a20005d30bc0548146f7f5322f02fce212ca14317f", size = 5394157, upload-time = "2026-05-18T23:36:57.194Z" }, { url = "https://files.pythonhosted.org/packages/6a/ef/f66cc724fcc36c1e364c67f51ae9146090b8b584f27d58b97fdae3edd737/numpy-2.4.6-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:948424b06129ce883307e8cff868c31396d8dc7630a59c61d70d98dbe70f222c", size = 6708728, upload-time = "2026-05-18T23:36:59.575Z" }, { url = "https://files.pythonhosted.org/packages/1a/9c/c531f2293b91265d8b48e9b329f54fdd7ffae73cb4134ea10cca4237e9cc/numpy-2.4.6-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5dbbdb29840ca3d91ee0fece42fc29278886d908280bfec0a5846c6f901a3eb0", size = 15798374, upload-time = "2026-05-18T23:37:02.674Z" }, { url = "https://files.pythonhosted.org/packages/1a/b0/413077f6b1153ed3cba361401c6783bbad6114804a000cc22eb71c13e190/numpy-2.4.6-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8ad03c0965fb3c692200e74d458ca28c1dbb4ce96f9a479a8aa041ad5fabca02", size = 16747286, upload-time = "2026-05-18T23:37:06.327Z" }, { url = "https://files.pythonhosted.org/packages/15/ce/e5ec180bc41812edcd8daeb8639d205622c0e8c02259d8ab25a0201b3c2a/numpy-2.4.6-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:2803abfebfc990042cd494d8ce2d5f82e9d847af6d35ec486923aa19dbad5e73", size = 12504263, upload-time = "2026-05-18T23:37:09.715Z" }, ] [[package]] name = "numpy" version = "2.5.4" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.15' and sys_platform == 'win32'", "python_full_version >= '3.15' and sys_platform == 'emscripten'", "python_full_version >= '3.15' and sys_platform != 'emscripten' and sys_platform != 'win32'", "python_full_version == '3.14.*' and sys_platform == 'win32'", "python_full_version == '3.14.*' and sys_platform == 'emscripten'", "python_full_version == '3.14.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", "python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'win32'", "python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'emscripten'", "python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] sdist = { url = "https://files.pythonhosted.org/packages/95/b0/c7453d0b6e2073c3264468b106ee1563750cecc910965e67357e3698c83e/numpy-2.5.4.tar.gz", hash = "sha256:9a94cf751c9ad8ebaa835bcd3d40dacf8534ad086b88c38029b65123c7999d2a", size = 20866315, upload-time = "2026-10-10T20:05:31.422Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d0/97/ba2074e92b7befea137e77ea8471e768bbd87c339b7e8c9f5a931949f977/numpy-2.5.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c6342f54c67093cae5c0227eb0eb772fdb79f2a2c37a6eb278b9909ee06aa356", size = 17001609, upload-time = "2026-10-10T20:02:40.843Z" }, { url = "https://files.pythonhosted.org/packages/ff/a9/bac826765e971d8e16e2064e9ac7525fd69b40ac17c905033a7f5442023f/numpy-2.5.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b11e8fda06a7d69f15ebf542660b74466c2e51094800c1fb794f47ad4faeef17", size = 12015718, upload-time = "2026-10-10T20:02:43.45Z" }, { url = "https://files.pythonhosted.org/packages/31/2f/5ea3570fcb8ccd0882bea99436a513b2c85dad8f774a2057849130a8fb99/numpy-2.5.4-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9cb18a327b49c5c337f972b03682f6a49855525faaf3c0d3e9c96cd0fd8880a8", size = 5451717, upload-time = "2026-10-10T20:02:46.169Z" }, { url = "https://files.pythonhosted.org/packages/34/f2/b4fc1bafca03868220b5eaf729d2f21ebd7d7b151c0f9e144fe212bbca35/numpy-2.5.4-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:aec3fc4b32ff82421274f5d205c559c51c840c8df66a78efd7f3612dd005a26a", size = 6789926, upload-time = "2026-10-10T20:02:48.139Z" }, { url = "https://files.pythonhosted.org/packages/dc/96/8319e2457ae4333c62c815c7006b869a4f60985c1e01024c2f8c6c040fe5/numpy-2.5.4-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fe4d21ab149f15e4e6043dfb0de87e6e5f34ac176cde83060e9802981fca2ac2", size = 15695312, upload-time = "2026-10-10T20:02:50.115Z" }, { url = "https://files.pythonhosted.org/packages/43/a3/c799c62e19c337e6d3770b08e475887fb30ce8477d3c09efca6b2f0228a6/numpy-2.5.4-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fbde6962867ee75b48b0ee29b2b9372ec5d617799dbaf38e82dc0596f2f7738a", size = 16727283, upload-time = "2026-10-10T20:02:53.186Z" }, { url = "https://files.pythonhosted.org/packages/39/6b/3604e53fb00314d0dc1b94ec9125a1484f649c0a17480b1f0f0c7a9d6250/numpy-2.5.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:381a7a3d2e65e64c0ec302795ab9dc12bb1e73f150904699c153716177eebdaf", size = 17047890, upload-time = "2026-10-10T20:02:56.038Z" }, { url = "https://files.pythonhosted.org/packages/4a/7a/e8b58a5289a0d464c52885de47c35a935cdd70c03a4c3ab94a5126416dd0/numpy-2.5.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b89d0aaae2fe498c648f4c4795c084db535af5bd98ef942b2a3681fb74ce8645", size = 18485839, upload-time = "2026-10-10T20:02:59.018Z" }, { url = "https://files.pythonhosted.org/packages/6f/c9/47094f597015009f310b8c900def59065ef1ff5a6fe7b51fc65ec58ec2c6/numpy-2.5.4-cp312-cp312-win32.whl", hash = "sha256:9968ab7e49b93ac6e1c3b2239732183152c9150f16308d30b66a372cffe3483c", size = 6138936, upload-time = "2026-10-10T20:03:01.626Z" }, { url = "https://files.pythonhosted.org/packages/12/33/fefe62073dc8acfd0f2b9ed7c003af2f50aa61555e113e6db02b8f79f145/numpy-2.5.4-cp312-cp312-win_amd64.whl", hash = "sha256:a7b1b6353e36a7e50de2973a38d705c88ee93adcf120673cee7f45a4a3fa223a", size = 12573091, upload-time = "2026-10-10T20:03:04.349Z" }, { url = "https://files.pythonhosted.org/packages/1a/07/161270b0c2eec56e4c905f6d6d22e1b836887b2cb189d3f5820aa588e9dd/numpy-2.5.4-cp312-cp312-win_arm64.whl", hash = "sha256:aa1cce2ff3f8d953de38b76bf44602caeb69f101430208f64a10067f7cb4b1d3", size = 10521630, upload-time = "2026-10-10T20:03:06.767Z" }, { url = "https://files.pythonhosted.org/packages/67/14/1c3ee0118a8fce08565a5d8482631608426a33af10a01077fada5dc7c119/numpy-2.5.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2377da2dd3ba2c1200956acbab2a358c83b8e1f8531191672d1cd6ad83250d53", size = 16997729, upload-time = "2026-10-10T20:03:09.291Z" }, { url = "https://files.pythonhosted.org/packages/83/8c/b0ea9477fb1f0d4484bbc5cba21678cc9969704d8d7f3f158d1db35f8e14/numpy-2.5.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7415db95818b39ec475a5eea54d9e3b6bc83e3912158e46da3438cdce399804d", size = 12009826, upload-time = "2026-10-10T20:03:11.946Z" }, { url = "https://files.pythonhosted.org/packages/e2/84/6a3d75b3ba3dfe84ac0053450753d1e6d250a8bf80f66474cc46d1fb643f/numpy-2.5.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:6d6a71b9d9a97c03633aa12565ef2825ffa036cc1d99cfd50dacf0f128af4fe2", size = 5445803, upload-time = "2026-10-10T20:03:14.329Z" }, { url = "https://files.pythonhosted.org/packages/61/18/bb993f267ca20b376e07092a16793a5b31ed3138751e9ba480011a14d742/numpy-2.5.4-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:d8200f16437b289a5bb927c6e184eccc3e8389bc0070fea4cd5b9e13c1757959", size = 6786220, upload-time = "2026-10-10T20:03:16.602Z" }, { url = "https://files.pythonhosted.org/packages/db/b6/135bb0953b61dc21c6cafa14b424ae666944e4899cf140e00c2b322a1a45/numpy-2.5.4-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c2e71b04c6cad90026e544501bbe0ab9290fa8a4d845e7e8c0d124fb429c988", size = 15689178, upload-time = "2026-10-10T20:03:18.721Z" }, { url = "https://files.pythonhosted.org/packages/da/24/3bd070f3269dc609d8f26b2643f62ef91bb415841c0b294805aaf7fe06da/numpy-2.5.4-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6ffa07666f8da0eef81d149934a626d0d95fbd6838432a33e66245423a9062c0", size = 16718044, upload-time = "2026-10-10T20:03:21.386Z" }, { url = "https://files.pythonhosted.org/packages/c7/8e/9d15bd356b0a019c965312b1a3c6a727cac4cae5bc40045fbc12ce4cff9c/numpy-2.5.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2fa3328f784fc8277fc48026f6cad516f5c561c5d8e2e39b3c9e0c8f23223b34", size = 17048364, upload-time = "2026-10-10T20:03:24.468Z" }, { url = "https://files.pythonhosted.org/packages/dc/fe/9d5b560db964f15871885f2250795d15945f8699e17ef90c0c2ff4c875b2/numpy-2.5.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b86966fbe4ad7de710422175572bcdc75fdedadfb54bc6fab7deabccddd7780b", size = 18474904, upload-time = "2026-10-10T20:03:27.895Z" }, { url = "https://files.pythonhosted.org/packages/e9/98/d27552990f1bd611ef3e7466adadc78312ea2df63b83aad47fdc3d3ca8df/numpy-2.5.4-cp313-cp313-win32.whl", hash = "sha256:5258bc06526964be5face2fc6f756857a3f24f21ec3e72ca131337a75b165d6c", size = 6134537, upload-time = "2026-10-10T20:03:30.511Z" }, { url = "https://files.pythonhosted.org/packages/90/8c/140a40398a66b4471211be1affdb6ed24c486d581bd28d07b7f2fcb69540/numpy-2.5.4-cp313-cp313-win_amd64.whl", hash = "sha256:8b4d2fd2d34e5f8c9235ee787de5631a37a28402b15cb80814df973d2be54129", size = 12566113, upload-time = "2026-10-10T20:03:32.612Z" }, { url = "https://files.pythonhosted.org/packages/34/52/01d205e5e8ccb27b2b0b141e801f22b830198c979111b0fa44771438d9a9/numpy-2.5.4-cp313-cp313-win_arm64.whl", hash = "sha256:bc39ac66a7a9a3fbd6134fda43136b60ffde99c8f4501e64e0d2b24da137babf", size = 10519523, upload-time = "2026-10-10T20:03:35.163Z" }, { url = "https://files.pythonhosted.org/packages/99/ba/005cb5edd580d2f84d7ca3206b92dc17d4388e56e6f87ffe8f2762f83139/numpy-2.5.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:c668b2f0d651605b58892644b0e302c7157f7159544227758c896982ef384b18", size = 17005499, upload-time = "2026-10-10T20:03:37.961Z" }, { url = "https://files.pythonhosted.org/packages/f3/49/fee7587c33ee35f7977f9051d7f2023d4e7246d62710c80f20c2361ea232/numpy-2.5.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ffa6ce09a1c6a08e9667dd9c97aa0b14184e8d18f2a14b78b2a2328c9147f076", size = 12019666, upload-time = "2026-10-10T20:03:40.606Z" }, { url = "https://files.pythonhosted.org/packages/d5/b2/c6ce165acffceb15a82c07b9cc77d391f86b3f379ba62911908ae5d34b91/numpy-2.5.4-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:956555e0603a4d38019ae6925711cb9dc43195c076a928accf7ea5d50bddfe53", size = 5455617, upload-time = "2026-10-10T20:03:43.138Z" }, { url = "https://files.pythonhosted.org/packages/77/7f/dd85ce260a669a89be06842cf355d7353a33e6cfbc590fb8ebb947d88dc9/numpy-2.5.4-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:2c2c4afffdeb7920e445028dd71eb932cac3e704792e964bc2a232426d4f1255", size = 6791932, upload-time = "2026-10-10T20:03:44.874Z" }, { url = "https://files.pythonhosted.org/packages/63/d6/34b0a2b0741386a63025a65a2c09caaaaaad6d0ca95b66cd65c30dd7fcb5/numpy-2.5.4-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4054173604cd8658796053f1f3bc0befb68ec1c0762c57fdad61e199256a8617", size = 15710899, upload-time = "2026-10-10T20:03:46.839Z" }, { url = "https://files.pythonhosted.org/packages/16/d5/928078d2b28f26829b138b4a6c3980045022fb409f570657a224ae60ef4e/numpy-2.5.4-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d549420b8858885cea8838a727842249218b9c1da24dd517e25c9c7a948310a3", size = 16721710, upload-time = "2026-10-10T20:03:49.489Z" }, { url = "https://files.pythonhosted.org/packages/f9/cf/673fd1b8f4cd78eb6320e87ec4c90ac19c095644259e3749853a405c70f4/numpy-2.5.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:823874a507a84af050493b622affde94b6f7c3a0dc22cb2801381bc03b871c00", size = 17066182, upload-time = "2026-10-10T20:03:52.25Z" }, { url = "https://files.pythonhosted.org/packages/f3/92/a77b5061b1b3e2643928c37976d79ee173e1b171ed158b7a3c61056b41bc/numpy-2.5.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4e263278bfb5ee6409db8aedbc4cc32973b1b82bc1e8d3c668551d04d83a7e37", size = 18480315, upload-time = "2026-10-10T20:03:55.39Z" }, { url = "https://files.pythonhosted.org/packages/bb/1d/1486ef3d3fb2279fd93c4c43c1bbbf1ca389a19816696684409f71babaab/numpy-2.5.4-cp314-cp314-win32.whl", hash = "sha256:cfd73180400042a7c532d30c5e287bdd03c59ff9ee1b4c0316af0539e29dfe23", size = 6185739, upload-time = "2026-10-10T20:03:58.186Z" }, { url = "https://files.pythonhosted.org/packages/52/9a/e1e512ebc948d5b9dd33b08736760f0ebbed2848fd4eda1f553088a6dcee/numpy-2.5.4-cp314-cp314-win_amd64.whl", hash = "sha256:2ca144f15135b6212a5c47b1e2aeca6e412f102f95a2d5d88d8aec77eb255de3", size = 12703552, upload-time = "2026-10-10T20:04:00.28Z" }, { url = "https://files.pythonhosted.org/packages/2c/05/de709a982d7bbcd688a3fad71f002e9ff80c2db39e03ee726609b610f1d1/numpy-2.5.4-cp314-cp314-win_arm64.whl", hash = "sha256:468397ba3c64427474706e5c9123fe266395496714dc684294eac75cd4930d1e", size = 10803901, upload-time = "2026-10-10T20:04:02.659Z" }, { url = "https://files.pythonhosted.org/packages/13/34/083570ada3bb2a30fbe5d77c8c6fef9141144a15d33e6f793a67e9749ab8/numpy-2.5.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1ef3aa6d7e29bb13677323114280b05acc57607fa2300e66432d665d5418a162", size = 12138695, upload-time = "2026-10-10T20:04:05.012Z" }, { url = "https://files.pythonhosted.org/packages/94/06/1f9c24db48eef0c2d1207e3b11fffb0478e39dfd8c1e1be7476936885eed/numpy-2.5.4-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:98b053943e5a0474ec0da309d2cb9d3f18ea57f8a2067c2ab7b5f763d1068380", size = 5574615, upload-time = "2026-10-10T20:04:07.316Z" }, { url = "https://files.pythonhosted.org/packages/da/0f/593fba2e1560e949123bc7d2fc48b5893d56e58cd4bd5a273d2fbf60b220/numpy-2.5.4-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:b64a85f40e154983960a4167d4c1d57a50c7f109b3d3264a3a984154e90a8454", size = 6889383, upload-time = "2026-10-10T20:04:09.918Z" }, { url = "https://files.pythonhosted.org/packages/eb/9f/b799dfdce4e05e80ed4bc815c71ff343a11533b2c0ffc221cae8538cda63/numpy-2.5.4-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a813ed7719bf45463c51779e6a98d0385fe905e48447526938a4b8337333d551", size = 15753763, upload-time = "2026-10-10T20:04:12.278Z" }, { url = "https://files.pythonhosted.org/packages/34/88/16c5f12f86f5ad2817c4d103205131fc6c8acb3d1878af05a1a4f23ec859/numpy-2.5.4-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9b80cdf5cedba0e90d93fa5f9a333c4d65bd545cd669b71bb97ce2b703c9d73", size = 16757212, upload-time = "2026-10-10T20:04:14.799Z" }, { url = "https://files.pythonhosted.org/packages/ff/4f/a1fe40e18a898e6a5089f4f0d891f0a493eb0574d5b34458f0fbe5aa3e5c/numpy-2.5.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2199ed071f460487c8db2c0e5c0b564494190edb4772fe80f9aad88b2604def5", size = 17116471, upload-time = "2026-10-10T20:04:17.58Z" }, { url = "https://files.pythonhosted.org/packages/aa/46/e923a11c78e65c1722e7aaad817c06bd591324174b9d28ce5d31eee4d432/numpy-2.5.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:64f9c9878c1938476365e11ccfb6b770f3b9e5f045ccddc514235041e6959365", size = 18524063, upload-time = "2026-10-10T20:04:20.365Z" }, { url = "https://files.pythonhosted.org/packages/5a/fa/84ab064514440c1f64a1b21088f2c82756defdd05e07c75ab233899565b2/numpy-2.5.4-cp314-cp314t-win32.whl", hash = "sha256:64d1c8ac28a4077cf987e0a71a7a0ef7e2df70722f07f0baa42dbb7eb6938647", size = 6340926, upload-time = "2026-10-10T20:04:22.865Z" }, { url = "https://files.pythonhosted.org/packages/7e/7e/6cd886876f435b10685db9b9f7eeb70356f99e052116f4e5f11c5792c714/numpy-2.5.4-cp314-cp314t-win_amd64.whl", hash = "sha256:067374eb538c34c745436365cf7b0112595c1d326f21ce4ff340f61230239fbb", size = 12901584, upload-time = "2026-10-10T20:04:24.99Z" }, { url = "https://files.pythonhosted.org/packages/38/1b/3c1684f6a06f7307f2335fca6e486cb162847fb97e91d65f8eb5cabad213/numpy-2.5.4-cp314-cp314t-win_arm64.whl", hash = "sha256:e94aef2c639da4a960ad0db8e06471208d8589974953d78b61d345b4eb99e394", size = 10891152, upload-time = "2026-10-10T20:04:27.52Z" }, { url = "https://files.pythonhosted.org/packages/08/f4/3224deff3af2bef6bc0b175369698d8cb348f3d91d9bb0286cd5c9eae9e0/numpy-2.5.4-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:8dddfbee2e68d26d0d7d7d9cb247b1fd4409241cce32d815a11d97ec2cfde179", size = 17003231, upload-time = "2026-10-10T20:04:30.021Z" }, { url = "https://files.pythonhosted.org/packages/be/75/fee0b8c6d94b44b2fdfae74f6a4ad5a138739589a8aebaec28ce4e713ed5/numpy-2.5.4-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:81e3420b27048b65eb14c3acf0c174a8cb0e023277716110347d2dcb26026dad", size = 12018300, upload-time = "2026-10-10T20:04:32.519Z" }, { url = "https://files.pythonhosted.org/packages/47/c0/d0b335a499a04b65f532c3f034346ef390f81299060f928492dabc1e0272/numpy-2.5.4-cp315-cp315-macosx_14_0_arm64.whl", hash = "sha256:0b4724a19de67bea8cfc4970798efa78bcbbe2ac2613cfac16721a42d44de2a5", size = 5454250, upload-time = "2026-10-10T20:04:34.943Z" }, { url = "https://files.pythonhosted.org/packages/5a/0e/461b3783c03d668052e6a21b01b673db6ffcb7831fd32d9aa5368c1cd426/numpy-2.5.4-cp315-cp315-macosx_14_0_x86_64.whl", hash = "sha256:2132418bf8dd124a427ca9e6a1daf9ee1a87185344c95119ceae868b99466da1", size = 6789644, upload-time = "2026-10-10T20:04:37.258Z" }, { url = "https://files.pythonhosted.org/packages/b3/02/5dad269b02166965a7b4ca14adaddd75dbee0de42435bfecf561b84ba5a6/numpy-2.5.4-cp315-cp315-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:325518d4245b9e331387702aa58c2ce1dc4cdcbb41dfb4ccd5dcbc7e08db1266", size = 15704353, upload-time = "2026-10-10T20:04:39.616Z" }, { url = "https://files.pythonhosted.org/packages/93/3a/01360c8036822ed9f7aa32189a77d1476567ec1e8e1383522389e4faac45/numpy-2.5.4-cp315-cp315-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:56733449d2544178beaa4545cee357370440cf056c197f9c7bfb19dbfdd0e86d", size = 16718648, upload-time = "2026-10-10T20:04:42.383Z" }, { url = "https://files.pythonhosted.org/packages/7d/5c/b863a2c093c4d6f21a597fcaf24ead0835c09ab16a8312d5a5a8868af683/numpy-2.5.4-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:5ec3753760c1a6d8bb91200666e545c3a9728e6269dfb5d6ce02340996698aa3", size = 17059053, upload-time = "2026-10-10T20:04:44.976Z" }, { url = "https://files.pythonhosted.org/packages/0a/60/ced4f57f9a1258a0af74f17cb0b0c2700b5c67cd6678823c803b263e4df3/numpy-2.5.4-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:b1185012870173de7ae33d370bd45b1cf5baee747ea4b97036b65f4e93016877", size = 18477406, upload-time = "2026-10-10T20:04:47.863Z" }, { url = "https://files.pythonhosted.org/packages/f9/bd/0ef22dafaafcc7d4bb3ca26b8d2afbd55dedad8eaba99a8c864e1997456f/numpy-2.5.4-cp315-cp315-win32.whl", hash = "sha256:298eca75243f2cbbfdb460560b9fb2a1792a33cf2ab4286efd43d92e8d3df508", size = 6185133, upload-time = "2026-10-10T20:04:50.467Z" }, { url = "https://files.pythonhosted.org/packages/50/bc/d2651b155ecc608a77e6f4d15495c11f14f19bb98f8bf0c5b0d38f86dda1/numpy-2.5.4-cp315-cp315-win_amd64.whl", hash = "sha256:332f3378fe077dd850e677ec01bdcc4f22368fb5d50ef10b2c79230b1bf5a592", size = 12703085, upload-time = "2026-10-10T20:04:52.63Z" }, { url = "https://files.pythonhosted.org/packages/dc/d2/45e404f8abb26fb9eda12b94012936873e827b1be76f2ee7890be128312e/numpy-2.5.4-cp315-cp315-win_arm64.whl", hash = "sha256:d4cccbbc78717966f764cd3af4fb70276fa01fc7a2688af11c78901fa5c04f05", size = 10801451, upload-time = "2026-10-10T20:04:55.677Z" }, { url = "https://files.pythonhosted.org/packages/c6/c3/2ae14e09cfdb67dc187a342e15308a21c15bf4d2071f8079e6aee5fe56dc/numpy-2.5.4-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:950ea81d57ef070665581b6e1b5f6a029306423cd1739c5b95fe78aa30db6b9d", size = 17097121, upload-time = "2026-10-10T20:04:58.403Z" }, { url = "https://files.pythonhosted.org/packages/f5/cf/305ae624ef8a039414317224abe9ec9c2fe7ea3c2e1cf204d43ff6b2ffb9/numpy-2.5.4-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:c05ede731b03fb1b7591faca9389ade3267d2bddf1ad8882bb3f2cc5e101694f", size = 12135439, upload-time = "2026-10-10T20:05:01.65Z" }, { url = "https://files.pythonhosted.org/packages/a9/a8/f75c63813aef95827bb2c0d13b12803016853056e8792c280058cdbfe783/numpy-2.5.4-cp315-cp315t-macosx_14_0_arm64.whl", hash = "sha256:5fbf7141bbfd63aea22f435c9062a032b9ea0082fe9845dad7f021d3f1234e71", size = 5571451, upload-time = "2026-10-10T20:05:04.135Z" }, { url = "https://files.pythonhosted.org/packages/6f/0f/f17763f983868b5c49b4101ebd7e00760bd1769478a6bb6a8de6e085bbac/numpy-2.5.4-cp315-cp315t-macosx_14_0_x86_64.whl", hash = "sha256:3573cd22564692a5b899ec344e5d5b9cc4576f2985b96f22af3564ed54f2710f", size = 6883356, upload-time = "2026-10-10T20:05:06.249Z" }, { url = "https://files.pythonhosted.org/packages/67/a7/8af04c5a79e047996cfa38854dcfbececdd0343a7c933a46fdd03ef6f5da/numpy-2.5.4-cp315-cp315t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6c109eac9cd439193678f69d70733c1108487546ca8eafc107b510ae10c1aecd", size = 15750991, upload-time = "2026-10-10T20:05:08.376Z" }, { url = "https://files.pythonhosted.org/packages/57/7a/648254290d0c504faa8f2d07aa206660c728802c781a6f3fc68ab7cb5d71/numpy-2.5.4-cp315-cp315t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:80d6ef6e8620eb2c2b4c4caad50b5935d6db3cde2d51581b55dcc79e14016d1d", size = 16757675, upload-time = "2026-10-10T20:05:11.393Z" }, { url = "https://files.pythonhosted.org/packages/b8/fe/4a8c3cdb0c70400cfe4c5bec42d3099a5673802a95064614b33e07b82aa1/numpy-2.5.4-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:77045a4b175bbf5316ec08003880804336c78f92281a1b72222b274ea85ec5ac", size = 17113846, upload-time = "2026-10-10T20:05:14.49Z" }, { url = "https://files.pythonhosted.org/packages/1b/7e/619692bb67778702c0e9eb2d468568a7573f4e269386ea61aed01ee4e557/numpy-2.5.4-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:0f02a46e49cfb6c73bdb7aea1c0d3461dbae9aba613542b65f657cd3d17b9fab", size = 18522915, upload-time = "2026-10-10T20:05:17.33Z" }, { url = "https://files.pythonhosted.org/packages/b7/b5/4da41c328788f575838f97a098fe8ca691ebc6f6fd73ad4a262ee40b184d/numpy-2.5.4-cp315-cp315t-win32.whl", hash = "sha256:ad62a416ddcf863bf44bba76fbf6b53366ab0692e294f51cae4b5fbe0d246788", size = 6335804, upload-time = "2026-10-10T20:05:19.921Z" }, { url = "https://files.pythonhosted.org/packages/98/94/6482ddfa3d312490cb9358f375bf2ad56427dbea8769187158e94d653753/numpy-2.5.4-cp315-cp315t-win_amd64.whl", hash = "sha256:38f47be9f74ab870d2633b5456ae519c43758a8d1fd05342f0ce4ecc034396ee", size = 12890095, upload-time = "2026-10-10T20:05:21.875Z" }, { url = "https://files.pythonhosted.org/packages/48/7f/c2d1b436b6e7cfebac140c2579a298344b85f2991a2ce5c3615cefb29400/numpy-2.5.4-cp315-cp315t-win_arm64.whl", hash = "sha256:7a14a461d9340f1b46b8648578aed9cdb8b3b018a8fac6c1dde2c9192a01a87f", size = 10883718, upload-time = "2026-10-10T20:05:28.547Z" }, ] [[package]] name = "nvidia-cublas" version = "13.1.1.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nvidia-cuda-nvrtc" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/a7/a1/0bd24ee8c8d03adac032fd2909426a00c88f8c57961b1277ded97f91119f/nvidia_cublas-13.1.1.3-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:b7a210458267ac818974c53038fbec2e969d5c99f305ab15c72522fa9f001dd5", size = 542848918, upload-time = "2026-04-08T18:46:22.985Z" }, { url = "https://files.pythonhosted.org/packages/3b/cd/154ca20c38269e05eff77c1464e6c1da89f50a6390b565e9d82e06bc11e1/nvidia_cublas-13.1.1.3-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:37936a16db8fe4ac1f065c2139360608a543a09275cb1a1af612e08cfa065436", size = 423138758, upload-time = "2026-04-08T18:46:58.655Z" }, ] [[package]] name = "nvidia-cuda-cupti" version = "13.0.85" source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/2a/2a/80353b103fc20ce05ef51e928daed4b6015db4aaa9162ed0997090fe2250/nvidia_cuda_cupti-13.0.85-py3-none-manylinux_2_25_aarch64.whl", hash = "sha256:796bd679890ee55fb14a94629b698b6db54bcfd833d391d5e94017dd9d7d3151", size = 10310827, upload-time = "2025-09-04T08:26:42.012Z" }, { url = "https://files.pythonhosted.org/packages/33/6d/737d164b4837a9bbd202f5ae3078975f0525a55730fe871d8ed4e3b952b0/nvidia_cuda_cupti-13.0.85-py3-none-manylinux_2_25_x86_64.whl", hash = "sha256:4eb01c08e859bf924d222250d2e8f8b8ff6d3db4721288cf35d14252a4d933c8", size = 10715597, upload-time = "2025-09-04T08:26:51.312Z" }, ] [[package]] name = "nvidia-cuda-nvrtc" version = "13.0.88" source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/c3/68/483a78f5e8f31b08fb1bb671559968c0ca3a065ac7acabfc7cee55214fd6/nvidia_cuda_nvrtc-13.0.88-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:ad9b6d2ead2435f11cbb6868809d2adeeee302e9bb94bcf0539c7a40d80e8575", size = 90215200, upload-time = "2025-09-04T08:28:44.204Z" }, { url = "https://files.pythonhosted.org/packages/b7/dc/6bb80850e0b7edd6588d560758f17e0550893a1feaf436807d64d2da040f/nvidia_cuda_nvrtc-13.0.88-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d27f20a0ca67a4bb34268a5e951033496c5b74870b868bacd046b1b8e0c3267b", size = 43015449, upload-time = "2025-09-04T08:28:20.239Z" }, ] [[package]] name = "nvidia-cuda-runtime" version = "13.0.96" source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/87/4f/17d7b9b8e285199c58ce28e31b5c5bbaa4d8271af06a89b6405258245de2/nvidia_cuda_runtime-13.0.96-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ef9bcbe90493a2b9d810e43d249adb3d02e98dd30200d86607d8d02687c43f55", size = 2261060, upload-time = "2025-10-09T08:55:15.78Z" }, { url = "https://files.pythonhosted.org/packages/2e/24/d1558f3b68b1d26e706813b1d10aa1d785e4698c425af8db8edc3dced472/nvidia_cuda_runtime-13.0.96-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7f82250d7782aa23b6cfe765ecc7db554bd3c2870c43f3d1821f1d18aebf0548", size = 2243632, upload-time = "2025-10-09T08:55:36.117Z" }, ] [[package]] name = "nvidia-cudnn-cu13" version = "9.24.0.43" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nvidia-cublas" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/ca/30/7c257e3d5cb4fecb147b93895c66e29c93f8e76d74b45bb418ff0587c4ec/nvidia_cudnn_cu13-9.24.0.43-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:a6812a554a1ff0413e9c52b84c26c050380649ab9615f9c16bded368ce9f421f", size = 650976863, upload-time = "2026-07-02T16:23:39.248Z" }, { url = "https://files.pythonhosted.org/packages/5c/ba/791cffd048fe5b044e620df55267e3e95c0e6e07d50b41e377c03dfc910f/nvidia_cudnn_cu13-9.24.0.43-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:71f181cd810e90f9b6023b01186fe82d13d65f0ec098581ee201d39fad769e4b", size = 553099438, upload-time = "2026-07-02T16:27:42.58Z" }, ] [[package]] name = "nvidia-cufft" version = "12.0.0.61" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nvidia-nvjitlink" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/8b/ae/f417a75c0259e85c1d2f83ca4e960289a5f814ed0cea74d18c353d3e989d/nvidia_cufft-12.0.0.61-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2708c852ef8cd89d1d2068bdbece0aa188813a0c934db3779b9b1faa8442e5f5", size = 214053554, upload-time = "2025-09-04T08:31:38.196Z" }, { url = "https://files.pythonhosted.org/packages/a8/2f/7b57e29836ea8714f81e9898409196f47d772d5ddedddf1592eadb8ab743/nvidia_cufft-12.0.0.61-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6c44f692dce8fd5ffd3e3df134b6cdb9c2f72d99cf40b62c32dde45eea9ddad3", size = 214085489, upload-time = "2025-09-04T08:31:56.044Z" }, ] [[package]] name = "nvidia-cufile" version = "1.15.1.6" source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/3f/70/4f193de89a48b71714e74602ee14d04e4019ad36a5a9f20c425776e72cd6/nvidia_cufile-1.15.1.6-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:08a3ecefae5a01c7f5117351c64f17c7c62efa5fffdbe24fc7d298da19cd0b44", size = 1223672, upload-time = "2025-09-04T08:32:22.779Z" }, { url = "https://files.pythonhosted.org/packages/ab/73/cc4a14c9813a8a0d509417cf5f4bdaba76e924d58beb9864f5a7baceefbf/nvidia_cufile-1.15.1.6-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:bdc0deedc61f548bddf7733bdc216456c2fdb101d020e1ab4b88d232d5e2f6d1", size = 1136992, upload-time = "2025-09-04T08:32:14.119Z" }, ] [[package]] name = "nvidia-curand" version = "10.4.0.35" source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/1e/72/7c2ae24fb6b63a32e6ae5d241cc65263ea18d08802aaae087d9f013335a2/nvidia_curand-10.4.0.35-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:133df5a7509c3e292aaa2b477afd0194f06ce4ea24d714d616ff36439cee349a", size = 61962106, upload-time = "2025-08-04T10:21:41.128Z" }, { url = "https://files.pythonhosted.org/packages/a5/9f/be0a41ca4a4917abf5cb9ae0daff1a6060cc5de950aec0396de9f3b52bc5/nvidia_curand-10.4.0.35-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:1aee33a5da6e1db083fe2b90082def8915f30f3248d5896bcec36a579d941bfc", size = 59544258, upload-time = "2025-08-04T10:22:03.992Z" }, ] [[package]] name = "nvidia-cusolver" version = "12.0.4.66" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nvidia-cublas" }, { name = "nvidia-cusparse" }, { name = "nvidia-nvjitlink" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/c8/c3/b30c9e935fc01e3da443ec0116ed1b2a009bb867f5324d3f2d7e533e776b/nvidia_cusolver-12.0.4.66-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:02c2457eaa9e39de20f880f4bd8820e6a1cfb9f9a34f820eb12a155aa5bc92d2", size = 223467760, upload-time = "2025-09-04T08:33:04.222Z" }, { url = "https://files.pythonhosted.org/packages/5f/67/cba3777620cdacb99102da4042883709c41c709f4b6323c10781a9c3aa34/nvidia_cusolver-12.0.4.66-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:0a759da5dea5c0ea10fd307de75cdeb59e7ea4fcb8add0924859b944babf1112", size = 200941980, upload-time = "2025-09-04T08:33:22.767Z" }, ] [[package]] name = "nvidia-cusparse" version = "12.6.3.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nvidia-nvjitlink" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/f8/94/5c26f33738ae35276672f12615a64bd008ed5be6d1ebcb23579285d960a9/nvidia_cusparse-12.6.3.3-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:80bcc4662f23f1054ee334a15c72b8940402975e0eab63178fc7e670aa59472c", size = 162155568, upload-time = "2025-09-04T08:33:42.864Z" }, { url = "https://files.pythonhosted.org/packages/fa/18/623c77619c31d62efd55302939756966f3ecc8d724a14dab2b75f1508850/nvidia_cusparse-12.6.3.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2b3c89c88d01ee0e477cb7f82ef60a11a4bcd57b6b87c33f789350b59759360b", size = 145942937, upload-time = "2025-09-04T08:33:58.029Z" }, ] [[package]] name = "nvidia-cusparselt-cu13" version = "0.8.1" source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/46/e1/cdc1797eadf82d3a9a575a19b33fdc871a97edbec42c00b5b5e914f4aff4/nvidia_cusparselt_cu13-0.8.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:4dca476c50bf4780d46cd0bfbd82e2bc10a08e4fef7950917ce8d7578d22a23f", size = 221051344, upload-time = "2025-09-05T18:49:51.289Z" }, { url = "https://files.pythonhosted.org/packages/34/7d/2661f2fb3ac4302f3a246f5fc030213ac60c1fe0bce84f9783dbd831dbb7/nvidia_cusparselt_cu13-0.8.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:786ce87568c303fadb5afcc7102d454cd3040d75f6f8626f5db460d1871f4dd0", size = 170148586, upload-time = "2025-09-05T18:50:50.248Z" }, ] [[package]] name = "nvidia-nccl-cu13" version = "2.30.7" source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/d1/21/a73174c6157101bdf1ffc22b517f76ff0082613989dd9bc8f43e8034caac/nvidia_nccl_cu13-2.30.7-py3-none-manylinux_2_18_aarch64.whl", hash = "sha256:ca786ffa5a647c75d4d1f5cc72a6c4f537947e2ba8823d7c8aaf768e7a7b9f77", size = 215983881, upload-time = "2026-06-09T03:23:15.633Z" }, { url = "https://files.pythonhosted.org/packages/3f/34/c500f90c7ae641b8e0f98965b36b8a7ac79cc8b296e8d251fe3eb592ee54/nvidia_nccl_cu13-2.30.7-py3-none-manylinux_2_18_x86_64.whl", hash = "sha256:cefa7fdb9710efd0f39c5f1be1d61ff6fc9a996c451265bd7fbdcf9455ed4b50", size = 215965170, upload-time = "2026-06-09T03:23:39.73Z" }, ] [[package]] name = "nvidia-nvjitlink" version = "13.4.92" source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/1d/6b/eef7a9e32872b8f41e145bf10cddc9af26e153c338852811fe9a9baddf9e/nvidia_nvjitlink-13.4.92-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:e0391f24ed94ec879b84e3da4d4ec320c879aff681f2c7a638462f7199284323", size = 42452378, upload-time = "2026-09-16T20:45:29.042Z" }, { url = "https://files.pythonhosted.org/packages/1f/a8/1cbd4014898af8b419e69b0d7dbc63da2121ee92d92b47d59f4fe9075349/nvidia_nvjitlink-13.4.92-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:25f74fad0d654271c921ac4dca614bd6258bc21791242fc7b2289dad7ae9c099", size = 40420120, upload-time = "2026-09-16T20:45:19.163Z" }, ] [[package]] name = "nvidia-nvshmem-cu13" version = "3.4.5" source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/dc/0f/05cc9c720236dcd2db9c1ab97fff629e96821be2e63103569da0c9b72f19/nvidia_nvshmem_cu13-3.4.5-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6dc2a197f38e5d0376ad52cd1a2a3617d3cdc150fd5966f4aee9bcebb1d68fe9", size = 60215947, upload-time = "2025-09-06T00:32:20.022Z" }, { url = "https://files.pythonhosted.org/packages/3c/35/a9bf80a609e74e3b000fef598933235c908fcefcef9026042b8e6dfde2a9/nvidia_nvshmem_cu13-3.4.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:290f0a2ee94c9f3687a02502f3b9299a9f9fe826e6d0287ee18482e78d495b80", size = 60412546, upload-time = "2025-09-06T00:32:41.564Z" }, ] [[package]] name = "nvidia-nvtx" version = "13.0.85" source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/c2/f3/d86c845465a2723ad7e1e5c36dcd75ddb82898b3f53be47ebd429fb2fa5d/nvidia_nvtx-13.0.85-py3-none-manylinux1_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4936d1d6780fbe68db454f5e72a42ff64d1fd6397df9f363ae786930fd5c1cd4", size = 148047, upload-time = "2025-09-04T08:29:01.761Z" }, { url = "https://files.pythonhosted.org/packages/a8/64/3708a90d1ebe202ffdeb7185f878a3c84d15c2b2c31858da2ce0583e2def/nvidia_nvtx-13.0.85-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cb7780edb6b14107373c835bf8b72e7a178bac7367e23da7acb108f973f157a6", size = 148878, upload-time = "2025-09-04T08:28:53.627Z" }, ] [[package]] name = "orjson" version = "3.13.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f2/72/380b97dc45bd162d23afe5194721ef678d9eac7cfaa549fe2873f7f0a518/orjson-3.13.0.tar.gz", hash = "sha256:d1de5eb04485110c5da4c657e49168995d55e076b1ce60f1a042e254f4186c4f", size = 2732604, upload-time = "2026-10-07T14:09:25.719Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ce/a3/0be3b115907fea61ed340639fb0e1562cd18969bad5b3f486f808197aaff/orjson-3.13.0-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:948bad47f2e2e43527f14248364a0e5dee26dd3184691010ec4a1ebeb0fd6771", size = 223146, upload-time = "2026-10-07T14:08:06.474Z" }, { url = "https://files.pythonhosted.org/packages/9e/f7/665935edb16163f8b764182e29a30cf056947a66893ed032191e5f01eb3d/orjson-3.13.0-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:1807c2fa49d393c7ee95fd1ef1b39cbb24aa3ccd81f30b84503ba59407666960", size = 123546, upload-time = "2026-10-07T14:08:08.324Z" }, { url = "https://files.pythonhosted.org/packages/67/ec/e7cde480c0e212594d17ba2b2bd210c002052e9147fc1a1aeafaabe722fb/orjson-3.13.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:637dbca1fccffe83780e806fbc0f17427c0c59bf822528eb0acc8f0aa9f19acb", size = 113290, upload-time = "2026-10-07T14:08:09.816Z" }, { url = "https://files.pythonhosted.org/packages/36/59/4455fb11a297af73611dfc437f0f89456220227ed1cb1544a5a0ee9d6c03/orjson-3.13.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:554948becd1110123ef9f6a6e1310fd92b2d07d2cbac6dbf65df3de75702e736", size = 130342, upload-time = "2026-10-07T14:08:11.253Z" }, { url = "https://files.pythonhosted.org/packages/ca/80/0eec5fbde2e52407646b4cb3118f63175bdcee1e2390c2759dc96e0bc62a/orjson-3.13.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9d9a101bd8dbfad112170f009cd155e52bb8c936468821a0d03cbb96c0e426", size = 129138, upload-time = "2026-10-07T14:08:12.814Z" }, { url = "https://files.pythonhosted.org/packages/cd/cc/c0874f13819ae346d69ca00d074d464710b494abd4442bdebf75ac404a98/orjson-3.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89bcf2d4bc6c9a7e1763c8cf534f38712e66b76a0fefda7fb7785462f0d635e4", size = 130518, upload-time = "2026-10-07T14:08:14.392Z" }, { url = "https://files.pythonhosted.org/packages/25/ab/140dd9adff84bf64b862c4fcfe2d055af6014d5ba03a075f95c9addb2ec7/orjson-3.13.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a79cdc4934fe81f593072c94e13da3095e9d41c2deef8f6ff2901794ca1c5042", size = 134924, upload-time = "2026-10-07T14:08:16.09Z" }, { url = "https://files.pythonhosted.org/packages/08/0a/e8f6deb032b1d98a39043cf99b863d8b9e842e2ffc2d2067d2e2a88c18e4/orjson-3.13.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:50a5202ba388b3850ba24437951727d3aa6d79a21964a30ae8dc6a059a5fd34c", size = 126704, upload-time = "2026-10-07T14:08:17.439Z" }, { url = "https://files.pythonhosted.org/packages/af/cf/be64b99ff75f7983488390d4ef5df72115119770eed295691c0a715d492a/orjson-3.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:a0377d6962fa431c93ecd78fdea771bb62ec545b24ee0c5d4e32acf2260af259", size = 121287, upload-time = "2026-10-07T14:08:18.843Z" }, { url = "https://files.pythonhosted.org/packages/ca/ab/1b8ca186baf3420f12db1f2819fcc5f2cae69e4cf051168501726a64c0fa/orjson-3.13.0-cp311-cp311-win_arm64.whl", hash = "sha256:1d84820b2ec4ac975cba482214032de5b0dbdd17046170c98e642ef9c4a4ee4b", size = 126314, upload-time = "2026-10-07T14:08:20.452Z" }, { url = "https://files.pythonhosted.org/packages/98/17/ed65f84ed5ed6a1e06eb628611b4172e7480fc4ad92594856751a6363cac/orjson-3.13.0-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:fb8644dc6d705e1269ed2842bf4dbe2b4e50d670de503bf79d5cef3a5148a4c7", size = 223063, upload-time = "2026-10-07T14:08:21.979Z" }, { url = "https://files.pythonhosted.org/packages/6f/4d/9332eb96d2e379384be0f211f543835eebc81f460c9403b84abe1294c431/orjson-3.13.0-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:6ff2a2c67f35202f7d823753d38ad371a9b7fc297567cdfff4420e763cb9f6f8", size = 123364, upload-time = "2026-10-07T14:08:24.026Z" }, { url = "https://files.pythonhosted.org/packages/b4/06/558456b7da27e974a8c9ea09117b07119f6fa131cd62b8b9ecad9eea94e1/orjson-3.13.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:65c4e0e106ccc7265b488385659117a6805c37d042f737558ecd68aa0c67ad8f", size = 113199, upload-time = "2026-10-07T14:08:25.476Z" }, { url = "https://files.pythonhosted.org/packages/b7/f2/1187a9c09965620348262ec0f406868f6d7c234b2e9b5ee51020bdde5748/orjson-3.13.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:fbbad6b9b1da43f25c1f5b20cd5a268e028a2fc95d5a8d1ade6059973bc71584", size = 130329, upload-time = "2026-10-07T14:08:26.877Z" }, { url = "https://files.pythonhosted.org/packages/46/07/5d1a151bc11600434fe799e73abfc6a4d463d02e149a20e47c59d3a985ae/orjson-3.13.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae1d895cf7bbfd50ef34bb63bb727b14514f259f3e3f8dd010783bd38e864c6e", size = 129072, upload-time = "2026-10-07T14:08:28.355Z" }, { url = "https://files.pythonhosted.org/packages/ea/8c/bb07c368abbf4021c4cd01c12edb526e00090f7f750ff1b88da6e6b6c7a6/orjson-3.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bceadfd314bd238f584fc229a4bbaf0e573597e7a026dec5429fbf29fd66c641", size = 130612, upload-time = "2026-10-07T14:08:30.041Z" }, { url = "https://files.pythonhosted.org/packages/d2/8d/4b66d19619ed344ac000ffea7c006477d0061d580646e736ef0e203759e8/orjson-3.13.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b74c30e56346aad067937d766846ee74c231d1d18aad3f324e9b9261de3b2d5e", size = 134632, upload-time = "2026-10-07T14:08:31.474Z" }, { url = "https://files.pythonhosted.org/packages/ea/88/f8221f6593e37eb26ec4706e185b9ac6f38ff0c8f7bad5459844031ffd2d/orjson-3.13.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4329c19b8a25693f60a77b867c9d2a3ab637b20e36f5b7bea7f5acb492b44b15", size = 126807, upload-time = "2026-10-07T14:08:32.914Z" }, { url = "https://files.pythonhosted.org/packages/58/9d/a1ca7321eeafd7d72e174cdc388cc96301f41516d863e7b1f64f0a1735be/orjson-3.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:b571236d8393edcd3236e07423f762bfcf571f852aad667a3bce9e7b755e0790", size = 121538, upload-time = "2026-10-07T14:08:34.325Z" }, { url = "https://files.pythonhosted.org/packages/d0/a0/1f19b4779c910104370932fceb9ed436b47ac077f297db74008062525c04/orjson-3.13.0-cp312-cp312-win_arm64.whl", hash = "sha256:8594956a75223f657e1e68c568c0eeb3dd145f02cd6b78a47fd9a8095dbc4eae", size = 126259, upload-time = "2026-10-07T14:08:35.765Z" }, { url = "https://files.pythonhosted.org/packages/a9/56/f8ad2546150168858c16915c452b00eecb79597597524d1ad6ae14ad4eab/orjson-3.13.0-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:64e8f345048d988c8b68d3882e5d41028fca1219a9939b32e4a77be34c8ae8e3", size = 222892, upload-time = "2026-10-07T14:08:37.495Z" }, { url = "https://files.pythonhosted.org/packages/1f/19/725d23160b2471a3f27026c55bb79af34687652d8be8f5f583cee5dcd42f/orjson-3.13.0-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:ded33b972cffdaf4ca0ac917338ab61d2bb10d68987dbcae641c313fbfdbf499", size = 123319, upload-time = "2026-10-07T14:08:38.989Z" }, { url = "https://files.pythonhosted.org/packages/ac/08/e5d81a00b22c73dfcb60d80da3bd92d5a7684346593536565f184dbae3c9/orjson-3.13.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:45e34deb3437509f4ec9888dd9ee5dc426cfe21be10f1eb4ea3a9e4d33034f9e", size = 113196, upload-time = "2026-10-07T14:08:40.383Z" }, { url = "https://files.pythonhosted.org/packages/67/78/fda6117c69a43e470b1e9dff38dd8c5f0bc6fd8a47e4d4561ab023039335/orjson-3.13.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:9825b954155b345c4759f24e5f8d652b9aec2261bb5d4e1abe06bba0a1200535", size = 130245, upload-time = "2026-10-07T14:08:41.878Z" }, { url = "https://files.pythonhosted.org/packages/6d/31/d0cfebd456defb234414795ae7599696bf124843dfe077d0c9ece0c93554/orjson-3.13.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b081f0e7b600ff24513dec4ca75507fa05e904607847e386e8310d5b7b96b6c7", size = 128981, upload-time = "2026-10-07T14:08:43.716Z" }, { url = "https://files.pythonhosted.org/packages/45/46/f8d83189ff5b7b2ff225a58c5908618cc4e86afe09e65d17a30ac68c9da4/orjson-3.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbed5f4c4b88d94bcc36115f4c3bb3aa25da1563a5c3328aa3acebce2b083040", size = 130370, upload-time = "2026-10-07T14:08:45.132Z" }, { url = "https://files.pythonhosted.org/packages/e6/6a/d6344c305003ea826b3fa0482645a897a3cd6d477ed74e1fe15d3322cb23/orjson-3.13.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e9b61676116f755126b90e740a9cff36b91562f47ec330056cc88cc3b9f02f4b", size = 134595, upload-time = "2026-10-07T14:08:46.63Z" }, { url = "https://files.pythonhosted.org/packages/9f/52/d73fa44f88d53e02d10de1cf77c16ed13204ff5bca47e1692da6b406619c/orjson-3.13.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3ef75ed7e81dae34a3649f82df52cd85f9ac839a7d6ec78ab355b33b3b27ef7f", size = 126513, upload-time = "2026-10-07T14:08:48.111Z" }, { url = "https://files.pythonhosted.org/packages/fb/f8/bcfc50b4ab851c4f9c0ee62f52bf3b28f0bcd0d9fe08e0ad98d4585148db/orjson-3.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:4ee06e53b998c71ce3eb93b86222912fdd9dcced685ac64d4525d36fac338ea4", size = 121371, upload-time = "2026-10-07T14:08:49.549Z" }, { url = "https://files.pythonhosted.org/packages/7b/7a/d6927845712ec2b1e89263cd12d7203531db185dbad67f914226f2fca156/orjson-3.13.0-cp313-cp313-win_arm64.whl", hash = "sha256:89efecad02515df7f318d0613b5dfd6d2a1acd323a2b8294712789a715945525", size = 126134, upload-time = "2026-10-07T14:08:51.118Z" }, { url = "https://files.pythonhosted.org/packages/f0/10/98b5a3cdc086abf78d8cd20bb0cba124485d4b6a745722197bd209d967a5/orjson-3.13.0-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a7bfc7db961c7d96cb75889dc6a1e4ae1e91d87ee61da564f582bd742b8dfeef", size = 222889, upload-time = "2026-10-07T14:08:52.673Z" }, { url = "https://files.pythonhosted.org/packages/22/7c/7728c5280ab5202f4891ff4b0b96e2e1dbd5520dfee53edf083c54409a64/orjson-3.13.0-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:91d933e668ff0ffe164d7c2daec36beba6d1ce7fadb71538fbe142a71f8a1e6e", size = 123312, upload-time = "2026-10-07T14:08:54.25Z" }, { url = "https://files.pythonhosted.org/packages/a9/a5/d9a44321e6f66c0f64b45be587395f87ad94cb447bce7d92286f6b97d46a/orjson-3.13.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:6c8bfe728b81b0fd58a3c7f3f9c5a113f87f2992c9948e0f28707aafd737c0bc", size = 113146, upload-time = "2026-10-07T14:08:55.803Z" }, { url = "https://files.pythonhosted.org/packages/80/da/d95c80d413f288feb471e16d82e5c1512d2439728e3bac917d058c31f098/orjson-3.13.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:e8e05549f3b30f9d8a8e28c5aba11cc2a4b90b90961ec685ca58444b0815fc09", size = 130348, upload-time = "2026-10-07T14:08:57.31Z" }, { url = "https://files.pythonhosted.org/packages/04/0f/36fdfb32ad1852997bac00e3ce52c7888d8a1094ba9dcdcbb22fcc6b953a/orjson-3.13.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c749ab3ac30b5ab1ffb7677f8b92eacfdfdc5260210baa398f845bc3714c05d8", size = 128971, upload-time = "2026-10-07T14:08:58.843Z" }, { url = "https://files.pythonhosted.org/packages/25/de/a82acf93bdcca0c79ccff25ef0c6868d24ccbc2e72f21fae39c8cabce4f1/orjson-3.13.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58a9619d88f8818d9ab6b39d70d203789457ba13c1ed5d274f33ce9ae7e81a36", size = 130359, upload-time = "2026-10-07T14:09:00.412Z" }, { url = "https://files.pythonhosted.org/packages/71/ca/2bc4f7697cb9f6897bf61aca11803df096a5d971bf69ef5538b243bb1fa8/orjson-3.13.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2715c4808d1571029ed18fd07a82140bf3ba7def0dc89f8d015c416e3649bf87", size = 134583, upload-time = "2026-10-07T14:09:02.047Z" }, { url = "https://files.pythonhosted.org/packages/23/b3/12b1af9b87ff9fa0aaf4e5724c87672b30bb5de76f275f7fac64e8219c1b/orjson-3.13.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:08bf722f923d2100bc5e5a5dcf72c656db557049c1bea26582fdd5dd9d5395a1", size = 126500, upload-time = "2026-10-07T14:09:03.863Z" }, { url = "https://files.pythonhosted.org/packages/ad/ea/cf257fc8a7f4b18f5677c22b3a9673a1b51d4b7161f25177ed389b76560e/orjson-3.13.0-cp314-cp314-win_amd64.whl", hash = "sha256:6adcaa85d79977659a448b4123a88eb33511a11ed2db243535ad7ea88a6668e0", size = 121378, upload-time = "2026-10-07T14:09:05.375Z" }, { url = "https://files.pythonhosted.org/packages/05/0a/9f4643f849e9918eab11983b83928af3aac14bedb04002e28e885ee1936f/orjson-3.13.0-cp314-cp314-win_arm64.whl", hash = "sha256:83705c12b4afde10c62a5dd3fe6fdb21b7900bd0dcd5af1c85612ae94d0ee590", size = 126123, upload-time = "2026-10-07T14:09:07.085Z" }, { url = "https://files.pythonhosted.org/packages/8c/15/d265f2b556c0c7c0b30ea830316d6e5af5b85dde08f234a1ebed60fab386/orjson-3.13.0-cp315-cp315-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:5ef4d4157392a0439b74f7e49e5636b4ea43d9616bd0884effc0195fffcaa2d5", size = 223305, upload-time = "2026-10-07T14:09:08.84Z" }, { url = "https://files.pythonhosted.org/packages/0c/97/781be8b80a33b8171b3f5acea941af47182c8b4b5827c2b7c3fea706f21c/orjson-3.13.0-cp315-cp315-macosx_15_0_arm64.whl", hash = "sha256:84d87e322e1674408f85adea63f11aa19201eba082755aec20ebc217f493bbd2", size = 123515, upload-time = "2026-10-07T14:09:10.792Z" }, { url = "https://files.pythonhosted.org/packages/20/68/011bb98fa7da7b430b363db1bb7ef9160c438fc5c43e7468fb593c220037/orjson-3.13.0-cp315-cp315-manylinux_2_39_aarch64.whl", hash = "sha256:8c2ac5c09b017c484df1b4c68b2cf250b4e8ba08204cb58e7cd6cbbc71a9c902", size = 129222, upload-time = "2026-10-07T14:09:12.542Z" }, { url = "https://files.pythonhosted.org/packages/86/7f/d96fa2aedaaec14c095ea9cd48d2158fdf33c0f4fd6e7a598d899d536b03/orjson-3.13.0-cp315-cp315-manylinux_2_39_armv7l.whl", hash = "sha256:51d11525bc3ca736fa97ce4e4c7da9999cc00bf261522bede43b4e7531bd7965", size = 113152, upload-time = "2026-10-07T14:09:14.059Z" }, { url = "https://files.pythonhosted.org/packages/e9/2d/ee77aa685c54bd920a1f0e2936986b46269adb0d72bf5098c2c694dbeb36/orjson-3.13.0-cp315-cp315-manylinux_2_39_i686.whl", hash = "sha256:ac81530647c3423107cf61c3481e91f57134e9ddfb6ef83f5150ccbdcbc3a3ee", size = 130749, upload-time = "2026-10-07T14:09:15.835Z" }, { url = "https://files.pythonhosted.org/packages/48/eb/3411fbfdad61b3f3af22343b5af7ed5c8a1679e35f442e8f1b229b33040e/orjson-3.13.0-cp315-cp315-manylinux_2_39_x86_64.whl", hash = "sha256:0526a3456db67b264c6d661b5f090077f326b6cd074d0ef53a72763595dec5d7", size = 130471, upload-time = "2026-10-07T14:09:17.463Z" }, { url = "https://files.pythonhosted.org/packages/87/71/abdc2b8c70b8d85a6cb22f404da0f52d7d712f9d49cda039a0cb1adcb973/orjson-3.13.0-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:dd61e64802d51d1e4f16531c64536354fc3bc67932dc0cff254044f72bf0f187", size = 134793, upload-time = "2026-10-07T14:09:19.084Z" }, { url = "https://files.pythonhosted.org/packages/0a/2e/1c13552d8b0241083116de02b2f284ee38501ef06ebfb79893f741538168/orjson-3.13.0-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:c5e3ccaac3106e8fa6e2f2f6962449d7c757d7b067e41b395a19d6f0d6cec892", size = 126711, upload-time = "2026-10-07T14:09:20.645Z" }, { url = "https://files.pythonhosted.org/packages/85/f8/d4ece953a519d064cf690adaa68cd389d5b64fd261726334841b32978d6a/orjson-3.13.0-cp315-cp315-win_amd64.whl", hash = "sha256:7804dd1d6161da0e53b284c2aebf20f23e78eaac617300803e1467d1828d987f", size = 121496, upload-time = "2026-10-07T14:09:22.359Z" }, { url = "https://files.pythonhosted.org/packages/70/cf/f691388c4a9bc4af7dcc1648c4b40845869908b517d7c0009d005c7d1fa1/orjson-3.13.0-cp315-cp315-win_arm64.whl", hash = "sha256:f5c05a8fee59309f537590a1ff12d3c1009c485e96a50a9ac60dd085c09d0fc0", size = 126260, upload-time = "2026-10-07T14:09:23.928Z" }, ] [[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 = "pandas" version = "3.0.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, { name = "numpy", version = "2.5.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, { name = "python-dateutil" }, { name = "tzdata", marker = "sys_platform == 'emscripten' or sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e2/17/d7b106e05bfa642e8694451e7d3d759c6a241c5386a5d962e4f66c047e06/pandas-3.0.6.tar.gz", hash = "sha256:66b07ef7315a31bfe1089cd3d71a7de781c9dca986762d0b4fe7c0ef17465d10", size = 4667686, upload-time = "2026-09-17T23:23:18.345Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/7d/48/88e8d250d28efa8163294f6809a71683c7ee67f63ac7c33021c0503b3547/pandas-3.0.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:085e3786ae6b2e82b406266bce36690f72b9dc1421903ba9296b2981a9fcf586", size = 10391798, upload-time = "2026-09-17T23:20:20.96Z" }, { url = "https://files.pythonhosted.org/packages/55/a6/39db5d41f3eb5d7846626312cb30e0cea48e988fc47a3725698bc931ad3c/pandas-3.0.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d7564d86a94c2eb8ab290b07f63ddaae5c032fa53897c29a2ff2197d43aee8af", size = 10023718, upload-time = "2026-09-17T23:20:25.094Z" }, { url = "https://files.pythonhosted.org/packages/54/b7/707e966129f77ee8a39d41a41bbd989b790b3fef581c6e26b821315cba6b/pandas-3.0.6-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e7c0afdcaf6661d795fcefc2f647ddd1136f62cdc153fba177c685d97a87808", size = 10612800, upload-time = "2026-09-17T23:20:27.99Z" }, { url = "https://files.pythonhosted.org/packages/63/be/dfb6cc9329d0bbe76dadda8a1113d026bb996ec76c509221368dc68349f4/pandas-3.0.6-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:47121f9571503f724c9b93e297ab6254ac99c77adf5e9ed085ea419fd585c258", size = 11108900, upload-time = "2026-09-17T23:20:30.65Z" }, { url = "https://files.pythonhosted.org/packages/1a/6f/3d58f15bbe972f3d7bfa13ee06d731785a76fe8d232c92b2655a8de14127/pandas-3.0.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:994a79608263fe1c14cc48ffa7300e2b834b7d1cb406ffe96a08828cb0cdd79b", size = 11630226, upload-time = "2026-09-17T23:20:33.582Z" }, { url = "https://files.pythonhosted.org/packages/58/54/9b494de4a3dd92fc6eb19187db1b21afb50fdc21962f32ea1aca9f270cb2/pandas-3.0.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a3a22e07fe75347eaacc75b0e85297947af4fba6b4aae23916bd8b6828d0bba3", size = 12146942, upload-time = "2026-09-17T23:20:36.792Z" }, { url = "https://files.pythonhosted.org/packages/d3/dc/d2df02854aec5d47659acfb2be352eecc691845b2f86e99c84f1010a8671/pandas-3.0.6-cp311-cp311-win_amd64.whl", hash = "sha256:2e5fa32ff162dfdbc280157d664f44d23049ae414725af9676df339c501d82cd", size = 9859246, upload-time = "2026-09-17T23:20:43.976Z" }, { url = "https://files.pythonhosted.org/packages/79/1e/2a30df0d7dede5c195300a1820b0bc21cea3aa24e4c8b6c4431565ecc79a/pandas-3.0.6-cp311-cp311-win_arm64.whl", hash = "sha256:5e75072773c1b2f7cb63faa3a6f562aede11f3976f68ed34cb538bc091a28171", size = 9106923, upload-time = "2026-09-17T23:20:46.611Z" }, { url = "https://files.pythonhosted.org/packages/77/4c/597d588c055d4373cff19cbbc32d4dd046c7be8fadee957585b5ba9e5b24/pandas-3.0.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7dac2d65e9087e8e7b5a45fe15c4920911a221df061ab629943ce016489145c7", size = 10397411, upload-time = "2026-09-17T23:20:49.465Z" }, { url = "https://files.pythonhosted.org/packages/18/8f/48907c7c707b61a8e5018c32e1a3f70623209bfb59020a2f6196159d3aa7/pandas-3.0.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9dab635a549e58a053c7b0fa054dc0bd7be22f0ed9a720f4a85d5fb993276172", size = 10051279, upload-time = "2026-09-17T23:20:52.409Z" }, { url = "https://files.pythonhosted.org/packages/67/fa/613d867c3d9554a61bafdec6f79565c8a3e73235feb52cc4a72ad2e0fa6a/pandas-3.0.6-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e3dccb584123b399c07562ac4d62543e90ede49ddf8ce3c13ffc64cbe828c281", size = 10303429, upload-time = "2026-09-17T23:20:55.597Z" }, { url = "https://files.pythonhosted.org/packages/cb/67/0c0f18e38d7f2d2af8c24b3315bc4046e73bbdd4a5540405506671ad0c0d/pandas-3.0.6-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0704044b676496b8350e023b09f174a26772456c974a2b11c36bebb558c9490d", size = 10788193, upload-time = "2026-09-17T23:20:58.617Z" }, { url = "https://files.pythonhosted.org/packages/39/53/1b57f3162501fe36687e4870e1b918a6458ca7386b173af75663ace95857/pandas-3.0.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e7c1905ef02c3d6d43d9dbd5b6ccb4da4870a0b0c821bbc103fbdb6f3ad2707b", size = 11323501, upload-time = "2026-09-17T23:21:01.911Z" }, { url = "https://files.pythonhosted.org/packages/f2/d2/b1182e8d39100369d7f13f4a125a3fb6b096fef112c46d0566c25781ff68/pandas-3.0.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:569e114072b24fc4970c12e2b4bab252671668a40b324318903380cab0254c0c", size = 11838173, upload-time = "2026-09-17T23:21:04.85Z" }, { url = "https://files.pythonhosted.org/packages/c7/33/5b717af24d2f27995e51e0875a269dddd373045216e34cf62e3aa764eaa1/pandas-3.0.6-cp312-cp312-pyemscripten_2024_0_wasm32.whl", hash = "sha256:2a8fc94be2ee5f1d86f97aacd8cc566f81680b6498e76f3007421bb5d98151bf", size = 7118499, upload-time = "2026-09-17T23:21:07.661Z" }, { url = "https://files.pythonhosted.org/packages/bd/2a/14b3b17cd75cef4a1ee1af4234eb41cc1afe4103b98c2d80e8916abfd42b/pandas-3.0.6-cp312-cp312-win_amd64.whl", hash = "sha256:3ef908d28590b3f42d7070e7ad8f9b34b442b260b7f3c1afb57e0040c58cdb1b", size = 9661439, upload-time = "2026-09-17T23:21:10.959Z" }, { url = "https://files.pythonhosted.org/packages/3b/11/3d580a604a1e35d69f6676847bd12db7d14344bc677b717f4413e79c5d0d/pandas-3.0.6-cp312-cp312-win_arm64.whl", hash = "sha256:f4e7c52eb108d752e7592268108fd3e98efd76d83a3125cdd06c621c2e44359b", size = 8959806, upload-time = "2026-09-17T23:21:13.851Z" }, { url = "https://files.pythonhosted.org/packages/8e/1c/143605a1f6443ad50ebda78a31e5a3a10147fec2590e931584aaa5ff0a09/pandas-3.0.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9ae8073aed8e21d1a7fe263dcdc6840743549722a6738198a0a46000fa9476f2", size = 10418900, upload-time = "2026-09-17T23:21:16.594Z" }, { url = "https://files.pythonhosted.org/packages/ea/ca/87f8548f73d452aab35e4a90f8b39ae303295e0f2ef0b4055c44d6b3f1be/pandas-3.0.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:60d81f9e1799b36f3739e7fff44d1fbb2e8fd5a271b3863e03de9715fccda0fa", size = 10064785, upload-time = "2026-09-17T23:21:19.677Z" }, { url = "https://files.pythonhosted.org/packages/43/1a/d951442e5607c6e3b2462eff8f420797d428aa74b87c6ecfe4f48553626e/pandas-3.0.6-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:097090508a1dd335013d39106fc10b20f4fd4a171638e47b77d55798ed9dab6c", size = 10245290, upload-time = "2026-09-17T23:21:22.797Z" }, { url = "https://files.pythonhosted.org/packages/50/fa/96d50e1e6cd0b08b5e2b7c838f65ae644940f75a124063380b5ef73b6866/pandas-3.0.6-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1e92d9fa834c7d877130027cddc0cad8dcff97c1f6cca26bd6310f847228b658", size = 10757657, upload-time = "2026-09-17T23:21:25.673Z" }, { url = "https://files.pythonhosted.org/packages/7b/12/f82d13a2cb703e1a8acee7e01fdc2b898d9cd0c00f07d1dfce63af43e350/pandas-3.0.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b27c8d890e4aa2171437ae2a39de1d215e674158e4865c4023a8b31c932513b2", size = 11249114, upload-time = "2026-09-17T23:21:28.898Z" }, { url = "https://files.pythonhosted.org/packages/1a/ce/8aef2e561a2f2c8b38c913c67373c65ba6748174e763d27c80271b24bd17/pandas-3.0.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f8029ec0f1f89e4f985929ce1f6626dabf3140d61a4e9c1215afdab34eaf9a5d", size = 11820511, upload-time = "2026-09-17T23:21:32.11Z" }, { url = "https://files.pythonhosted.org/packages/c0/bd/63cb67e6903ef6d9c2871916dbcbc09d254da0fe8b870cf62e16b21945f2/pandas-3.0.6-cp313-cp313-win_amd64.whl", hash = "sha256:f3ce8a6968045481e91a3990e797e348ce13db45ee164a7095bbc824e26c09dd", size = 9638092, upload-time = "2026-09-17T23:21:34.883Z" }, { url = "https://files.pythonhosted.org/packages/75/2e/e7b35b712edb068d382ddc8b2bea8a04974100515ba2daa22b478b265842/pandas-3.0.6-cp313-cp313-win_arm64.whl", hash = "sha256:cc39303913e2ea129915670de5d1c9fbd647f543bb72e5543bac8baa94e9e42f", size = 8952032, upload-time = "2026-09-17T23:21:37.729Z" }, { url = "https://files.pythonhosted.org/packages/75/55/1a8875395b05ccd572cbca0b9255dcd2db6e6508e632a558c1a6884b39ad/pandas-3.0.6-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:ee913a91669056c1de1a6b733fbfeab711de9e54e3bee2dfa5fe79d9457247d1", size = 10492213, upload-time = "2026-09-17T23:21:40.746Z" }, { url = "https://files.pythonhosted.org/packages/35/61/47ae13476995cc8a40cd609e93e7cf11f273d8692925c2903cb6d38aa0d1/pandas-3.0.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ff51a4459ed036e93d1eb1bb5e6e7b28685d3cb6b7c12b91c05b31024e234729", size = 10156618, upload-time = "2026-09-17T23:21:44.142Z" }, { url = "https://files.pythonhosted.org/packages/bc/f2/cc5f2adb8d6e86a85d9fb5128f8cf205a61189336f70d1f7faf0d1b53ec9/pandas-3.0.6-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:654aae059295dbba6ecd2328ca12712a2cf1676214c8699f1c29213f7ccf9c34", size = 10375479, upload-time = "2026-09-17T23:21:47.159Z" }, { url = "https://files.pythonhosted.org/packages/ca/ba/ffdcb19be4ff6bfe7d969e7cef2c567c633df5a3a1cc1053394ad053bca8/pandas-3.0.6-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62f51d7f651c8054c5e82a69265c98082e795d1442df7ca6edc3a545d61214b1", size = 10783244, upload-time = "2026-09-17T23:21:50.367Z" }, { url = "https://files.pythonhosted.org/packages/77/5b/e150075b2c6eb69fae896f2d9239bc6ed07db97735971d53d66de6553460/pandas-3.0.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:22172a92e7ee678ec0140c7af4fc9366b55413834a1cd86af78b3caa0b0574de", size = 11382223, upload-time = "2026-09-17T23:21:53.355Z" }, { url = "https://files.pythonhosted.org/packages/d6/8a/b441c587dc7355bf6e1f68a91b4f76a6c29740f0c23be3acc5d4ebbeea6d/pandas-3.0.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:583be68728a31d0d750d5b8d9e00f02b153df0d4655f858bde93cb84cfc4227c", size = 11854881, upload-time = "2026-09-17T23:21:56.342Z" }, { url = "https://files.pythonhosted.org/packages/b7/e9/f43410fada510b43fec09993c08f552086c3d247d3ee801a678f3cb10ea5/pandas-3.0.6-cp314-cp314-win_amd64.whl", hash = "sha256:77ccbe5057aece6fc172b9b77f19c04335af6882bc2e10c8f3ee4e6bfb3da553", size = 9791672, upload-time = "2026-09-17T23:21:59.332Z" }, { url = "https://files.pythonhosted.org/packages/8b/9e/db14c059c21f9baa1907d436f8bf30e0c76c6288225c5e8b79a08ba8b2c5/pandas-3.0.6-cp314-cp314-win_arm64.whl", hash = "sha256:fb625f426b375bcc96e3a04c5d5d266cd7be6ae5d6866e0e703382ab5164068c", size = 9121246, upload-time = "2026-09-17T23:22:02.123Z" }, { url = "https://files.pythonhosted.org/packages/67/ba/bad0f8dac020ab38a8637fddab01a57a82da7a496a6e6f19590aad53ab62/pandas-3.0.6-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:9e492cd4bdba6778de4fe0df7f4590c012161ebcf9902dce01b01dc683105514", size = 10920612, upload-time = "2026-09-17T23:22:05.404Z" }, { url = "https://files.pythonhosted.org/packages/c4/a9/b500982e9aac6d52a58da4ad3f11e14168a315b06906b3f397c427878065/pandas-3.0.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d7dcd21238cbb4828ff148481ba01cac8946dc5121457b5aeba28636f8f99a60", size = 10570213, upload-time = "2026-09-17T23:22:08.44Z" }, { url = "https://files.pythonhosted.org/packages/4b/fa/e6ecd0073c98be8f840ac3125b955272835d7d9fd69f5944383b164deb5e/pandas-3.0.6-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6ff482fa91fa2bafd92e8fe66ce3645c851824310f295c1f0a2f96e928fc4541", size = 10252356, upload-time = "2026-09-17T23:22:11.302Z" }, { url = "https://files.pythonhosted.org/packages/04/f5/001e230a7a7803590d9275a1a3f7e1bb605e3a495cfe5e8d3a532090621b/pandas-3.0.6-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:db7ec631f26223beee8e5c9e0b8f23c24d8197bbd1d982421d4e3188bea51965", size = 10655952, upload-time = "2026-09-17T23:22:14.283Z" }, { url = "https://files.pythonhosted.org/packages/ca/ab/bab587148a3852c96aae26c4b5f9e04ce2221801ad94e166b4fbf969ede0/pandas-3.0.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bd75ed0c840f709fc2ae26ddd9534ac77ca1a48ac0cce521a74acaa85f3340a7", size = 11274177, upload-time = "2026-09-17T23:22:17.352Z" }, { url = "https://files.pythonhosted.org/packages/f3/32/74b48d87df2b80892d713c149abfe36d5db4de41b4eccb042a2bc07dafc1/pandas-3.0.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ef738d71d1059245b6bb03e312be06d8b3821326a83486c1ad03b9aba3710e44", size = 11719041, upload-time = "2026-09-17T23:22:20.227Z" }, { url = "https://files.pythonhosted.org/packages/f6/c6/d64b72d64d7eb0fad9fe424d34138e45dee70ddbea1360dcd0adf30e28f6/pandas-3.0.6-cp314-cp314t-win_amd64.whl", hash = "sha256:429d9df32731ab01383ed98f2baa7a60368090d1a94fc06019a12062510e8630", size = 10191388, upload-time = "2026-09-17T23:22:23.524Z" }, { url = "https://files.pythonhosted.org/packages/7a/30/5e5b2ccabeca73ae2b03fc82bca3eabb7466cf43737f05ac08d591665d47/pandas-3.0.6-cp314-cp314t-win_arm64.whl", hash = "sha256:a4dbd4dc65cbe645b92b8785d0f96dd7311010dc6606cf620e51b07b8788a12a", size = 9387796, upload-time = "2026-09-17T23:22:26.64Z" }, { url = "https://files.pythonhosted.org/packages/b6/77/47c5fb0be8bdd00116814c2c40d9ec42dbeb943865ef95130fe58a898226/pandas-3.0.6-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:50c44cbf5820b6b91a5f74aae04972472aefadd3cd9fbd1010409d85528bd570", size = 10483960, upload-time = "2026-09-17T23:22:30.071Z" }, { url = "https://files.pythonhosted.org/packages/09/08/a310cb2fefe6d2b4623ab2150da818d93d4e73e33b58e4d163bb74243c5a/pandas-3.0.6-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:eb6900de08ac85f93ac4948aa6b80842eba555875337b8359035ac9c43e92d34", size = 10149432, upload-time = "2026-09-17T23:22:32.818Z" }, { url = "https://files.pythonhosted.org/packages/54/36/6af478ec3a26d7754555cd62c3101c589c0931b1d85398e4fa5403910a1c/pandas-3.0.6-cp315-cp315-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e25e2e1adee99ddfada6f7206a79ae8e9c8a8861b0e3eaaba165006d3eef18e", size = 10360981, upload-time = "2026-09-17T23:22:35.621Z" }, { url = "https://files.pythonhosted.org/packages/43/20/5ece0e9cb79a6473216620db6a90546f578001c2bd857b77c444b27acad1/pandas-3.0.6-cp315-cp315-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4ff44b2cb51cbd691c91f92c4ea6c71e34003f239ebd67c2e857dc898466b49c", size = 10776585, upload-time = "2026-09-17T23:22:38.427Z" }, { url = "https://files.pythonhosted.org/packages/2f/b6/cd3038f31ade5e8d2b4e1c9549d4b31e4d598469562f47142b2ad9171c0a/pandas-3.0.6-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:5edd0a7abb0986ecce1ac81f56d99b6763f86aa6946dceb6c661224f90af5a19", size = 11385249, upload-time = "2026-09-17T23:22:41.18Z" }, { url = "https://files.pythonhosted.org/packages/0a/87/05bb3003737f80375d7311774916a24d161e2e591abe8c672aed7813defc/pandas-3.0.6-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:1bcb3e9ed29e74a7439cedff9e2aefd3ea65de84d7de9ccb6c194192541bd60e", size = 11848595, upload-time = "2026-09-17T23:22:44.207Z" }, { url = "https://files.pythonhosted.org/packages/c0/30/1c0d46acf236d19ef975e9cdd5d1e0dd54924b03f0ed8287096ad4a18152/pandas-3.0.6-cp315-cp315-win_amd64.whl", hash = "sha256:253e12cb9081b0afbac607920f6142975966bc315135e09de275fdbaa415d2de", size = 9783810, upload-time = "2026-09-17T23:22:47.097Z" }, { url = "https://files.pythonhosted.org/packages/87/03/df3304a9c2833c4810e7f1c887b04105b24731f9deef8b5d5d04522a375b/pandas-3.0.6-cp315-cp315-win_arm64.whl", hash = "sha256:97274c9adf6255bb48c620cd6959805efa7f09ea2167f0e0ae006a448cd2fca7", size = 9116820, upload-time = "2026-09-17T23:22:50.149Z" }, { url = "https://files.pythonhosted.org/packages/47/25/d5f6cce5efa17c38e4f752a875b4a26d66cfadd529cb8c81672f0376d6a6/pandas-3.0.6-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:265f562fdd1079f69f3de96dd425c3405224038c0af4f920c54bd240ee2c4640", size = 10894614, upload-time = "2026-09-17T23:22:53.223Z" }, { url = "https://files.pythonhosted.org/packages/ea/8b/e1876bfdc1df06bafc022d33202b5663bd86c81df2a6140aacafd0344669/pandas-3.0.6-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:c6e4aae3e9bea26c6c9a20d88d96c86ec4a99b4db5fd516bcb4e829ab2c0ee36", size = 10546973, upload-time = "2026-09-17T23:22:56.155Z" }, { url = "https://files.pythonhosted.org/packages/e9/27/e0a27a5a5c27f7db66657b44def9e93121fd0ad4f0808355b9898fcbf204/pandas-3.0.6-cp315-cp315t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a77a1a44e4d88f1c6a2a64d3eb12efec8420875722e14279800b173a7c7c2804", size = 10239717, upload-time = "2026-09-17T23:22:59.603Z" }, { url = "https://files.pythonhosted.org/packages/d5/4f/4eadb7d86a921c1e8bc70916cfe601ed667c4169118d17d69958611c21f8/pandas-3.0.6-cp315-cp315t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:86fa853a12e0b70927e2b1ee00d56d2224ec9cbb4b9d58348b5ad52d2f21150e", size = 10641275, upload-time = "2026-09-17T23:23:02.81Z" }, { url = "https://files.pythonhosted.org/packages/c7/d1/eba72e9d905e84e79aefeefdcc6bc1abe15d9077973566643f4211636966/pandas-3.0.6-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:c826e9babb7790142c399f58599d8de679bea059d7b39c5b6efa2096fac37266", size = 11262919, upload-time = "2026-09-17T23:23:06.038Z" }, { url = "https://files.pythonhosted.org/packages/9d/8a/1c5bd2642b450e374b6191189f47c49538fe41f82348a66de6f647e6ab59/pandas-3.0.6-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:8fe77b408d82e2615674dfed62533b95e18a03610573877422aada4f625d4947", size = 11709148, upload-time = "2026-09-17T23:23:09.082Z" }, { url = "https://files.pythonhosted.org/packages/73/3d/1b142bd0d0f1326a5d98c91c955b923cd1e06b5eecb428cd9d8817fa01c0/pandas-3.0.6-cp315-cp315t-win_amd64.whl", hash = "sha256:83e91d15738d7783c050197cef2f2cf82fc6353dae9865aa87ed1fa16aa4d55a", size = 10161518, upload-time = "2026-09-17T23:23:12.365Z" }, { url = "https://files.pythonhosted.org/packages/0b/a3/6419c14da2adc1f09a6a183b8f91d7494d325b287f4ca984ac04f663638a/pandas-3.0.6-cp315-cp315t-win_arm64.whl", hash = "sha256:963ca21199097a84c7827c4678b04e30833084fbf8ef44fde3fa7180a29f8fa0", size = 9364529, upload-time = "2026-09-17T23:23:15.274Z" }, ] [[package]] name = "parso" version = "0.8.7" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/30/4b/90c937815137d43ce71ba043cd3566221e9df6b9c805f24b5d138c9d40a7/parso-0.8.7.tar.gz", hash = "sha256:eaaac4c9fdd5e9e8852dc778d2d7405897ec510f2a298071453e5e3a07914bb1", size = 401824, upload-time = "2026-05-01T23:13:02.138Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/99/5d/8268b644392ee874ee82a635cd0df1773de230bde356c38de28e298392cc/parso-0.8.7-py2.py3-none-any.whl", hash = "sha256:a8926eb2a1b915486941fdbd31e86a4baf88fe8c210f25f2f35ecec5b574ca1c", size = 107025, upload-time = "2026-05-01T23:12:58.867Z" }, ] [[package]] name = "pathspec" version = "1.1.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", size = 135180, upload-time = "2026-04-27T01:46:08.907Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" }, ] [[package]] name = "pexpect" version = "4.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ptyprocess" }, ] sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, ] [[package]] name = "pint" version = "0.25.3" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version < '3.12' and sys_platform == 'win32'", "python_full_version < '3.12' and sys_platform == 'emscripten'", "python_full_version < '3.12' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] dependencies = [ { name = "flexcache" }, { name = "flexparser" }, { name = "platformdirs" }, { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/52/9d/b1379cdbd33a49d17d627bc24e2b63cca06a1c5343b38072d2889499e82e/pint-0.25.3.tar.gz", hash = "sha256:f8f5df6cf65314d74da1ade1bf96f8e3e4d0c41b51577ac53c49e7d44ca5acee", size = 255106, upload-time = "2026-03-19T21:57:08.72Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/1b/dd/a9fe6a0a09512da23951c68bf36466aeecd89def3183dc095edbc807ddc5/pint-0.25.3-py3-none-any.whl", hash = "sha256:27eb25143bd5de9fcc4d5a4b484f16faf6b4615aa93ece6b3373a8c1a3c1b97d", size = 307488, upload-time = "2026-03-19T21:57:07.022Z" }, ] [[package]] name = "pint" version = "0.26.2" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.15' and sys_platform == 'win32'", "python_full_version >= '3.15' and sys_platform == 'emscripten'", "python_full_version >= '3.15' and sys_platform != 'emscripten' and sys_platform != 'win32'", "python_full_version == '3.14.*' and sys_platform == 'win32'", "python_full_version == '3.14.*' and sys_platform == 'emscripten'", "python_full_version == '3.14.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", "python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'win32'", "python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'emscripten'", "python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] dependencies = [ { name = "flexcache" }, { name = "flexparser" }, { name = "platformdirs" }, { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d3/b0/cef9c8913ebe959d97b2d57b1fc2a77a4291c4f2bd4dc3fe4d3313c938ea/pint-0.26.2.tar.gz", hash = "sha256:391e5d2fc01fdb121c113b8eb47386688575542c1f5144c465ff318bf5133573", size = 295834, upload-time = "2026-10-19T19:49:31.845Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/b7/d5/01ea71591a29e88926582e3ca7ed32f8b933e9ebc99187a7ab100587242d/pint-0.26.2-py3-none-any.whl", hash = "sha256:c94124cdb19baa1a84bb65c8bb9a620a9636b9b9cd80f32f30ad7ff795ea2eb8", size = 351853, upload-time = "2026-10-19T19:49:29.966Z" }, ] [[package]] name = "platformdirs" version = "4.13.5" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/58/e6/d0abbb256b44e6a05748c6942511ff67db8dbb068de0c35b24bf1b395b09/platformdirs-4.13.5.tar.gz", hash = "sha256:05831adf87d392760f4b5c3a0a95579ab5a10b18b9b9bd43680dcb47544788a0", size = 62362, upload-time = "2026-10-19T01:02:11.778Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/6c/8a/1d8cb3842909dc193a73835adedf412e32e18f8ffd59f43983949622fe6f/platformdirs-4.13.5-py3-none-any.whl", hash = "sha256:53d3ec4280b815c1e0b02edad7f9ee8fda1ba9c0865dd9c2e6e63849ce82fc1e", size = 32779, upload-time = "2026-10-19T01:02:10.17Z" }, ] [[package]] name = "pluggy" version = "1.7.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/bf/db/7fc19e6f2dc92a966727031389fc2e08b558f0f25eb7403c1119ad4713cd/pluggy-1.7.0.tar.gz", hash = "sha256:d1eaa46ebb595891b860ab086b4d09c8588af65ebd4361b8e8f4bb8920b90ba8", size = 123304, upload-time = "2026-10-15T09:50:58.343Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/40/9e/2b38731e0fc536806f16490e1a12d7f0dc2a1235aa8cc07bcc75416a7daa/pluggy-1.7.0-py3-none-any.whl", hash = "sha256:7dd7b0d8832ba3cb632c306926ded123429211b83641b35dc5c41ad2d34f9bec", size = 27082, upload-time = "2026-10-15T09:50:56.808Z" }, ] [[package]] name = "pre-commit" version = "4.7.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cfgv" }, { name = "identify" }, { name = "nodeenv" }, { name = "pyyaml" }, { name = "virtualenv" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3a/c3/6965c2690ddce885ec75121572d065a5b94c5a5d8d3e657927ecda9fd715/pre_commit-4.7.0.tar.gz", hash = "sha256:1f3deee12b914c8fa184bd2b5953391c2e4f36763e403d4a23dc9983fa7c6e86", size = 198120, upload-time = "2026-10-12T20:45:40.32Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/eb/83/ce0a196e4f7b20b11ce3aa1fc72fb973f64b7628d51c1b8aebad37fb7f81/pre_commit-4.7.0-py2.py3-none-any.whl", hash = "sha256:2e229038ad3656081b70c27913157e4b636ef306f643f024a8a8e3f0f7b2f877", size = 226261, upload-time = "2026-10-12T20:45:38.858Z" }, ] [[package]] name = "prompt-toolkit" version = "3.0.53" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "wcwidth" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7d/ea/39b988c938f75cb75d7045b5c69f8bfed47ee2152c8837fb403de29d6fb8/prompt_toolkit-3.0.53.tar.gz", hash = "sha256:9ec8a0ad96d5c56148b3f914aa79c1564c3fde5d2e6b876e7bc327e353cf8fa6", size = 435492, upload-time = "2026-07-26T20:56:14.758Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl", hash = "sha256:01c0891d7f9237d5e339f7d3e42cdae80b7534abb1c7c0e3352efba6231492f2", size = 392288, upload-time = "2026-07-26T20:56:12.512Z" }, ] [[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/81/69/ef179ab5ca24f32acc1dac0c247fd6a13b501fd5534dbae0e05a1c48b66d/psutil-7.2.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:eed63d3b4d62449571547b60578c5b2c4bcccc5387148db46e0c2313dad0ee00", size = 130664, upload-time = "2026-01-28T18:15:09.469Z" }, { url = "https://files.pythonhosted.org/packages/7b/64/665248b557a236d3fa9efc378d60d95ef56dd0a490c2cd37dafc7660d4a9/psutil-7.2.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7b6d09433a10592ce39b13d7be5a54fbac1d1228ed29abc880fb23df7cb694c9", size = 131087, upload-time = "2026-01-28T18:15:11.724Z" }, { url = "https://files.pythonhosted.org/packages/d5/2e/e6782744700d6759ebce3043dcfa661fb61e2fb752b91cdeae9af12c2178/psutil-7.2.2-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fa4ecf83bcdf6e6c8f4449aff98eefb5d0604bf88cb883d7da3d8d2d909546a", size = 182383, upload-time = "2026-01-28T18:15:13.445Z" }, { url = "https://files.pythonhosted.org/packages/57/49/0a41cefd10cb7505cdc04dab3eacf24c0c2cb158a998b8c7b1d27ee2c1f5/psutil-7.2.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e452c464a02e7dc7822a05d25db4cde564444a67e58539a00f929c51eddda0cf", size = 185210, upload-time = "2026-01-28T18:15:16.002Z" }, { url = "https://files.pythonhosted.org/packages/dd/2c/ff9bfb544f283ba5f83ba725a3c5fec6d6b10b8f27ac1dc641c473dc390d/psutil-7.2.2-cp314-cp314t-win_amd64.whl", hash = "sha256:c7663d4e37f13e884d13994247449e9f8f574bc4655d509c3b95e9ec9e2b9dc1", size = 141228, upload-time = "2026-01-28T18:15:18.385Z" }, { url = "https://files.pythonhosted.org/packages/f2/fc/f8d9c31db14fcec13748d373e668bc3bed94d9077dbc17fb0eebc073233c/psutil-7.2.2-cp314-cp314t-win_arm64.whl", hash = "sha256:11fe5a4f613759764e79c65cf11ebdf26e33d6dd34336f8a337aa2996d71c841", size = 136284, upload-time = "2026-01-28T18:15:19.912Z" }, { 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 = "ptyprocess" version = "0.7.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" }, ] [[package]] name = "pure-eval" version = "0.2.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/da/9f/abfd2959e9261dd5217ca8551d4de211ca6ab26fe9b72cf44731ff6c4442/pure_eval-0.2.4.tar.gz", hash = "sha256:260c2774686e651b79f8b8e7fc9d80b3599ea6a66334b47d5f4abb69fc2c0ea1", size = 20563, upload-time = "2026-09-10T21:41:22.836Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/6d/18/83376915176eb058cb86470eb7396388a13350b09a8f233a79303bbcbc5b/pure_eval-0.2.4-py3-none-any.whl", hash = "sha256:96cae060a313cfaad51bb761278bfb0e62dc0248d9315a81173752dc546cd37a", size = 11893, upload-time = "2026-09-10T21:41:21.532Z" }, ] [[package]] name = "py-cpuinfo2" version = "10.1.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/dc/97/a8b1ddada14c8280a047c0746f95cb05d94a31b1a331cea22bcdc2b2a82d/py_cpuinfo2-10.1.1.tar.gz", hash = "sha256:7861133863663f16e06eca63b12904ef100b5760415e92372dac0162799a4771", size = 100840, upload-time = "2026-03-25T21:49:40.797Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/23/0a/ba69d2dde1ae12ef1d389ea5a216384c5ff6ef7a1e7a48d1e9b6686f6790/py_cpuinfo2-10.1.1-py3-none-any.whl", hash = "sha256:adc53396bfb206e6498d078ec2ab407f85799ecd819584ac36a8f80a2d4d762d", size = 23791, upload-time = "2026-03-25T21:49:39.574Z" }, ] [[package]] name = "pydantic" version = "2.14.1" 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/7c/0b/8e10b2e693af8ec54346a14caf36221334775975a747c9ceaa3f8371d96d/pydantic-2.14.1.tar.gz", hash = "sha256:94f478203dd03404682a1ada216965651dd74b1d2d5ffd62e00e0837caab5c26", size = 900362, upload-time = "2026-10-11T18:37:55.396Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/35/ea/a56b9fe5066f3537b7882f77e9c5dfb26d8c2eefdaed9b5fc73d57b4dc22/pydantic-2.14.1-py3-none-any.whl", hash = "sha256:9195d967ec791692a04438115466764fb8b9a27b31f14a760437694f40d6b454", size = 488106, upload-time = "2026-10-11T18:37:53.437Z" }, ] [[package]] name = "pydantic-core" version = "2.50.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a6/24/af4ec4be49fbc810f35b0bdcacc3d433b56bbfa469fd3bfd4ae116cd9bf1/pydantic_core-2.50.1.tar.gz", hash = "sha256:e50d7b94baac6c7d09927fa5ca5800a0c7ee5015c7fcff65beb3a1931b5a6e09", size = 513515, upload-time = "2026-10-11T18:35:44.82Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/45/1b/ca81811da3d2aea724fb3c4ba6b83f50ab8f210576306ccd601973142d35/pydantic_core-2.50.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:c531166c42ea7bdfecc8c50049581f05dd1993b09cc7c52bb36a14e96deaec7d", size = 2152145, upload-time = "2026-10-11T18:31:58.046Z" }, { url = "https://files.pythonhosted.org/packages/59/20/938ef7e0541af0a314e2f9d63848dbd1656ba2ebfe5ca0469f7ebee00d5e/pydantic_core-2.50.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b6d0c2183008c188e19f4906d426b293bdc4f67ab17df8e180fe16cda208fa71", size = 2045761, upload-time = "2026-10-11T18:31:59.35Z" }, { url = "https://files.pythonhosted.org/packages/2f/4b/456497fe2affa18f49b226e89bde31e8a204751ee343dd9beaac5438123e/pydantic_core-2.50.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94be440c03fede26969a5ce75468e0e6a9927a1b46d9b679ee8adc1b057b0350", size = 2049557, upload-time = "2026-10-11T18:32:01.121Z" }, { url = "https://files.pythonhosted.org/packages/a5/9d/cd5dfe13928f55e236dff3a1bee06721d318ca6c955d9ca993b0a5d09f39/pydantic_core-2.50.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:36c426eac0af8d1529ff8467e612b933346caec1fdc0d774f78f67a1a11e16c1", size = 2188153, upload-time = "2026-10-11T18:32:02.442Z" }, { url = "https://files.pythonhosted.org/packages/fb/8d/d0b25bc484f8d9136ea76ece69e0b2d24ab370cc2e7bbd1b79e61723b763/pydantic_core-2.50.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:028e2f212273d4a39b1ec1e0de8166b1165a65fc0f1111452a9d94fc7c625c63", size = 2388308, upload-time = "2026-10-11T18:32:03.767Z" }, { url = "https://files.pythonhosted.org/packages/c5/64/6513cac7c9f78492abafa01d57a69de1d246bf3085fd7b0330bf14b025b3/pydantic_core-2.50.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e6f0cc1bb9900dc558960894adeb30b0c083366fc1d69b856209fb2ca5c36fe5", size = 2431187, upload-time = "2026-10-11T18:32:05.159Z" }, { url = "https://files.pythonhosted.org/packages/ed/60/7f2ae89c37e69a3dc0da9ff57b0388c285542c688d05f36767770429de85/pydantic_core-2.50.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8812592c85d0edf423f10eadcef42716d71e8219085ad9e85b775057b7306133", size = 2157623, upload-time = "2026-10-11T18:32:06.616Z" }, { url = "https://files.pythonhosted.org/packages/87/02/e3a71373b85a7973099b9a229a4302c7792262717e0b4997e41c01f7dd16/pydantic_core-2.50.1-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:bbce99252ba3167b2b6277f1829d5bf4b43b754524bddf7f944707c3db7d2253", size = 2254539, upload-time = "2026-10-11T18:32:07.968Z" }, { url = "https://files.pythonhosted.org/packages/3f/d5/5b620aaf40dc631d911565b64d49d3fa8422027c046a7a96dc4e4921ae98/pydantic_core-2.50.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:476f6ed8e43cd1e0b460920e23571700872b284e77331cb30c4faf459cf48a4b", size = 2267344, upload-time = "2026-10-11T18:32:09.399Z" }, { url = "https://files.pythonhosted.org/packages/e0/48/f46baf4580d8a56ca4782aa65842e16d3cf39736b29fcce8e9c0521b3422/pydantic_core-2.50.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:2cbd1b75b09e976ed0d6b6ca297675632ca35df86130088457cdc60ef36970ae", size = 2300877, upload-time = "2026-10-11T18:32:10.903Z" }, { url = "https://files.pythonhosted.org/packages/2b/9d/e7d28505e6092c1fe075838a4f793ccbe6dd676e44ab16175815ee06cfe0/pydantic_core-2.50.1-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:5958c72adb417c39b12ac87525ac60b0d73315fcdc59e21f44ee4a5e2512c9ef", size = 2464270, upload-time = "2026-10-11T18:32:12.329Z" }, { url = "https://files.pythonhosted.org/packages/22/b1/3bf63b82efd93ebc9968f9c12fc46037a28bcb452c88e4688f33e5ff7dca/pydantic_core-2.50.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d8f9e8a6c4ab04b78d61f78627370d834eb004b2869dcb28cfffa647b4ea1980", size = 2478653, upload-time = "2026-10-11T18:32:13.735Z" }, { url = "https://files.pythonhosted.org/packages/28/17/26d1e4b9c2ba6a92b7dc75bbcb99ef44456b7e3af1bced868403667ea7d3/pydantic_core-2.50.1-cp311-cp311-win32.whl", hash = "sha256:4be846f55c9477f5f3ddde8f2ce941137e16862a56d018ed885d422bb6ae02f2", size = 2120246, upload-time = "2026-10-11T18:32:15.591Z" }, { url = "https://files.pythonhosted.org/packages/24/65/3e875e7991eaecd4d70686293ff0d8a99aa8f93dc295e6a21c3d702912fb/pydantic_core-2.50.1-cp311-cp311-win_amd64.whl", hash = "sha256:0048b6dddc8ef4b64fccaad878bd143b0c3882ea9936279dc11d613f6b7dd1bc", size = 2176332, upload-time = "2026-10-11T18:32:17.153Z" }, { url = "https://files.pythonhosted.org/packages/ab/5c/58dbd17c61f209d91c70f549eb7a3bbec7023e89ea12dead091462d6d658/pydantic_core-2.50.1-cp311-cp311-win_arm64.whl", hash = "sha256:6a733778df2f7087ec1100ed0b41533e4f3001976e99570fa34f57c66e7f8e3e", size = 2182471, upload-time = "2026-10-11T18:32:18.49Z" }, { url = "https://files.pythonhosted.org/packages/ee/94/101b49a6c63f99586755690696eae14532772587d9e39e93f7b8d28a49da/pydantic_core-2.50.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:704075d10b74f2f3c6e15407c696d88701df35fc8953f434a431add0d0074db0", size = 2222428, upload-time = "2026-10-11T18:32:20.228Z" }, { url = "https://files.pythonhosted.org/packages/db/a3/f8b1b39349c33037c73d7a1b794c9c29d8f07d5bd2b74399c1375a529cc6/pydantic_core-2.50.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e8e1d6ce820aa23317e8209a86bd65a540973c12dc7552b48a4f6c8e9926815e", size = 2025779, upload-time = "2026-10-11T18:32:21.723Z" }, { url = "https://files.pythonhosted.org/packages/d2/2d/862a7d115305cc621358e51ba13f296e0ffdf4fbd984be9f63bc7862730b/pydantic_core-2.50.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c18db21573bd2c6489f9a544b7499f0df2853958c568e5e783536ee1f690af41", size = 2048429, upload-time = "2026-10-11T18:32:23.3Z" }, { url = "https://files.pythonhosted.org/packages/c0/7d/fed95d18bf2b5abe2d5ab2bbec4184bfc22b6805994a33ccdae8edffd25a/pydantic_core-2.50.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cb57f304525a5e3c13333b772bf9a473f36326e9c821b2e8e1b2fd36f80ae2c3", size = 2173274, upload-time = "2026-10-11T18:32:24.697Z" }, { url = "https://files.pythonhosted.org/packages/93/1e/c6f22ceac65dc3d291ff79bea0eb74cbd1de8b128f01fee48af03bcea1e1/pydantic_core-2.50.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a27c09d86600f1bf2fe3f37e1ae697faf3143931c09322cd799da94deee923b5", size = 2360403, upload-time = "2026-10-11T18:32:26.281Z" }, { url = "https://files.pythonhosted.org/packages/2c/97/190b5b6bfe4c72f265feb657913eb30749193927a5ad7b83cfa7866a25a2/pydantic_core-2.50.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:46b3301d3b5c886f77de7546e47274a5842c622ea2020b8c6524c6b66913b4a6", size = 2439799, upload-time = "2026-10-11T18:32:27.844Z" }, { url = "https://files.pythonhosted.org/packages/90/24/48cd98388e4ac2c08d0800af36d15413db15e20387f1038123a2c86cb2f6/pydantic_core-2.50.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93ba4e9d8210d941c200431a56b2c0400b131865947903937ed3ec5404307d2e", size = 2160157, upload-time = "2026-10-11T18:32:29.553Z" }, { url = "https://files.pythonhosted.org/packages/00/86/d909133d0b9979ed14c20f110f21124a0e346caf071bd66ac5af3009062b/pydantic_core-2.50.1-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:e5faeaee74a57d32b3ab3aebad2e348f06d3ba946fc5d28c1728455f00a3d13a", size = 2229523, upload-time = "2026-10-11T18:32:31.027Z" }, { url = "https://files.pythonhosted.org/packages/90/31/4b43f08131b2098e73a852fd932063385f3103b33839fd9d1abdb89e673d/pydantic_core-2.50.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a3cda0e538208e5d722bbf3698b24f19c0a7d05bc8d5f8a7f9b121ea7fa243d9", size = 2242700, upload-time = "2026-10-11T18:32:32.622Z" }, { url = "https://files.pythonhosted.org/packages/88/77/de39658569dc7a4c293d110a89629f61145e7538f00d1e4280c28debefd3/pydantic_core-2.50.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:57f51b31ff826e2859120cf4737c5a758a48d96f3e97da40ccee1796d58078ff", size = 2278452, upload-time = "2026-10-11T18:32:34.165Z" }, { url = "https://files.pythonhosted.org/packages/46/bd/1eeb9e4e791e81210ef9096f58080b32ba15b5b13c108d50aaa3f8ce9f73/pydantic_core-2.50.1-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:8daa7ee75245d43ad7d747e5c9ecc1b1d06552f72b14887e9276f787d57375f4", size = 2450098, upload-time = "2026-10-11T18:32:35.547Z" }, { url = "https://files.pythonhosted.org/packages/1c/e6/b2accfdff17e5a88d6358536702146de00f9339adaa4d5bbe1ee93cb4832/pydantic_core-2.50.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:acbf31f37c53a5ac0c34706c80b4f5107ba20b05fdd3816124bf236ef0c57dd2", size = 2476839, upload-time = "2026-10-11T18:32:37.119Z" }, { url = "https://files.pythonhosted.org/packages/3b/7e/c8a83eb5d2cd42c2e13507150fb777b1edea5a018adc9cbf2858a1d08285/pydantic_core-2.50.1-cp312-cp312-win32.whl", hash = "sha256:45b11cac094aa25725581d9304eee93c9028516b9ea80dd9e175e13a5a2c840e", size = 2101425, upload-time = "2026-10-11T18:32:38.593Z" }, { url = "https://files.pythonhosted.org/packages/c5/17/8bbd530b8659e9d963f5b16f6cb8e159f4cd174b4d6304e48969ab12dba8/pydantic_core-2.50.1-cp312-cp312-win_amd64.whl", hash = "sha256:132529c83901437ff642f585216831bf5fd7a91df66829907e155192ead62498", size = 2172522, upload-time = "2026-10-11T18:32:40.112Z" }, { url = "https://files.pythonhosted.org/packages/af/9f/a79d690b127e4e3cff143d031538ab9aa715f6b2fbeecbd07cd6f2bf9fb7/pydantic_core-2.50.1-cp312-cp312-win_arm64.whl", hash = "sha256:4e834f6a8e4ff772dcc34f58ef5504147a3ea5b0f4eeb13b0f8eb2ca75ac57f1", size = 2161366, upload-time = "2026-10-11T18:32:41.606Z" }, { url = "https://files.pythonhosted.org/packages/ae/57/0e237d7091d2cd44a35d243b7344227f90440166860469cd036afc23a04d/pydantic_core-2.50.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:d5e062c01286d861fd6a1c4ff6e063547b3e713067f2df033c0ff97ac2ca006b", size = 2222774, upload-time = "2026-10-11T18:32:43.103Z" }, { url = "https://files.pythonhosted.org/packages/f7/b9/c720e56858d4e1539503297ed37063e0c08e0f3541c41b777f6a800f75fa/pydantic_core-2.50.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0c003c3b7f49debb893d2d85ae099ac5959c9839e2f330fadb1fcdf7a6594482", size = 2024738, upload-time = "2026-10-11T18:32:44.587Z" }, { url = "https://files.pythonhosted.org/packages/4d/b8/fbfc25875219cc060e613170ff10e850c6d8924beb4910da57c2ee3ba1d2/pydantic_core-2.50.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:409e0ea40ec30d9158f33574fd758e689f6045a0f2596701828c27816ca9687d", size = 2047049, upload-time = "2026-10-11T18:32:46.164Z" }, { url = "https://files.pythonhosted.org/packages/d7/43/34210124d504c553688f2f04b48500b131237528ac545b445e0d6d30e0d5/pydantic_core-2.50.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:131059670f1d2444269b8585cb888963994871932447c08b39ac6a51fcfef658", size = 2173415, upload-time = "2026-10-11T18:32:47.722Z" }, { url = "https://files.pythonhosted.org/packages/65/cf/6e178e8fdc11da5965bef980983bf46326a42f436871dd51ba0a57f39df1/pydantic_core-2.50.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6dbcbee53bf17196a7f745aa9bf5a9603953a1e365b1f020be3207c676a3e7c4", size = 2361719, upload-time = "2026-10-11T18:32:49.217Z" }, { url = "https://files.pythonhosted.org/packages/11/14/bd5169d356aa91bf777e28ba0b281c192d286d03c2812c9c9db023a2f00e/pydantic_core-2.50.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:325c23f3e35cfbf0fe3486fa5f7260d1e45885173002d30a28ca019994124255", size = 2439803, upload-time = "2026-10-11T18:32:51.025Z" }, { url = "https://files.pythonhosted.org/packages/1c/bc/d79d000e5203ebef39af839f2ce77a777fcad6e08ad26af9a2fcd114ffc8/pydantic_core-2.50.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17e722e156d0444ecaefbe640bdb60928752bf2013e2b7a11cdb099aaae19bec", size = 2158402, upload-time = "2026-10-11T18:32:52.714Z" }, { url = "https://files.pythonhosted.org/packages/1b/a5/4902cb5fd599422c130bd3124ab31ee8b771199bd56662702eed07d3fec7/pydantic_core-2.50.1-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:aa8224f10880d9bf1b5993988ba153d42a8b4f3f4f511f93b1f09c93ff613c72", size = 2229755, upload-time = "2026-10-11T18:32:54.126Z" }, { url = "https://files.pythonhosted.org/packages/1a/f5/c1481f8669f6060d89110c9b1374173fc8767ca276b84f4870bd8acd5e3f/pydantic_core-2.50.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:41bc8237121bd8dc8d888dfd6279fc166ffc88c1f1bf3a8bf00869680533ca4c", size = 2242303, upload-time = "2026-10-11T18:32:55.641Z" }, { url = "https://files.pythonhosted.org/packages/04/f9/77fc3c7653ba9b6e42049e17e96b25388187d4a7c274ab1cb07f58ac8419/pydantic_core-2.50.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:45c6266d071c241f2a168d45bf8c54344f0effce35e7e6b73afdec11f3687568", size = 2278345, upload-time = "2026-10-11T18:32:57.38Z" }, { url = "https://files.pythonhosted.org/packages/95/9b/0579c5d12e7f2b16b27e6782427987341fcce07b0725e02ddb0b74add0c4/pydantic_core-2.50.1-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:1deeacb112d14d3f4fcb16b165f7dbaf76c70ba6e82f37ba042bdab51970a0b8", size = 2449947, upload-time = "2026-10-11T18:32:58.896Z" }, { url = "https://files.pythonhosted.org/packages/a8/ac/1b677db91eba54cc5922f4de6edc46ba45c2bd712dfdc0130382d158e214/pydantic_core-2.50.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:1c96fd793b73d1b92e65570132505498fe7b21eaef73cdf74e67e5dfba7ac9e4", size = 2476889, upload-time = "2026-10-11T18:33:00.665Z" }, { url = "https://files.pythonhosted.org/packages/4d/2a/3a9f6624ee3ea9ccba5249dde11418bb4c35780a7a92608f8768bd3fea39/pydantic_core-2.50.1-cp313-cp313-win32.whl", hash = "sha256:06ead20d39ffd6f2f6f2a8f8a6de67ff8bb1b4f14a8a30e058502514ee2ac685", size = 2101118, upload-time = "2026-10-11T18:33:02.329Z" }, { url = "https://files.pythonhosted.org/packages/2d/1f/323f78ddd9d9938aac420c1abb4e8ba799fc8bdab0acc67c0593b837c979/pydantic_core-2.50.1-cp313-cp313-win_amd64.whl", hash = "sha256:7816e98acc08119dc0f340ab167048ecc54126316330c1f0caf7c6756c88e28f", size = 2170840, upload-time = "2026-10-11T18:33:03.919Z" }, { url = "https://files.pythonhosted.org/packages/cb/09/8497c52a739ae425c3ac2f7f56414cbc711c67d374346174f40fe2062644/pydantic_core-2.50.1-cp313-cp313-win_arm64.whl", hash = "sha256:c17799a62c142d61b8a3c51752a7cbc87fe2ad4ccfab10e628a77b405075c662", size = 2161633, upload-time = "2026-10-11T18:33:05.518Z" }, { url = "https://files.pythonhosted.org/packages/49/33/28b96e81677153715e3eafb9f26663a80841e859fde282a380359b0d3fa1/pydantic_core-2.50.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:1cf41f1ae3fa155cf167a72689ad044bcc1e3c97e064123677149bdfb5dafc4a", size = 2224428, upload-time = "2026-10-11T18:33:07.153Z" }, { url = "https://files.pythonhosted.org/packages/94/40/15c06410c9b7b8da5805d27b64e09bd3f900e986728106db2689dbc51513/pydantic_core-2.50.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4df197990c15b5a37c5a277d131d9f2c67de6133f2e5dafd80d9bba4b99f46f9", size = 2023740, upload-time = "2026-10-11T18:33:08.763Z" }, { url = "https://files.pythonhosted.org/packages/a1/4e/5eb629f6efc2a27e421d789dd4bfacbb5f6d09c80c28b13d1e87d73163d5/pydantic_core-2.50.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0036473f5583e6a60e50b8b21651511564277a3f05cc5dab8cf579f552cd5f6c", size = 2049435, upload-time = "2026-10-11T18:33:10.366Z" }, { url = "https://files.pythonhosted.org/packages/ba/8e/f195aebec49ad12318876ac2368c197a7939f5d52f8e156d2238ef8a4588/pydantic_core-2.50.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:992c3514ec891fa7858099183e4d64e6bd5a5d4ff452fae29df22faa77a006bb", size = 2172975, upload-time = "2026-10-11T18:33:12.368Z" }, { url = "https://files.pythonhosted.org/packages/e0/f5/7ad9fb83010cd5ea0948409db105676ed779c4e709e2d3d89b9fe2558794/pydantic_core-2.50.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:739dc730e6be3bd5ec2f4ab5cfc7eb047cc45fc1497b3bafec74ff2ed07df597", size = 2364197, upload-time = "2026-10-11T18:33:14.244Z" }, { url = "https://files.pythonhosted.org/packages/ca/fb/bf0aab3e78301d202b82a0322ec968cd703b11fc0623fde9a28708936f62/pydantic_core-2.50.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:32fad3a91e51b6d2039c572db04a5a873260b399f6bd62c3552671fa7a4a2899", size = 2444259, upload-time = "2026-10-11T18:33:15.79Z" }, { url = "https://files.pythonhosted.org/packages/45/35/38f6d6564fae57d9b12e5676dfa947e0e7d5c46dbeaa7eb3352261d6d299/pydantic_core-2.50.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42b54c2c90ad348b5e3a85e03e715d572c1fde357ef104cdfe3b03b697a404ea", size = 2159857, upload-time = "2026-10-11T18:33:17.51Z" }, { url = "https://files.pythonhosted.org/packages/65/a0/fb0a3ca10f139dcf765b2d312d10cf0f65c57c59993229d00ad12b14ceff/pydantic_core-2.50.1-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:2df1ff41884de2bc4b307bafd7c40a691094fad2ff8e767e5b45a319257bcf4e", size = 2233954, upload-time = "2026-10-11T18:33:19.591Z" }, { url = "https://files.pythonhosted.org/packages/8c/6a/e63842252702aa4ec6e6b7178ca85e541a77459076592c23ebe2d9840b33/pydantic_core-2.50.1-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fe90228920fd8ff2be62622b6bb8a2b11acd65046d50c6b130614b5879605a20", size = 2243876, upload-time = "2026-10-11T18:33:21.393Z" }, { url = "https://files.pythonhosted.org/packages/39/25/5991cf8318b37e0dfab47b87541619a1df8501a793cba0d978846cba37a7/pydantic_core-2.50.1-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:844b869f118e22a41a091bdcedda8a71bc1b0f62c38d1a0c3211cece47e1d8fc", size = 2277908, upload-time = "2026-10-11T18:33:23.324Z" }, { url = "https://files.pythonhosted.org/packages/a7/3e/3ee8baaa6cc25a6961c69168cf9ff0f002d56f4e0d541ad6724c18fb61f3/pydantic_core-2.50.1-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:2eb75304506894a281d346220a4f7481a1b8729577c5ed2a05395991966a8396", size = 2449285, upload-time = "2026-10-11T18:33:24.942Z" }, { url = "https://files.pythonhosted.org/packages/c0/c7/acbec6deac13fe697a80c275a9b6661db62c4d323bac8a47347b1f39c7cd/pydantic_core-2.50.1-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:6b20a4bffabdad0db2927ac034ae3b8a681b1f7a0182f3e60b479ad2fde21ebb", size = 2479013, upload-time = "2026-10-11T18:33:26.925Z" }, { url = "https://files.pythonhosted.org/packages/10/08/21a3f237b264389f6219d053ee78fc1b5c2fd402c1b1cb2b6cb8b85f9834/pydantic_core-2.50.1-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:99ba9bc2b8062ea0c326a990f7f00e6530c23579de66dd246e72c4cafef950a5", size = 1484400, upload-time = "2026-10-11T18:33:28.693Z" }, { url = "https://files.pythonhosted.org/packages/09/ce/077a6d262d12ef09108377ac0717f029f420d773ace63cafd6143af75568/pydantic_core-2.50.1-cp314-cp314-win32.whl", hash = "sha256:cf356f70551d40374eaffb1aa63f1eb6d2006681cbd7a9faea173ce0f4dd7cd2", size = 2103222, upload-time = "2026-10-11T18:33:30.326Z" }, { url = "https://files.pythonhosted.org/packages/14/4c/350a2415209c43d670eb71d3c040f332c04a30583d39e311b05c7ac15762/pydantic_core-2.50.1-cp314-cp314-win_amd64.whl", hash = "sha256:d32f3acc081cc3923386d88f422cde8892335e95f034e0104bb4cf9310d9915f", size = 2171586, upload-time = "2026-10-11T18:33:32.139Z" }, { url = "https://files.pythonhosted.org/packages/bf/92/9bea6ca96580a0902fed366f064f0829e404f41889b34543279a1162b888/pydantic_core-2.50.1-cp314-cp314-win_arm64.whl", hash = "sha256:bed5163e03b98bc1fa2eb05d74c63d9c5c95d8ed6254985481640fbf5e237dea", size = 2155773, upload-time = "2026-10-11T18:33:33.896Z" }, { url = "https://files.pythonhosted.org/packages/86/8c/f121f073cf32bdd5cba7e6230b1ce0ac845b0cf43e44dd597d95af272db2/pydantic_core-2.50.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:9572c1369e9c9da2d64a7b7992c786d90ff295abc93964cfe3125e4290768070", size = 2234017, upload-time = "2026-10-11T18:33:35.588Z" }, { url = "https://files.pythonhosted.org/packages/a4/69/2bb2bcd6146cffe98d760a46c42ae71efd5151d9b2f9c9bf6619a3b32083/pydantic_core-2.50.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2005207aafe1231315718bf6ed5d064a7300fb4772754af35ee72fc68159492e", size = 2001016, upload-time = "2026-10-11T18:33:37.57Z" }, { url = "https://files.pythonhosted.org/packages/20/b3/fbf854c7d07ec114260c26e9e2071a4381740f9ae09641dbfcbdf2a18c45/pydantic_core-2.50.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64f6047f62a6c5ae08d0a6afb035667aa2d97c3d20d69762e034c5ea144d92a5", size = 2023015, upload-time = "2026-10-11T18:33:39.433Z" }, { url = "https://files.pythonhosted.org/packages/65/20/6de55b2f92cdb614b745c6e9ced639fc4fd7e1e77604825a88bdece6fcbd/pydantic_core-2.50.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1ef800dd7d85bcdadf4c3076e4c94e43939493558a3b69a1ea830c706d4617bb", size = 2192543, upload-time = "2026-10-11T18:33:41.381Z" }, { url = "https://files.pythonhosted.org/packages/0c/d9/19e91c94bd5c405945ce2f15526808aea37e162c253160de8ed7bf70b406/pydantic_core-2.50.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b0135bcdcaa0f23573f286e4cb5e0fd2962700964ed13df085b85f2b97aeab9e", size = 2388704, upload-time = "2026-10-11T18:33:43.167Z" }, { url = "https://files.pythonhosted.org/packages/b6/bc/2e24c8415eae1a25ee5a5484946a917123bad2e9d01689a759236928175a/pydantic_core-2.50.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0b3a6f334c6a2345ca15318ff894502a90012536404b37c844a976c76c846e0b", size = 2464118, upload-time = "2026-10-11T18:33:44.856Z" }, { url = "https://files.pythonhosted.org/packages/bd/1f/945b8053cb061c64e102bcaf7bfb9ed740c0bd4349f9bb978a7d4ddff4ab/pydantic_core-2.50.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06e01fbbfdb9be777b316a71b6c49efaf4a08b615d0a98d678cda3023f79d019", size = 2150142, upload-time = "2026-10-11T18:33:46.661Z" }, { url = "https://files.pythonhosted.org/packages/2b/78/96a3e50bf0d64aaae781107eb9335b7529d05a85793ed6e7241c4cd1d931/pydantic_core-2.50.1-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:a29a061fec0b4e2d714f277e70a3a18125ecff803f2fea6eade2f2e53711d112", size = 2245577, upload-time = "2026-10-11T18:33:48.574Z" }, { url = "https://files.pythonhosted.org/packages/7a/5d/a6038a0322232758a6ebfa709f4ca14a60bf5b93940cd0b345056a557da4/pydantic_core-2.50.1-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f5187624823423e1d1b82b1072ac41dc837389e18d3d0572cc19bbee46cd550a", size = 2263728, upload-time = "2026-10-11T18:33:50.527Z" }, { url = "https://files.pythonhosted.org/packages/0d/4b/76ded3333a457a9344c4f2d63f2d82d0101654b05178fa4ddfe7d3627674/pydantic_core-2.50.1-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:3e46a9eb0a0901dd6275e6b06ac3a464885ef350ec4121fe486869de8053e4bb", size = 2293630, upload-time = "2026-10-11T18:33:52.362Z" }, { url = "https://files.pythonhosted.org/packages/a9/00/9eca378335c9c1b72bc779bf6e4c2a82ce784f14ec48a0e87102c9870e05/pydantic_core-2.50.1-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:756d669f04e62ec4148ecfe22be6a4484d9b1181a6ef32e205ebfd200540858b", size = 2468048, upload-time = "2026-10-11T18:33:54.118Z" }, { url = "https://files.pythonhosted.org/packages/35/ca/e3832e9cf93651251de43c8c5c029ed680a3c1a0a1b17ee26c81bed08cbd/pydantic_core-2.50.1-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:c516cc5367ca3448995d42cb994bf3f4c9002d2a7c22eac9622551269ad1b807", size = 2512159, upload-time = "2026-10-11T18:33:55.99Z" }, { url = "https://files.pythonhosted.org/packages/4b/f2/773469b5a10a39116a2cb17edaf6d722f017dd8da07161b371465311c542/pydantic_core-2.50.1-cp314-cp314t-win32.whl", hash = "sha256:9d1bed94af6a63835461f3cf7502058eb166c58c4778e11d0f433cfb1bd69e19", size = 2098406, upload-time = "2026-10-11T18:33:58.043Z" }, { url = "https://files.pythonhosted.org/packages/ee/42/0bb74f8f25204b259b11ab7c12dc7f180893b6bd706118b385147fb6efd5/pydantic_core-2.50.1-cp314-cp314t-win_amd64.whl", hash = "sha256:c8dce1f1e0e5358b682a6ad3fa5e31b31d4560997b8e61417e9217c8d60f8a0c", size = 2148481, upload-time = "2026-10-11T18:33:59.913Z" }, { url = "https://files.pythonhosted.org/packages/47/0d/d801646c9679a4e630e15cf521d4108b93854b42a6e6e02391bd4c6b1095/pydantic_core-2.50.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ceff0acc940be2715bd6ad17b24c0e5304abf44f6efd0f81ee8499e640f9dc86", size = 2174972, upload-time = "2026-10-11T18:34:01.875Z" }, { url = "https://files.pythonhosted.org/packages/b2/84/23984b763d8862a02a13d27a44b6e8169428fd85ecfed88f54c29108604d/pydantic_core-2.50.1-cp315-cp315-macosx_10_12_x86_64.whl", hash = "sha256:8a6791afa2245e6c6b180122d105941644f5bd410bb18623b408808cc41a3102", size = 2224599, upload-time = "2026-10-11T18:34:04.016Z" }, { url = "https://files.pythonhosted.org/packages/4d/90/a63cf8586abc1d1a3f6d9b18f0224789ebf003851f092ebda3c7c863fd32/pydantic_core-2.50.1-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:84f34323a61a365b4e9295de6028474754829aaddd59c7bf1a040e7487ef8f3c", size = 2024191, upload-time = "2026-10-11T18:34:05.901Z" }, { url = "https://files.pythonhosted.org/packages/a6/6a/f34bff9808ffb4907fbf5f5040457d253cacf2da7fce9efbc99ca1b1a44d/pydantic_core-2.50.1-cp315-cp315-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23edad659e8dbd8ca7e4e877fe6c81573abbdf215bd25a68b53e1272f58b80c7", size = 2048252, upload-time = "2026-10-11T18:34:07.757Z" }, { url = "https://files.pythonhosted.org/packages/b2/54/13f419bf1eb59852003818e25935aaf175687d978f4c4bca70e08fe40a3b/pydantic_core-2.50.1-cp315-cp315-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a5fce22f1e87d181e924e12da7d81cfe031fb3881a5ddf26ad28f141756ca43", size = 2173376, upload-time = "2026-10-11T18:34:09.592Z" }, { url = "https://files.pythonhosted.org/packages/6d/6c/b5a34d24cd0c81669d8f8339d74e6815abcf2f8fb48ab4b49b84c09be1d5/pydantic_core-2.50.1-cp315-cp315-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c73622ef819328873b53109ee4f77ceb598bffedd02daf916102be3228866b78", size = 2364559, upload-time = "2026-10-11T18:34:11.534Z" }, { url = "https://files.pythonhosted.org/packages/eb/8d/d64d6216a8df365082665927ff923f183056f9049fee08e9777c9ac05296/pydantic_core-2.50.1-cp315-cp315-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ce8c25ca38cc0e3d7753ba180808de2c0c8cb24eae0df64491e40921454e9831", size = 2444697, upload-time = "2026-10-11T18:34:13.535Z" }, { url = "https://files.pythonhosted.org/packages/b8/0d/1b1149f60a00ea21ba5f70e28acbd40feb4598af414f80f53c921fac07c9/pydantic_core-2.50.1-cp315-cp315-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7689580e72a642ab5ec64d5f55b2e33636fa43b4ebe63c0c2c965ef307c7d1aa", size = 2159961, upload-time = "2026-10-11T18:34:15.56Z" }, { url = "https://files.pythonhosted.org/packages/1e/35/f236549299dcc78e71e945495d7ec67e78d20844d0999c60601685003031/pydantic_core-2.50.1-cp315-cp315-manylinux_2_31_riscv64.whl", hash = "sha256:d5c0e32fdbce7f1e8ef4d11f655694bf5f4175c757a9f1dc2be09b8864e5bcf5", size = 2234581, upload-time = "2026-10-11T18:34:17.502Z" }, { url = "https://files.pythonhosted.org/packages/6a/85/26901a490522b7f75ef9bb9a7afb73e5bb550f0e1cb5b99a0069183e2eb9/pydantic_core-2.50.1-cp315-cp315-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40f523349960fa30f3ea51404308ff50f9997a90df639590f47a057c1f32b415", size = 2244090, upload-time = "2026-10-11T18:34:19.402Z" }, { url = "https://files.pythonhosted.org/packages/ca/2c/481bcfc70ceeb77a778ca6e5b705fe592cb64735c108157f81b7dd9c280e/pydantic_core-2.50.1-cp315-cp315-musllinux_1_1_aarch64.whl", hash = "sha256:d4193206b6587047437f6f11d7e776df23e1c1e23af2a54d9347275614791e10", size = 2277948, upload-time = "2026-10-11T18:34:21.317Z" }, { url = "https://files.pythonhosted.org/packages/24/eb/f1e09333faa7ba447cde967310f758430cc7c5e987bdab5228816c70030d/pydantic_core-2.50.1-cp315-cp315-musllinux_1_1_armv7l.whl", hash = "sha256:84bc765b282a9d5b7fe0348b8648904f25a6a04b2139da52b1dd30c8ac3a2c8f", size = 2449688, upload-time = "2026-10-11T18:34:23.321Z" }, { url = "https://files.pythonhosted.org/packages/d1/b3/036bde636db8f76d92996e81aefc75678ab5cec4a07eea1ad0c72a893fc3/pydantic_core-2.50.1-cp315-cp315-musllinux_1_1_x86_64.whl", hash = "sha256:ed1e728b39a383c81035b2459cfcb35d99dfb01f7d6ebe3a913bc1cc5b81e459", size = 2479286, upload-time = "2026-10-11T18:34:25.214Z" }, { url = "https://files.pythonhosted.org/packages/d0/a3/07f018294ee18d144afeb6df1a47d9e92960f014be45c5ed13519fa5af95/pydantic_core-2.50.1-cp315-cp315-win32.whl", hash = "sha256:bc94f474417604bd383d2cd445d071b07dd55fedceed3ce33407bf1fcc107290", size = 2103683, upload-time = "2026-10-11T18:34:27.42Z" }, { url = "https://files.pythonhosted.org/packages/5f/98/f9bd7e1f9b6709f155acb9ef826d9c3884fe925f811fd8e55b9b52280bad/pydantic_core-2.50.1-cp315-cp315-win_amd64.whl", hash = "sha256:983a662de2571cb2502fc8ff47b6770b03d025d2eb314c92f77b3f07c74720ed", size = 2171681, upload-time = "2026-10-11T18:34:29.508Z" }, { url = "https://files.pythonhosted.org/packages/10/87/4bb3e1e7f385c076ab5af4d6dd0571b22042cd8207eb810d5b9fef15ae31/pydantic_core-2.50.1-cp315-cp315-win_arm64.whl", hash = "sha256:94845ff54dc5193f228cab81b2662a04bfbb892e95bdc15edf7399000ce57d54", size = 2156251, upload-time = "2026-10-11T18:34:31.455Z" }, { url = "https://files.pythonhosted.org/packages/47/47/83643225b08f2aef6c8cc4bbe6e3f79c5e139c4364a6e450d0f399d87774/pydantic_core-2.50.1-cp315-cp315t-macosx_10_12_x86_64.whl", hash = "sha256:4a53d13cdfbedbfa87f08b83c1a0a5efcc767d785a4b41934fa9cb672670493a", size = 2234363, upload-time = "2026-10-11T18:34:33.65Z" }, { url = "https://files.pythonhosted.org/packages/5e/66/127ca649ba2f2462039dc1e694c6c01e00a3689f023a617364d3507e6d97/pydantic_core-2.50.1-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:efbecf43d321f7b9281441f1f213f7c21c66988b0e06c2730ba13ed47a46bb08", size = 2000972, upload-time = "2026-10-11T18:34:36.037Z" }, { url = "https://files.pythonhosted.org/packages/5e/4f/e421e0a5d653b1203b090b2e48745976988d7338a647940704b5b9c2b399/pydantic_core-2.50.1-cp315-cp315t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc1f08f68dac9f9e83845a8039880aba2ab553eb9b2259c3243a313182c253fe", size = 2022925, upload-time = "2026-10-11T18:34:37.972Z" }, { url = "https://files.pythonhosted.org/packages/d5/4e/ea5568e2491e1a71100f15ae8c2d01ef52db42a184a2d4e716bc79e5eb8f/pydantic_core-2.50.1-cp315-cp315t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5dfe41f232befddb9c4377f6cfc702b51595e2d78ed082672adf8758d2c4619f", size = 2192867, upload-time = "2026-10-11T18:34:39.921Z" }, { url = "https://files.pythonhosted.org/packages/ae/5e/3b8c3a35acbe219909ada5defad5d7d9fed845fb2b37bd5ec518f453c119/pydantic_core-2.50.1-cp315-cp315t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:adc06d218a1cadfd2ec4628424d7d79ce4eba69c2965e7e7b55106f0da5208c8", size = 2388687, upload-time = "2026-10-11T18:34:42.184Z" }, { url = "https://files.pythonhosted.org/packages/b6/aa/7889b4e515f91a2e8c0ae6b5081fec0feb30c4398d1434e14793c60f173a/pydantic_core-2.50.1-cp315-cp315t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2cf91809d0721ab81592ba67bea7694821679c10b1a2e3c3460082b286c1918a", size = 2464415, upload-time = "2026-10-11T18:34:44.384Z" }, { url = "https://files.pythonhosted.org/packages/08/78/93449e628eb8a6fdcce3eff9043081179d1bc7ce6f1bff32dc5006f41e00/pydantic_core-2.50.1-cp315-cp315t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23923ab9292c40da026330b1ecf4dc2618c8e86e0422e5d1fbf50d94d64ca4f8", size = 2150823, upload-time = "2026-10-11T18:34:46.392Z" }, { url = "https://files.pythonhosted.org/packages/f4/f1/72c5bc129fceb0d00f05dc1e67f518c1728de1928c55f81fc13d7690de39/pydantic_core-2.50.1-cp315-cp315t-manylinux_2_31_riscv64.whl", hash = "sha256:f3377c8c2b3ce898423c5e5dd94c7982e30aa7717a7e6ab2470b9de364963709", size = 2245806, upload-time = "2026-10-11T18:34:48.805Z" }, { url = "https://files.pythonhosted.org/packages/28/2a/922a0e78f3aa6ab837b59f88190233fb8dad546c17995fde9bb3ed3b9b49/pydantic_core-2.50.1-cp315-cp315t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:455a773617b5913bf5c20d0692e5787b119e52c4d40ea644ca31f5758fd31be2", size = 2264160, upload-time = "2026-10-11T18:34:50.876Z" }, { url = "https://files.pythonhosted.org/packages/52/a8/0f1449e3e1b20941c9372faa18e7b6a092e30cdfa841902473f7989532ac/pydantic_core-2.50.1-cp315-cp315t-musllinux_1_1_aarch64.whl", hash = "sha256:1a9006395dece0e32e704c315eff8a00bede494f6108546cfc5539c89fef4f9a", size = 2294031, upload-time = "2026-10-11T18:34:52.876Z" }, { url = "https://files.pythonhosted.org/packages/d1/d0/1031f492857de70355fb16524bbb03efce5fd34c93ed4a1ec60be07e0d4b/pydantic_core-2.50.1-cp315-cp315t-musllinux_1_1_armv7l.whl", hash = "sha256:d2d82aa62521c55ddfb000ae70f88cdd8de974078f6024e821dfe5addd0c818f", size = 2468423, upload-time = "2026-10-11T18:34:54.995Z" }, { url = "https://files.pythonhosted.org/packages/46/52/269ffffa645b8e47906395a39cf9db1151ae9fa4bcd7f47b960bc31baf37/pydantic_core-2.50.1-cp315-cp315t-musllinux_1_1_x86_64.whl", hash = "sha256:009634b83993777ddcd69cad0ffcace43dabde692109528e35f0fde91e386a8b", size = 2512598, upload-time = "2026-10-11T18:34:57.149Z" }, { url = "https://files.pythonhosted.org/packages/31/5c/e47e28281f20326ff6f3c31d626f0a83e615d2d94ba41bb0ad6ec237184a/pydantic_core-2.50.1-cp315-cp315t-win32.whl", hash = "sha256:3fde4fdc6487a58d944ca87cf5adc95d5f266e872c19599f5f4c0a8a1b1f9f9f", size = 2098535, upload-time = "2026-10-11T18:34:59.313Z" }, { url = "https://files.pythonhosted.org/packages/03/ad/759e181e69c1b472c60b2049e5f61d5da1deefdd5ce1df4bb2ebcf771f25/pydantic_core-2.50.1-cp315-cp315t-win_amd64.whl", hash = "sha256:1c8632d4ac04e6f91128fca584b3a8a507d81604c24eeaaad00d4be42765c32b", size = 2148645, upload-time = "2026-10-11T18:35:01.571Z" }, { url = "https://files.pythonhosted.org/packages/6d/56/8a702c27e5be9f47e5f19d8669227424290e4c024e7c370279cbaf244b4e/pydantic_core-2.50.1-cp315-cp315t-win_arm64.whl", hash = "sha256:c3ede305158e75510be50869b319550ab072008c13d64d4ab1e094fb286b6f44", size = 2175297, upload-time = "2026-10-11T18:35:04.079Z" }, { url = "https://files.pythonhosted.org/packages/e7/73/a23a327237d9bb985298ce47702e196f995ce850224c12c70886bd66bb5c/pydantic_core-2.50.1-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:062e891facce5ca296a1c37098e5e466780457f86413894b399f0cf22934f769", size = 2162560, upload-time = "2026-10-11T18:35:06.274Z" }, { url = "https://files.pythonhosted.org/packages/df/b2/33b37b5e82408f402a5e82649a43e7c95cd5dab7beaeef2c35cedbfd18f2/pydantic_core-2.50.1-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:49c2cbb2397fe4d0987e84606e691af6cb87bc0ee1bd3e7b737f7e10b4c142f9", size = 2075250, upload-time = "2026-10-11T18:35:08.455Z" }, { url = "https://files.pythonhosted.org/packages/04/62/c7d5b9249466ccab90f3ce4790c2399dbfb8172ae9e74a7753dd295fe65a/pydantic_core-2.50.1-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9e4472072de0137ee0d8e72d6620e85939c271d2f90f6bbb4b15c24638b79f92", size = 2107891, upload-time = "2026-10-11T18:35:10.918Z" }, { url = "https://files.pythonhosted.org/packages/d4/7e/28d29bc1657195933147f772dee0558d9e0f045bbc11db7f992f40c37bb5/pydantic_core-2.50.1-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ed4f3cef55164b026fefb41341b7754cc6b624c75dfe7142d2ecceb5ad21c87", size = 2268026, upload-time = "2026-10-11T18:35:13.336Z" }, { url = "https://files.pythonhosted.org/packages/a5/09/1bcf160f3cd6333e2a76982fae5963e5032de0bcaaba38464223dc266bfe/pydantic_core-2.50.1-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:76e2e83fa6ec8cdc972d438dafc2522b3a47bee4ec0ae668b29cfb1977ab5242", size = 2217070, upload-time = "2026-10-11T18:35:15.688Z" }, { url = "https://files.pythonhosted.org/packages/3d/81/f02de95eec7794dfc7a5bc69a834f0e834b31b3009014ce6de903855f775/pydantic_core-2.50.1-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:a51eee75939cf811ac09b278745a6cee7dc873ccfbc8b9af3cc88fe4b7ce25b5", size = 2039027, upload-time = "2026-10-11T18:35:18.07Z" }, { url = "https://files.pythonhosted.org/packages/4d/16/227746ed3771d9bf2304568b55134849ece34e13b38b1d76de763015c77f/pydantic_core-2.50.1-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae28183297fb0d2b8dc46a1f01d51f5e45825fc5afe76a835a6cb7fb34821295", size = 2109009, upload-time = "2026-10-11T18:35:20.218Z" }, { url = "https://files.pythonhosted.org/packages/e5/b9/7664d1592a0e5a74903f357cd5b28ceb7336f3473256c5a4e8c8432f1881/pydantic_core-2.50.1-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88e492e8b9d0312e7dc13667c30222abf284dc3b79b5302b3607b41a5784ce61", size = 2269883, upload-time = "2026-10-11T18:35:22.48Z" }, { url = "https://files.pythonhosted.org/packages/bd/35/002a378302ff91d2a7f149bc8d22363faf581ba40ac39d0123444315a32d/pydantic_core-2.50.1-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7456d699b13954e9c0164dcb267250a10ae0dfb03e6e26d6796ab0d46e189c84", size = 2154076, upload-time = "2026-10-11T18:35:24.743Z" }, { url = "https://files.pythonhosted.org/packages/4b/5c/7a034330082c00f3c9795052bd9b161aaaf6e1951e897ac00a094823ef7e/pydantic_core-2.50.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0d955195bbbe489ad343fcc956eacea9357b79cb22192c66cacdefcbc14b32f", size = 2085850, upload-time = "2026-10-11T18:35:27.009Z" }, { url = "https://files.pythonhosted.org/packages/57/fa/d5b44a7d3d4eceed6ef8713a0003af56fefde6ec75915513bcdd5d730cd9/pydantic_core-2.50.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2c634642694e6a0dad2ab1d375589fa671fd442edd5caf7d9737b8f6ca22906", size = 2259754, upload-time = "2026-10-11T18:35:29.763Z" }, { url = "https://files.pythonhosted.org/packages/b6/88/e01dd37301710bd8b3b2daf34ec9e2a6e83a333130831c0d468b0292a48c/pydantic_core-2.50.1-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ee6db2fbed51a7991302e8fac498cd67e336246026d0dfa84cf5166ce1412760", size = 2268712, upload-time = "2026-10-11T18:35:32.654Z" }, { url = "https://files.pythonhosted.org/packages/3e/43/5bb80d4a4d2b2d84612a30205662cc521a20d209c94abc079ea48b4e0df2/pydantic_core-2.50.1-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:79490e33c4c0fcb933bbbcfc3a62184d8803b99f535863dfbb925e1bcb6945ad", size = 2305049, upload-time = "2026-10-11T18:35:35.392Z" }, { url = "https://files.pythonhosted.org/packages/e8/7b/e3ef76b269cfe4a5bd3bdcf5d7124cf05e5a8909d443b91639307116bdae/pydantic_core-2.50.1-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:48569b0ade9edfbe065cad1d700175546592aebbb42f02adcebcc26e75b896fe", size = 2466001, upload-time = "2026-10-11T18:35:37.791Z" }, { url = "https://files.pythonhosted.org/packages/8f/7a/ea0947aadc1d9f72d4be00d2e19939611ec17363bcb5e6eb9ec7d8221c34/pydantic_core-2.50.1-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:5f3cae32fc46121f787cb2486de9cf95a8bf72aec5cc78f64c606fa1735a6ef5", size = 2481777, upload-time = "2026-10-11T18:35:40.287Z" }, { url = "https://files.pythonhosted.org/packages/24/f3/d15bc0b1fb0c4f1e07b3326ffb7489f7ae70da2b56a0884d22641b0eb47c/pydantic_core-2.50.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:7f476456ac2bb0d937f75191494a09c83a30765fea4f70f3b404942fe25f6cdf", size = 2336787, upload-time = "2026-10-11T18:35:42.558Z" }, ] [[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 = "pymongo" version = "4.19.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "dnspython" }, ] sdist = { url = "https://files.pythonhosted.org/packages/42/8b/a9d214044153cb7d9141229d3e1b171cdf4f460fa07cade9354c4ce2f84d/pymongo-4.19.0.tar.gz", hash = "sha256:3c510dd3c5d9b392d3b33bb5d2a594758acfe8f026fca654253f947ce0af9d40", size = 2689381, upload-time = "2026-10-14T19:48:19.629Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ab/36/c75f48240cf3e5f4b88951602f37dda3de0eca47ecf543a75427237a46b9/pymongo-4.19.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:59b91b6856e099c7d8273901358b9a6ec0549dcc8930260748c25cde41c43780", size = 826481, upload-time = "2026-10-14T19:46:01.243Z" }, { url = "https://files.pythonhosted.org/packages/49/f5/de6d07f989620be35b70cf5692939ac86b2d3a5de3214aa182bac6d56eb8/pymongo-4.19.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d947eaff7cc132ae4d50dfd91d0ef7cefc71387fa66662295a81e6399a7f67ec", size = 826969, upload-time = "2026-10-14T19:46:04.412Z" }, { url = "https://files.pythonhosted.org/packages/c9/78/0181193cdf7590f8346e575d2a63fc12767c2caf4f1dde10f7b64e8cb41e/pymongo-4.19.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d7e8454cd242c41950e479941ccd79e111178779b709c22e75e61e0ad6d38055", size = 1032058, upload-time = "2026-10-14T19:46:06.334Z" }, { url = "https://files.pythonhosted.org/packages/6a/d1/15b2c596f65b947a61f67f16afa2931a41498f2679b265f769ba32844e28/pymongo-4.19.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0138fc5ce521017f31ba727213141df92557f60d22496617f65bd46eb71f0adc", size = 1039305, upload-time = "2026-10-14T19:46:08.373Z" }, { url = "https://files.pythonhosted.org/packages/c4/de/08b63f4e587ce1a1771c1b70f6e05597f3cfdb5df8012488ca1553599fd9/pymongo-4.19.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:46080e858976d01bb0c1acefabd16dfa87833d32e88bb5a57599a1937f6113d1", size = 1061685, upload-time = "2026-10-14T19:46:10.06Z" }, { url = "https://files.pythonhosted.org/packages/67/7a/23188fdfbdd357352b7d95e603210649fc30d23d1cada71e2df64fb9270d/pymongo-4.19.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3e889d608a1427599d9475cddd53fb70edf9a5858c4e33a40b5b93a040f035ee", size = 1054790, upload-time = "2026-10-14T19:46:11.673Z" }, { url = "https://files.pythonhosted.org/packages/9e/e4/2ddf312f603a620f2cf136599e34809c4a1771629b99a35e12a9054f89b0/pymongo-4.19.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a29b19dffe2d131258071fd8ea27c1b64605636e1b46a89e4f8396611df13d18", size = 1040803, upload-time = "2026-10-14T19:46:13.272Z" }, { url = "https://files.pythonhosted.org/packages/50/77/24b5eb286d70f97d85052c2df2458a8ea071ad5642a8afa646105ff45767/pymongo-4.19.0-cp311-cp311-win32.whl", hash = "sha256:763f6083d526644d6d9bf35ca9d51598d609ef4e21080c3f1dc38b5edbf9e167", size = 822076, upload-time = "2026-10-14T19:46:15.12Z" }, { url = "https://files.pythonhosted.org/packages/a3/f8/d21796502b11c9c66f6db179493afb3d4b05b07241fcb55d21c0bcc8e405/pymongo-4.19.0-cp311-cp311-win_amd64.whl", hash = "sha256:a23b2bf767426918759876c64579e7a7ba15ecbf8aa9d9f8d1fbde441d751110", size = 829055, upload-time = "2026-10-14T19:46:16.754Z" }, { url = "https://files.pythonhosted.org/packages/ff/a2/b4a8970b07f352c4f7e96edb63696c810f77f668577e468360ce849f96a3/pymongo-4.19.0-cp311-cp311-win_arm64.whl", hash = "sha256:8540b877c0129469a6ed8d6276d76b1901737f29bedc09f915d29afbfc2bca53", size = 825325, upload-time = "2026-10-14T19:46:18.679Z" }, { url = "https://files.pythonhosted.org/packages/9a/a3/47f2c964779c395314b1dc5506df9d00d4ba26c1aa6f35674e81a4a418d3/pymongo-4.19.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d28d6ff5cec9fd405657de12128e3faafb9c4a0b0194527e3d761dd9d083d7a7", size = 827051, upload-time = "2026-10-14T19:46:20.446Z" }, { url = "https://files.pythonhosted.org/packages/4f/58/d4ee8dac050365c0de8ca3ad02aafb9128176d63b9145ace2865c7850d2e/pymongo-4.19.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:dcf04e36e192791fb07f53e3a508c4752e6e0bba7aeda5cee10a84b3ccd0ca44", size = 827371, upload-time = "2026-10-14T19:46:21.921Z" }, { url = "https://files.pythonhosted.org/packages/b8/ce/83e24645c49cb66631e3802b574deba362e2712c92228f0853e44c10b098/pymongo-4.19.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:117e64c5ba2755d147bea31c86f3b4cd59ec8fb0f44cbae2f49e1502ff226789", size = 1047887, upload-time = "2026-10-14T19:46:23.669Z" }, { url = "https://files.pythonhosted.org/packages/36/02/f9336de0777074c37f164901bb28c9b6cd26e366e054f1b9d0e0938be380/pymongo-4.19.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8f072289060739430d2ded949a196939c3e3ff8ba4469b40e4833b5f1d8b0943", size = 1058974, upload-time = "2026-10-14T19:46:25.416Z" }, { url = "https://files.pythonhosted.org/packages/37/b9/01c3e07d93ec955ca72ef20f8ecacf77b4e75ad2b453acadd356c924e05c/pymongo-4.19.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ff9679803b691aa5ff6efe4de2d715e65e1784641e334d701b7b80a0776c35f8", size = 1082922, upload-time = "2026-10-14T19:46:27.605Z" }, { url = "https://files.pythonhosted.org/packages/0f/04/989bb02c9fb545304d88b77727c62fd215c46df43a8847d07960aad00227/pymongo-4.19.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:03ae5228d97eb465e42cd3058888be6892146296a600e8038b6dd3a4c4ac20fe", size = 1076649, upload-time = "2026-10-14T19:46:29.49Z" }, { url = "https://files.pythonhosted.org/packages/44/1b/e8364fadbc05bff19e67dda4f151e63fb13c58252cd5e1e1750c22cc1b8f/pymongo-4.19.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a5af9e52dfd18224474d5f54817ef2cbf06e313d100772a4a72aea8394037941", size = 1058052, upload-time = "2026-10-14T19:46:31.23Z" }, { url = "https://files.pythonhosted.org/packages/cf/f0/b562a891e73ae371f26fd9aa949c69f9596e720431a25396b8f9416a5194/pymongo-4.19.0-cp312-cp312-win32.whl", hash = "sha256:43debbb3e14be3db2764a77f14da2ac220b8ff192b485145855574127e2feee2", size = 822933, upload-time = "2026-10-14T19:46:32.885Z" }, { url = "https://files.pythonhosted.org/packages/ac/1d/dda443f738b63e34f045ba0249e03e0010e0406c093eb9af9c2468d56300/pymongo-4.19.0-cp312-cp312-win_amd64.whl", hash = "sha256:4fd6db124a081b627fb86e1f1d681a58f42c6ae2ec876c6e2015f1d516931ea9", size = 829709, upload-time = "2026-10-14T19:46:34.605Z" }, { url = "https://files.pythonhosted.org/packages/25/53/0392704674a921e9798eddc726045a01a554748dc7e80ec00d6577c76099/pymongo-4.19.0-cp312-cp312-win_arm64.whl", hash = "sha256:6073c762dbd4d0d17acbdd3aac4004750eec842fa40aa10965451367963f40d6", size = 825566, upload-time = "2026-10-14T19:46:36.382Z" }, { url = "https://files.pythonhosted.org/packages/ef/17/67576f517eeb18ce214e483164b0e8e124c3baee07aa114d3a5c5e72d2cb/pymongo-4.19.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:701c4a102c8794a1f656ff9c06ec9269276fb5f62c268359ee68d46163655b68", size = 826947, upload-time = "2026-10-14T19:46:38.094Z" }, { url = "https://files.pythonhosted.org/packages/2e/5a/15074c71298adfe468f7aa02080b2bdfc17bf9752d4855893df96a2b6718/pymongo-4.19.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ae2eb0a729de0b009de52b76003e4f1f19fd28cda88ec7a81c51faf90dd1587b", size = 827243, upload-time = "2026-10-14T19:46:39.827Z" }, { url = "https://files.pythonhosted.org/packages/50/45/bf0d840668f8932d6342c026a6ac9070d60c79a18453ab1fea5632688336/pymongo-4.19.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e8e44c4229cfe7e36fc5772b2c4c2d273b141bf9a212829ad5b0cc402efcd629", size = 1048053, upload-time = "2026-10-14T19:46:41.742Z" }, { url = "https://files.pythonhosted.org/packages/95/46/661e222349c1a9c64d83f859404076fc4e1063e395643f3526e013b5a74c/pymongo-4.19.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e7204210e9a613aef743b9c7a2e1f07406c21090b61b9338e3d96bb8b2b14b36", size = 1058956, upload-time = "2026-10-14T19:46:43.505Z" }, { url = "https://files.pythonhosted.org/packages/b6/11/d3e355464b01786a11700e70266d649c29ab281e98c7e32ca4b7ffb2d83c/pymongo-4.19.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ab0167d3c99a33a119befa93f1771ef0436832275ed6fd95c68b2535dae3f2e7", size = 1082727, upload-time = "2026-10-14T19:46:45.142Z" }, { url = "https://files.pythonhosted.org/packages/a3/eb/40f52875c43952533f0faa683a607600842df55e58a66d88dab22955f5f2/pymongo-4.19.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:df57b703b0b07c35860da7b214735b7750b2f2a5288f296dc08eeaf10cf8c46a", size = 1076511, upload-time = "2026-10-14T19:46:47.067Z" }, { url = "https://files.pythonhosted.org/packages/0c/98/ad65d39cab6cf071d09823aa525a0ff531cb9a4868130b9dfc44bb84828b/pymongo-4.19.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d199721ab77c83a7da83fcd219d3b819c559d8133e66c0d9bec9408001649f7", size = 1058253, upload-time = "2026-10-14T19:46:49.138Z" }, { url = "https://files.pythonhosted.org/packages/aa/0b/9ea41c62a2ca75326424eda2e798aa4269d2cfe221c662df5181274728dc/pymongo-4.19.0-cp313-cp313-win32.whl", hash = "sha256:54877c8e89add9ed115316722ead430d422b95d475b4eb57663bc6e017587853", size = 822970, upload-time = "2026-10-14T19:46:50.861Z" }, { url = "https://files.pythonhosted.org/packages/73/04/4622fcc48338b1f59318e4488327248dc3e8eeb1c2886c477d319632d803/pymongo-4.19.0-cp313-cp313-win_amd64.whl", hash = "sha256:2f5719dfbb5527a55dfaf6a68164df118efc13fffd00bc2ee9231488c1e8e03a", size = 829736, upload-time = "2026-10-14T19:46:52.927Z" }, { url = "https://files.pythonhosted.org/packages/d4/77/3a15fda4d2bbc91bfb186d72e40528b8bb52ad6fcf336221dc41dbbeafc0/pymongo-4.19.0-cp313-cp313-win_arm64.whl", hash = "sha256:9bf359a18df79981ea775b90c4c1fa044480b8896c0ff45932e568b0aed6a9eb", size = 825616, upload-time = "2026-10-14T19:46:55.076Z" }, { url = "https://files.pythonhosted.org/packages/ee/e7/6e62d60303a1e5cc816cefaa4d57d74df8ee65753ee9fe154b5fad851de3/pymongo-4.19.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:08c354566ab8b5dce6d805f35d61b5575455d3ea1835d7b90151d53e8c32e669", size = 826849, upload-time = "2026-10-14T19:46:56.892Z" }, { url = "https://files.pythonhosted.org/packages/e7/68/b2f67b99f22c5543a8be397c0ed8dee526c23717b4491405ae513138d88c/pymongo-4.19.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:06b9ee12c4ceb7fb6ff8a7ab0465814c1cb5e5c6c2c452cb18eab7435b38a5b2", size = 827363, upload-time = "2026-10-14T19:46:58.842Z" }, { url = "https://files.pythonhosted.org/packages/02/bb/35e17473d000bc0517190aabe1429853aa142499370dbd6d7ae3743e8833/pymongo-4.19.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ec25ab536e42e48fde356c6fc86e66f548e5af0cc584365e2ec34d3683be5a63", size = 1049786, upload-time = "2026-10-14T19:47:00.537Z" }, { url = "https://files.pythonhosted.org/packages/f2/2f/83cc2961d977c1ba36662f24ae55c9f5dbee2845ca615146fec0f4eda053/pymongo-4.19.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e65783e95b37c3387ed1105fe01e2be6b1b394c22331c5e8cc2fed2c3a30a06", size = 1059425, upload-time = "2026-10-14T19:47:02.511Z" }, { url = "https://files.pythonhosted.org/packages/cc/94/baa32ef582f9edf3112b00f6e271cf5f83c481edcf999e2f462898990e87/pymongo-4.19.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f3264b209b6319cae120306e266ed5fa9c7bc071b73ba5e13cbad23a6cbd73d2", size = 1082787, upload-time = "2026-10-14T19:47:04.38Z" }, { url = "https://files.pythonhosted.org/packages/37/eb/949a24776ceba31e9b731f7048dce4fbb913047afd16580a61723143afb9/pymongo-4.19.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:212dbc97f8e813a24639aaaef38503d84f7652d00b88b391f87762ba4c1f1709", size = 1073579, upload-time = "2026-10-14T19:47:06.247Z" }, { url = "https://files.pythonhosted.org/packages/5c/b0/a577ab8eff3772cf7036118b4e407a8cbb53add7bbe322f011871eb6db44/pymongo-4.19.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2faa34469b052635c81dcec6b07fc5757d4aba0ec60f94c6658c7fa6f887bc46", size = 1057865, upload-time = "2026-10-14T19:47:08.076Z" }, { url = "https://files.pythonhosted.org/packages/95/cf/81b1d8a35ac3e5d5dcd8fc466f9acdd8f67a5035da130afb0d76e2efd6ac/pymongo-4.19.0-cp314-cp314-win32.whl", hash = "sha256:eee3fc70ea4253c8c7a6bd7917be468c5ef0a2860898766dd55497a563ddda94", size = 823938, upload-time = "2026-10-14T19:47:10.086Z" }, { url = "https://files.pythonhosted.org/packages/5a/c5/1aa13304c714ad81ab70feb6bd99f6514baafe8e6c84d243ffabae678379/pymongo-4.19.0-cp314-cp314-win_amd64.whl", hash = "sha256:ac673404456b23c568cea326ab996a6b35a6009e41d42bcb774db025d0918b7d", size = 831074, upload-time = "2026-10-14T19:47:12.088Z" }, { url = "https://files.pythonhosted.org/packages/7f/a8/5de505ba380af3d10737a2d0ddd2c6752ff6e9a0fe484c992483efe74889/pymongo-4.19.0-cp314-cp314-win_arm64.whl", hash = "sha256:2bb0e7c422c14ff2b31ec8be3e6ecaad326c17fca17071bcfcd13482584a8e0f", size = 826686, upload-time = "2026-10-14T19:47:13.959Z" }, { url = "https://files.pythonhosted.org/packages/9a/fc/eddcc314b76ab9f3ab1417ecc088f88336cc2bca5be1356c8aa3d183dda8/pymongo-4.19.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:b01cc054878931ea81fc0a57c4c10489db723b8d7275fb10070f7228149012f1", size = 829839, upload-time = "2026-10-14T19:47:15.761Z" }, { url = "https://files.pythonhosted.org/packages/87/51/caa4ac1f33d4b8a4de2469a0624ffc7f7fae7441f7d71d41c2be306734a4/pymongo-4.19.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:823f8b2fb59e4e635e296d5e92efa883e3d01a8faa477d515fc9dfe515368026", size = 830216, upload-time = "2026-10-14T19:47:17.789Z" }, { url = "https://files.pythonhosted.org/packages/fc/e7/b3eb14aa900cfe7b6f7c0dd2349b5d0a488c17a9db76a8bfdf8bd30afd9d/pymongo-4.19.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1435721737b46be9bab5aa2374cfe57de934dc4ac421d5473308aa94c9fa39c3", size = 1113851, upload-time = "2026-10-14T19:47:19.743Z" }, { url = "https://files.pythonhosted.org/packages/00/b7/ec2c2bdde80e23693703f01805a1e37509e088127177f2d5758ca05c9a79/pymongo-4.19.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9dee18feff3203fa128798c6673c7795ef8a46d0b32c0e6b920c7b3f46129447", size = 1133130, upload-time = "2026-10-14T19:47:21.617Z" }, { url = "https://files.pythonhosted.org/packages/40/df/4f1bada8fa02babd094a5c4ed8f4ea1dc76cfc1366b26238a2ad1fc55b51/pymongo-4.19.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8d866560dfbe44bc5e1110e96af4b8d92ffe6368c345dac1c36c8060188ebba6", size = 1152659, upload-time = "2026-10-14T19:47:23.572Z" }, { url = "https://files.pythonhosted.org/packages/c3/cb/a97d315c4c4e362d1f2e216d306122ae0f713ab457f73730684f3606a349/pymongo-4.19.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:47f04522f786dca82c776d5c3ed3ff9d08d6bf4cd0074c42296da5fac4d816ad", size = 1144177, upload-time = "2026-10-14T19:47:25.554Z" }, { url = "https://files.pythonhosted.org/packages/8d/59/2a6c68bdee03f326194361149c68ec6720a22460d11a2a43a0742a7d7fce/pymongo-4.19.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ac55cf643eaa6146822f5f05f07be4dedbed906f525bb2ee098a865c4892788a", size = 1125673, upload-time = "2026-10-14T19:47:27.582Z" }, { url = "https://files.pythonhosted.org/packages/20/c1/b108dda370e09db7a4dccfb2bb003e769a8dd98513135e4429040cb88b83/pymongo-4.19.0-cp314-cp314t-win32.whl", hash = "sha256:3bcebec2536a9aec1d490ad6fa9fc7ffc3329059fb1f99154efa5d594abdc98c", size = 826636, upload-time = "2026-10-14T19:47:29.463Z" }, { url = "https://files.pythonhosted.org/packages/b9/55/a0da8479007f149838c094f6f863fc05c973abf6802654881a4dfc68858e/pymongo-4.19.0-cp314-cp314t-win_amd64.whl", hash = "sha256:24668c6990bef96e1558328ba0802279cc1f752a3bcc7b283c2f39099a01e28c", size = 835337, upload-time = "2026-10-14T19:47:31.313Z" }, { url = "https://files.pythonhosted.org/packages/98/d0/9837244d18d8280277e7b2e9366ee2b9d35338052362888a4704d77ad633/pymongo-4.19.0-cp314-cp314t-win_arm64.whl", hash = "sha256:542b0f4e47fe68e753c85503f8352d4baa81ac73593601c8ede0fa22ba5c0431", size = 827513, upload-time = "2026-10-14T19:47:33.367Z" }, { url = "https://files.pythonhosted.org/packages/97/6c/af80cf714a91b41441e9ad0aeac1af2000d902dfef7bac31388ba05bbfe7/pymongo-4.19.0-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:cc81d7ceeb7766254bce7ad7644dddb44241fb57555cd7c71de305b6903493b8", size = 826913, upload-time = "2026-10-14T19:47:35.317Z" }, { url = "https://files.pythonhosted.org/packages/95/14/2ed9ee6c83fd05a36d310100562b599ea987d2339c57955b1afba80d07ec/pymongo-4.19.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:b602baef46ec5cd876fdf45dfdf864a58f5a507129393b93b8248249008f9a70", size = 827513, upload-time = "2026-10-14T19:47:37.463Z" }, { url = "https://files.pythonhosted.org/packages/78/78/cd65885104e7b37f8cb7dd7e33d0b2c2415270afc2644ed643b52f526214/pymongo-4.19.0-cp315-cp315-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:179bc536b73fc76ae3d227114123ffc804f002fb45ddd996a81b233e806a0d2d", size = 1052003, upload-time = "2026-10-14T19:47:39.539Z" }, { url = "https://files.pythonhosted.org/packages/1e/ed/99fc74ed08dded2351818bf374303ddc400bd2e8b5ab297dac352aa0df56/pymongo-4.19.0-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a4bd5e3ecd44d94b4eeef51f7e20a513206f2fceeab9534e9299c31133cc2e42", size = 1061762, upload-time = "2026-10-14T19:47:41.601Z" }, { url = "https://files.pythonhosted.org/packages/8e/8b/ded0ef32a2c4032cbec796f29b7b6067e76ac27714fbcfe06ce9a969b415/pymongo-4.19.0-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a38cfd2d81daef820a099c28065c6dc2ec9254ae80fefcf7981ea27e5381159", size = 1084314, upload-time = "2026-10-14T19:47:43.874Z" }, { url = "https://files.pythonhosted.org/packages/52/64/82099393a7178c80fe1b16cc5dca94f388dec3df7a3f059a7b831bbf10dd/pymongo-4.19.0-cp315-cp315-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:567e509e1e01c956bfd5e60805b7d582aae45eeba34e9690d0da6f09560afb4f", size = 1075560, upload-time = "2026-10-14T19:47:45.904Z" }, { url = "https://files.pythonhosted.org/packages/09/d2/1eab760f5dc3d09fbc8fec7ad2474def3c8d2efbeb8550bff12fed61f863/pymongo-4.19.0-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3c3a47a6b325ac605352e9825ef658e6cca4f612e3a09838a564859f7d5435ea", size = 1060541, upload-time = "2026-10-14T19:47:47.885Z" }, { url = "https://files.pythonhosted.org/packages/8a/7d/426c1b661e8b4bd78671ea063ee66005faff0dfe6731ebdce0fb0000c339/pymongo-4.19.0-cp315-cp315-win32.whl", hash = "sha256:5d684e289cdb687f1508b15a44d3c0268f974c92ba129f658c1ef1fd196854e7", size = 823985, upload-time = "2026-10-14T19:47:50.253Z" }, { url = "https://files.pythonhosted.org/packages/b6/e9/f2ece0253d82d34fad0a316ffec848ac4e85357cae849cd5ea29def72ae4/pymongo-4.19.0-cp315-cp315-win_amd64.whl", hash = "sha256:546350d196b01b7feff7f8e6d140b6d4ab47486d5ae70dab858605cdfc2ffe1d", size = 831173, upload-time = "2026-10-14T19:47:52.418Z" }, { url = "https://files.pythonhosted.org/packages/a2/e0/be46ba1676cd04f831a9d4f6f8dbe0d3f816034788b8e3157762139f7aa8/pymongo-4.19.0-cp315-cp315-win_arm64.whl", hash = "sha256:d29ea47eebbeec81b67809fbb3440ffc53628d28f5b9f21624eed0038d9fddaa", size = 826603, upload-time = "2026-10-14T19:47:54.538Z" }, { url = "https://files.pythonhosted.org/packages/ab/20/3e04d21eab4844372ef141d5cc4f5e03d4fb9ebda057dd5e5ef1db562433/pymongo-4.19.0-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:b7e8b5b546e31ac63255650b0bf764383885a6c657b3269e83b9e1e5de3ed129", size = 829820, upload-time = "2026-10-14T19:47:56.428Z" }, { url = "https://files.pythonhosted.org/packages/44/9c/dbad3291c3614a884285d10e2cc123567386d682bf8a08caf5e0a630bf3e/pymongo-4.19.0-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:f21109534f5555cf77689ad323a21fbc07e8a397b34f157938a347725d83b7b5", size = 830313, upload-time = "2026-10-14T19:47:58.457Z" }, { url = "https://files.pythonhosted.org/packages/68/2d/17e783859c89e749fe63803a08ab5e85ca0ee8416f0cbe84d5fe6efa2981/pymongo-4.19.0-cp315-cp315t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3af5ab5a9e490580d3f40660665f0f4d579a324e25acee6372e1508e4b7c7b7a", size = 1117096, upload-time = "2026-10-14T19:48:00.917Z" }, { url = "https://files.pythonhosted.org/packages/34/cf/0b23e363eb5856ecfdf3b7edbdfea7f964da664eb78e507bb8375820c7e5/pymongo-4.19.0-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fb9d9bff4f666405cd9d7a17b6127294394847dce60ca38d8ba45f4879ada6c9", size = 1134854, upload-time = "2026-10-14T19:48:03.05Z" }, { url = "https://files.pythonhosted.org/packages/23/b8/60758f35a90729d77fdfd36eeff5ddf191d9f198528074884d816865d942/pymongo-4.19.0-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:be75840640e98ea4b5f150bceda8a55f1085e395732e21da028195da30ae79b5", size = 1154121, upload-time = "2026-10-14T19:48:05.638Z" }, { url = "https://files.pythonhosted.org/packages/5a/b0/e2b56cf154bf1dff7deca641de160215f9163253609a8beb780dc35f007b/pymongo-4.19.0-cp315-cp315t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fa39c6ddaf987a48ef073ff7fc225b84282079a46fbabaea9c5fcb6f89476e44", size = 1143786, upload-time = "2026-10-14T19:48:07.734Z" }, { url = "https://files.pythonhosted.org/packages/d1/88/39b61ede07785568d47229a01e7e82fc3903f5cac55ad377e0e64a0d324a/pymongo-4.19.0-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b92aa4cc4b0bf67a18e3c73062ef70e00ca6921c742aa4d0f4770a493193c661", size = 1126770, upload-time = "2026-10-14T19:48:09.891Z" }, { url = "https://files.pythonhosted.org/packages/40/f2/391d41d24384545b2a6ed09694b2444f765a6e20932c75ed4eb507c9ef36/pymongo-4.19.0-cp315-cp315t-win32.whl", hash = "sha256:eececca812e8f5b3c12ad33dc90201ac20f5f193da446f7719f4321a0841387b", size = 826638, upload-time = "2026-10-14T19:48:11.962Z" }, { url = "https://files.pythonhosted.org/packages/d1/48/96b923a2d29456896c7f11f8e6104339818112f5a8621f42ba51f131a510/pymongo-4.19.0-cp315-cp315t-win_amd64.whl", hash = "sha256:f17b100fdc16b65c12997ec4fcc78eecc0a6395254c7ec92a4596e855ff1f33a", size = 835209, upload-time = "2026-10-14T19:48:14.063Z" }, { url = "https://files.pythonhosted.org/packages/46/6b/2ede9f64d96393e8111d250620f5340d64e62f4617322a43800516027ce9/pymongo-4.19.0-cp315-cp315t-win_arm64.whl", hash = "sha256:bfcb5f8912edd9714a52564ad41c0dcd72e5408d1d3d67b41f6145df4a516318", size = 827452, upload-time = "2026-10-14T19:48:17.534Z" }, ] [[package]] name = "pytest" version = "9.1.1" 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/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313", size = 1636369, upload-time = "2026-06-19T10:58:32.857Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c", size = 386536, upload-time = "2026-06-19T10:58:31.347Z" }, ] [[package]] name = "pytest-benchmark" version = "5.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "py-cpuinfo2" }, { name = "pytest" }, ] sdist = { url = "https://files.pythonhosted.org/packages/63/8f/83a15e40dbc34a580ee56eb56983cae5394c6e94d50cf28fe268e457be25/pytest_benchmark-5.3.0.tar.gz", hash = "sha256:358444d4e89be901ee2b6404fb043ac3d7684002ad7f3563cc153fca6339c965", size = 375410, upload-time = "2026-08-23T17:45:08.891Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/eb/42/7e80f7cfa191e0a766d1de99b4661847415ad5db34f8209d81fd42175b59/pytest_benchmark-5.3.0-py3-none-any.whl", hash = "sha256:920ab1dfcffa718d49aa15ba144c7e357bda59216a0dc308016cc1c7236f719d", size = 48401, upload-time = "2026-08-23T17:45:07.094Z" }, ] [[package]] name = "pytest-cov" version = "7.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "coverage", extra = ["toml"] }, { name = "pluggy" }, { name = "pytest" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b1/51/a849f96e117386044471c8ec2bd6cfebacda285da9525c9106aeb28da671/pytest_cov-7.1.0.tar.gz", hash = "sha256:30674f2b5f6351aa09702a9c8c364f6a01c27aae0c1366ae8016160d1efc56b2", size = 55592, upload-time = "2026-03-21T20:11:16.284Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl", hash = "sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678", size = 22876, upload-time = "2026-03-21T20:11:14.438Z" }, ] [[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-discovery" version = "1.6.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "filelock" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f3/ee/cf608372c88ce2c136ee13c69ab6f667dbc0d0c1176af188b4ddc8853e66/python_discovery-1.6.4.tar.gz", hash = "sha256:bc70d31f0ec5de11eda13d4d64c16e24b3506a65984684f2b6c98cb83b2ea9df", size = 89883, upload-time = "2026-10-19T01:45:14.855Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/60/91/1aa70d3dfcab0dbcf88a2cbc3bce7f7c69562287a90216e617eaa4937e25/python_discovery-1.6.4-py3-none-any.whl", hash = "sha256:530179cc51a1816d512b15635b3dc931295ae12efb183783ad31190a5d425d2b", size = 39385, upload-time = "2026-10-19T01:45:13.668Z" }, ] [[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/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, ] [[package]] name = "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 = "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 = "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 = "ruff" version = "0.17.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f9/e7/e6d5749983b020e6cb1055abec0a6f361a8e94f0184cdcf56d4760995f02/ruff-0.17.1.tar.gz", hash = "sha256:5bb796c5112e9fb9527f2ef2faa0a130d6312d19de92bcfaddd70dbb2d41020f", size = 5323349, upload-time = "2026-10-15T15:23:18.64Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/2e/78/90c46ca6250709f7c37e397b60d06061adee8d0f7d13959ed6a8e49b14fd/ruff-0.17.1-py3-none-linux_armv6l.whl", hash = "sha256:1796c41eafec66f4635125dd1e074a7aa27b8d20c187d484360acf11d247fc4a", size = 10147528, upload-time = "2026-10-15T15:22:33.667Z" }, { url = "https://files.pythonhosted.org/packages/aa/d2/a2e28bc35b083ae51fa07dfba5280a667c8b01ecaee7802fc8849dcd5c46/ruff-0.17.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:8eadb09a788010be29c895418bdfa513e4e1c65e64b94e5b19e4cd381f6cc7fb", size = 10225974, upload-time = "2026-10-15T15:22:36.328Z" }, { url = "https://files.pythonhosted.org/packages/8e/71/7a9029a81c8206ee01a98f6cfeeb56e6c095af86857581a37045c46d7e94/ruff-0.17.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:29b454f18ca3eeaf37fbf140841dcf27d36109e29dee9aae8acecb68c26c6f74", size = 9270361, upload-time = "2026-10-15T15:22:38.651Z" }, { url = "https://files.pythonhosted.org/packages/c0/8c/e075e9c917cb0575297880c96768304e881240171c870cbd8d9b7b54bec2/ruff-0.17.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:872e03dd231744d6c5ec5c8af6be52b71323fc6ee096e4c8b34d9f844ee3b978", size = 9938300, upload-time = "2026-10-15T15:22:41.284Z" }, { url = "https://files.pythonhosted.org/packages/87/27/0b4bb926a49de2383f161272b4d863571a4c7ecdbf595a6bc58813a13367/ruff-0.17.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4c0d6cb5f8fbac77eec9af49f4fc0eaf856b05545e372b0694d24b4e76b1c640", size = 9948464, upload-time = "2026-10-15T15:22:43.681Z" }, { url = "https://files.pythonhosted.org/packages/14/27/518d57e0e02aecb8ea4acac6b57b51a53173d25fa734952bfdd7d531e88e/ruff-0.17.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78beced4a3c94dfedbee4b999b95b6a27b35820fdc0afbacc6d37a8da26c1cd1", size = 10638639, upload-time = "2026-10-15T15:22:46.081Z" }, { url = "https://files.pythonhosted.org/packages/01/82/d89a4e498ade59e6cee52d67f8da569019372212b87468c1fdeae884601c/ruff-0.17.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7feefc63921202894f0e158b0e32f45a5950d70a7fb693ccb9264816c25b1c05", size = 11337238, upload-time = "2026-10-15T15:22:48.894Z" }, { url = "https://files.pythonhosted.org/packages/a2/7c/3b0fdef9352656317c977086fe1d802902406e4f2a0d8578da90c0e6d1c5/ruff-0.17.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:684154861a819bf1f433669d2a0ce9c3e54677c65b8ebb866cc2a7ec86345785", size = 10896327, upload-time = "2026-10-15T15:22:51.45Z" }, { url = "https://files.pythonhosted.org/packages/62/86/5566290219708ce2928f3a29c4f843a1185b341ec6111c4631a33c5ceced/ruff-0.17.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6ef98e51de8ef38082f90653ceeb84944bd7673783eea13e1647c5b9b064189", size = 10350811, upload-time = "2026-10-15T15:22:54.401Z" }, { url = "https://files.pythonhosted.org/packages/ad/d2/ca8462dabb3c413990d49703ba306c30c862195a75448d080fa8fcce9775/ruff-0.17.1-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:8f9aa5b5bd5fa1937803ea609c8f153b8de39bf3e0e149897ae34b0c5b52f467", size = 10569994, upload-time = "2026-10-15T15:22:57.142Z" }, { url = "https://files.pythonhosted.org/packages/e3/ad/dd1864c1f1db17c8cfb297ce70b352388e6977620f66f7182c52855407df/ruff-0.17.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:80e53b0e5faa3c5667f035daaa032893ae42b7cfe708c886d39ed131e54688ab", size = 10059672, upload-time = "2026-10-15T15:23:00.084Z" }, { url = "https://files.pythonhosted.org/packages/65/45/3f56cf1d2168c2165cdd5ac6f9668aee66a4cfdd4caf2b2cc5ccb2b1d568/ruff-0.17.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:056c5d5fa0ac790051ae165d7035c7bf956d02de2db557f2e9b31d877a505fca", size = 9947803, upload-time = "2026-10-15T15:23:03.132Z" }, { url = "https://files.pythonhosted.org/packages/aa/4b/5457cb2be4c1d1ea5e919558131a0f197a4a454a0530d9e30820e8206e4c/ruff-0.17.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:bd8f5a55b10f371642eacd0e8665a42a8b97da15c9a7187c79e697b77b5e0ce4", size = 10351807, upload-time = "2026-10-15T15:23:05.628Z" }, { url = "https://files.pythonhosted.org/packages/49/fb/db15b4f8fa24a1e36b99e1401f42ef6df16ee299a48670d5d262b771e7d7/ruff-0.17.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ce05e6f3973611d9550a600e04bb531061e368baba31610eb57c1509a8f21a0a", size = 10765716, upload-time = "2026-10-15T15:23:08.092Z" }, { url = "https://files.pythonhosted.org/packages/0a/e8/1e186578076aff7a80735f625005fde678412ab609cd323ed182eb7d6b87/ruff-0.17.1-py3-none-win32.whl", hash = "sha256:1de0030a8aa78c65c5fecb84b2e5c390ac684c0452875a02afc7c083d49a496a", size = 9895093, upload-time = "2026-10-15T15:23:10.582Z" }, { url = "https://files.pythonhosted.org/packages/6a/2e/da3d9589bae8e8b58f3a48bd5bc0b980232fb14a83bf02c3be7660f87c1b/ruff-0.17.1-py3-none-win_amd64.whl", hash = "sha256:5df76f16580fab58d0f6c98a3ac254a4abceb7b2489b8b678335869cff77b3d7", size = 10097955, upload-time = "2026-10-15T15:23:13.309Z" }, { url = "https://files.pythonhosted.org/packages/df/c9/0f2a4dea06a5e12c1191ee3d96b1e1233797d0d5e18f97a2b909a95a9836/ruff-0.17.1-py3-none-win_arm64.whl", hash = "sha256:42400b9a6ff8515ff27796f07f92e0195be011c86e81e381606f58ea5502fef4", size = 9853542, upload-time = "2026-10-15T15:23:16.05Z" }, ] [[package]] name = "setuptools" version = "84.2.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/70/b3/c19426f783614d625699a4b247faf628ea9ab1db228674491767b417f9e1/setuptools-84.2.1.tar.gz", hash = "sha256:3ff8b3b5492a0aa66960f4419365a86b84e013070d4313e4d4a6894f5d64d6bc", size = 1230289, upload-time = "2026-10-20T19:01:37.742Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ef/55/6dc6d6bb953bdfc52519a0059592c52b6e3b8ad51cf8256dffceb55b0610/setuptools-84.2.1-py3-none-any.whl", hash = "sha256:ca140b45d5325a9478f880e351484f62fef15f336462e449ca0c03c873d589c2", size = 876263, upload-time = "2026-10-20T19:01:35.678Z" }, ] [[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 = "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 = "sphinx" version = "9.0.4" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version < '3.12' and sys_platform == 'win32'", "python_full_version < '3.12' and sys_platform == 'emscripten'", "python_full_version < '3.12' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] 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" }, { 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/42/50/a8c6ccc36d5eacdfd7913ddccd15a9cee03ecafc5ee2bc40e1f168d85022/sphinx-9.0.4.tar.gz", hash = "sha256:594ef59d042972abbc581d8baa577404abe4e6c3b04ef61bd7fc2acbd51f3fa3", size = 8710502, upload-time = "2025-12-04T07:45:27.343Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/c6/3f/4bbd76424c393caead2e1eb89777f575dee5c8653e2d4b6afd7a564f5974/sphinx-9.0.4-py3-none-any.whl", hash = "sha256:5bebc595a5e943ea248b99c13814c1c5e10b3ece718976824ffa7959ff95fffb", size = 3917713, upload-time = "2025-12-04T07:45:24.944Z" }, ] [[package]] name = "sphinx" version = "9.1.1" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.15' and sys_platform == 'win32'", "python_full_version >= '3.15' and sys_platform == 'emscripten'", "python_full_version >= '3.15' and sys_platform != 'emscripten' and sys_platform != 'win32'", "python_full_version == '3.14.*' and sys_platform == 'win32'", "python_full_version == '3.14.*' and sys_platform == 'emscripten'", "python_full_version == '3.14.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", "python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'win32'", "python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'emscripten'", "python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] 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" }, { 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/fc/73/567727fc8c8d85bc3adc88a246e12937cfda8d565cf1d80e85bceaa61fe5/sphinx-9.1.1.tar.gz", hash = "sha256:48b627f02908f22c601b3ba9c7b17265b4f315dd05c8bc64cd4da41183f44fbc", size = 8725638, upload-time = "2026-10-20T00:41:13.96Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/47/18/3c66ea76da7de47e716b181c35bdbfafbd5e9af0bb247b14578e9de348e9/sphinx-9.1.1-py3-none-any.whl", hash = "sha256:f8b60013ce25017be41a509e5c2d265bc1918410061315c36b809c7f335646c0", size = 3923559, upload-time = "2026-10-20T00:41:11.288Z" }, ] [[package]] name = "sphinx-markdown-builder" version = "0.6.11" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "docutils" }, { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, { name = "sphinx", version = "9.1.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, { name = "tabulate" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ad/13/102d7134743120db25e636ffb57a30818e95a416583dca83aadac9c5dd87/sphinx_markdown_builder-0.6.11.tar.gz", hash = "sha256:ba3bf33e0e42ff30ae686ac73957a95e6d045790dcfbaca012dd8ae01794e577", size = 24020, upload-time = "2026-08-16T06:51:38.158Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/c9/71/06b415631c2e494c80546073b46013d1715dceb3abe30bd63b34b4e7d9ca/sphinx_markdown_builder-0.6.11-py3-none-any.whl", hash = "sha256:acfb94d6ee66c7a47da0ca0420578fa16f115812af25b8fd21755d5909aacf51", size = 18088, upload-time = "2026-08-16T06:51:36.81Z" }, ] [[package]] name = "sphinx-rtd-theme" version = "3.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "docutils" }, { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, { name = "sphinx", version = "9.1.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, { name = "sphinxcontrib-jquery" }, ] sdist = { url = "https://files.pythonhosted.org/packages/84/68/a1bfbf38c0f7bccc9b10bbf76b94606f64acb1552ae394f0b8285bfaea25/sphinx_rtd_theme-3.1.0.tar.gz", hash = "sha256:b44276f2c276e909239a4f6c955aa667aaafeb78597923b1c60babc76db78e4c", size = 7620915, upload-time = "2026-01-12T16:03:31.17Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/87/c7/b5c8015d823bfda1a346adb2c634a2101d50bb75d421eb6dcb31acd25ebc/sphinx_rtd_theme-3.1.0-py2.py3-none-any.whl", hash = "sha256:1785824ae8e6632060490f67cf3a72d404a85d2d9fc26bce3619944de5682b89", size = 7655617, upload-time = "2026-01-12T16:03:28.101Z" }, ] [[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-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-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", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, { name = "sphinx", version = "9.1.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, ] 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 = "2.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/59/02/4f334c7fc3e54c51d2364575a41cd2fae6847e7f53001949f0be5f32e18b/sphinxcontrib_jsmath-2.0.0.tar.gz", hash = "sha256:551f780cf9687f9c3c74f0cf9f18aca06e0d6958853453f3803fe4d357c5b924", size = 14511, upload-time = "2026-10-20T18:22:05.514Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/da/c2/2965c35b39587d4b7a397f65a9c7d4b942b031061e7ac1ce91782f394a0d/sphinxcontrib_jsmath-2.0.0-py3-none-any.whl", hash = "sha256:15ca92fe0eec82f0baf91a7efcc51ffacdb605924be6327683a52ebdacb6744c", size = 78095, upload-time = "2026-10-20T18:22:04.42Z" }, ] [[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-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 = "stack-data" version = "0.6.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "asttokens" }, { name = "executing" }, { name = "pure-eval" }, ] sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, ] [[package]] name = "sympy" version = "1.14.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mpmath" }, ] sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" }, ] [[package]] name = "tabulate" version = "0.10.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/46/58/8c37dea7bbf769b20d58e7ace7e5edfe65b849442b00ffcdd56be88697c6/tabulate-0.10.0.tar.gz", hash = "sha256:e2cfde8f79420f6deeffdeda9aaec3b6bc5abce947655d17ac662b126e48a60d", size = 91754, upload-time = "2026-03-04T18:55:34.402Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/99/55/db07de81b5c630da5cbf5c7df646580ca26dfaefa593667fc6f2fe016d2e/tabulate-0.10.0-py3-none-any.whl", hash = "sha256:f0b0622e567335c8fabaaa659f1b33bcb6ddfe2e496071b743aa113f8774f2d3", size = 39814, upload-time = "2026-03-04T18:55:31.284Z" }, ] [[package]] name = "tomli" version = "2.5.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/b0/78/9ad63712633ed3ab5cc1a648d863d7e7da371e9425e209555a0fe711b695/tomli-2.5.0.tar.gz", hash = "sha256:264507556cd8b8c8e7c6ee037cdf443a463f03f4c958e57195e3d369711b8ff6", size = 17662, upload-time = "2026-10-07T12:23:37.892Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/22/a6/ab99b60ee52acd949684febabc3005d0045d0f66bebd9cdebd67372d26dd/tomli-2.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c4dc1c1781f2f716de763d1e9a7b34c6a894e167e291c7c5d16c72f7a9538545", size = 163901, upload-time = "2026-10-07T12:22:15.601Z" }, { url = "https://files.pythonhosted.org/packages/bc/00/ee01b7ed4579180fff07142d290257f25ba786f23f3ec6005f620933c2f5/tomli-2.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:eff8babca5a7999bc137acbc7482a8b7e17ffca5075ab41f5d770ab408c7bfef", size = 163756, upload-time = "2026-10-07T12:22:16.957Z" }, { url = "https://files.pythonhosted.org/packages/72/c2/4efebf65372f6583185f79799312109dddb61102d47e5c33dcfd1a297aca/tomli-2.5.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:86665cee9c4835b7a7f1e8ec2c719b5258d4dc782887aded5a8ae7352a96843b", size = 268038, upload-time = "2026-10-07T12:22:18.135Z" }, { url = "https://files.pythonhosted.org/packages/53/07/5850468e925d898abb36038666f9c333a94d2a223e802a8ba5b6d319d23f/tomli-2.5.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d7e369fd63331746182360977b1892bfc215476a30d61612d732425311639f56", size = 276422, upload-time = "2026-10-07T12:22:19.567Z" }, { url = "https://files.pythonhosted.org/packages/b4/87/f293984cdcf83c054196d4fd3dad44fc68ae55b4b8c44bc76cef360c3150/tomli-2.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7ad1ea345759240d6463efa0ed1c704402752e49aa21476620738d74d72d8aa1", size = 272616, upload-time = "2026-10-07T12:22:20.794Z" }, { url = "https://files.pythonhosted.org/packages/ce/ce/db582886b3c1219d3fec93ebd669332482e5aee7a91e0f7838d84f2d1759/tomli-2.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:96243987194634bd411066ce40c952e108f86af04db533ecd8ac3ff2a85b1885", size = 276593, upload-time = "2026-10-07T12:22:22.12Z" }, { url = "https://files.pythonhosted.org/packages/bf/72/7619b87dea4261fc27dd7b54c4461c129c1f7d9bb7ba3aec89c797a431b8/tomli-2.5.0-cp311-cp311-win32.whl", hash = "sha256:610b27d99f28ec5f191c7064a48f3ddb179a1fe6ca73d571483ae859f57b605e", size = 101830, upload-time = "2026-10-07T12:22:23.651Z" }, { url = "https://files.pythonhosted.org/packages/1e/74/220106da34502304b6751a2a9b8a9fbca6c3fd47e737a2e2e3da7c61c9db/tomli-2.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:c804ae44fe7b4bab5da295e4f980a1ff04670bca9d23fe0a4e887e08ebd741a8", size = 112742, upload-time = "2026-10-07T12:22:24.972Z" }, { url = "https://files.pythonhosted.org/packages/27/99/7d9c8b41837a7773613e169504147375c157a290167aa59ad74a085f521f/tomli-2.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:cfac177ebd6236003846ea339981f71457cb6eb748f23381eb257e45092e3980", size = 109332, upload-time = "2026-10-07T12:22:26.117Z" }, { url = "https://files.pythonhosted.org/packages/52/ed/7baa86f87493646a594de388c7c1c40a39dd0461f7e9c0359cbeefc91fe8/tomli-2.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1f4a40d03fb9f63424f0979855bdeaf44dd7696b8d59501822c10ed30ba532df", size = 164854, upload-time = "2026-10-07T12:22:27.444Z" }, { url = "https://files.pythonhosted.org/packages/a5/b1/44c0341f2224397855723c7a8a39f718ea6fcbcc3dacc66e5aeca0f334e3/tomli-2.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9ebf8d19b17bd0daeb7b7dec81a946a439b753942fd0210d6e96c532249eea6b", size = 164074, upload-time = "2026-10-07T12:22:28.679Z" }, { url = "https://files.pythonhosted.org/packages/23/04/e2d5b7d3fba47adedb23de616c16d428ea076c79a3d8e1d95d649ffe197e/tomli-2.5.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf0b5e8e0f68ebb494356e577c06c139161efd8d3b9050f93b39b7c26cc54ff0", size = 274274, upload-time = "2026-10-07T12:22:29.804Z" }, { url = "https://files.pythonhosted.org/packages/43/90/6090e706ff27a6f89f4a40578e3324b95c3cd8c4150868aabf33a8f414c3/tomli-2.5.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cf74416bdc94ae458b14e37286c1073081850ac8459a00d0c5efef5d44294c6", size = 286435, upload-time = "2026-10-07T12:22:31.297Z" }, { url = "https://files.pythonhosted.org/packages/0a/9e/a2c40768df16c408f22430afb0a73e9d7e5f79c950884954649d1146b74d/tomli-2.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:61ea1ebe1e55a34ea8199cc8dbff398d35027b82271c8ac4802fd3a1fd5b1bcc", size = 278119, upload-time = "2026-10-07T12:22:32.601Z" }, { url = "https://files.pythonhosted.org/packages/12/25/3c0cb485b98e9cfac495629b1c93c87ccf0b72fbe9d2689fd8fe62c6d5a3/tomli-2.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ed53f7e89bb04f6d9e8e7799112360b0c4d5cbff067de0814c98c37c39b920f7", size = 286177, upload-time = "2026-10-07T12:22:33.745Z" }, { url = "https://files.pythonhosted.org/packages/77/8b/0144c65f0e37e51c18d04ae15c21b19431c165002d0131fe9aa8b0b8b1e8/tomli-2.5.0-cp312-cp312-win32.whl", hash = "sha256:e7ad033e27a516a233bea839cdb77b80146facb3b4f40bf02cd0cac165cdd5c2", size = 102760, upload-time = "2026-10-07T12:22:34.887Z" }, { url = "https://files.pythonhosted.org/packages/de/32/5d6d8f42fc9a05fce69354e00ff256484192f5f2fc9a2165718fa0de61ec/tomli-2.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:bd05de8c1698f8413dd7d869492693a0bf2211543b787ac78cd5e7536af1a6d7", size = 112722, upload-time = "2026-10-07T12:22:36.162Z" }, { url = "https://files.pythonhosted.org/packages/30/65/df18032218db0fb9b769fb23c8039a051f15c811993995ea04c350273a32/tomli-2.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:069435bd5480429b98c5e5afb02ab21c219b6f0064680671c6dc0d46817346ea", size = 109534, upload-time = "2026-10-07T12:22:37.296Z" }, { url = "https://files.pythonhosted.org/packages/42/e5/51736d70da209350969e15aca5c5ab6e2ce1ea87a0a892a6c13aec172a86/tomli-2.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:943276cf269e0071948d9ff697159c1735e623c1151d88abb09b74659ef0cbea", size = 163328, upload-time = "2026-10-07T12:22:38.373Z" }, { url = "https://files.pythonhosted.org/packages/ec/55/086f80dab4ab497602644274e6dea7ec5dd0b4e262e443a8ad3bb7edee2d/tomli-2.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:463b16086865b97facd8d0b3fb4cb7c544e3f58d2a69dc3113d6db9653fdb043", size = 162246, upload-time = "2026-10-07T12:22:39.673Z" }, { url = "https://files.pythonhosted.org/packages/aa/eb/3ecc94459f3635c92321f4e7bde571323fdb2267c50e19e3188a281eae3b/tomli-2.5.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1245a6638fc4bb0a60af38a7d45413db34a13842027c77597c712c998c62fdf0", size = 272655, upload-time = "2026-10-07T12:22:41.08Z" }, { url = "https://files.pythonhosted.org/packages/c0/d7/494fd1f0c37a621f1ad9975c2efadb523e8101f144ed6edb2e7fe64738f2/tomli-2.5.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5d8bac3d603c97e6854424e5b2b5b741bdbde387e09f162fb0446812b4a8362b", size = 283595, upload-time = "2026-10-07T12:22:42.222Z" }, { url = "https://files.pythonhosted.org/packages/70/51/bb8d62b1317e6640866f6949b2d5855e5300f2c99d46de1cd245570bba65/tomli-2.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:21e4cae4114aba25aa0d4f85cdf486d290fb35c0954d7bba536248da64d43066", size = 276253, upload-time = "2026-10-07T12:22:43.625Z" }, { url = "https://files.pythonhosted.org/packages/66/f4/f46bd7f0763cd47de2db697dca9257c6a4adfd1a93b018cc75c8190ed5a8/tomli-2.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bbaefc84548d754be821bba7c4141c4787dda182f9e77f2f87b71213529efa7b", size = 283582, upload-time = "2026-10-07T12:22:44.983Z" }, { url = "https://files.pythonhosted.org/packages/ac/03/70f2bcb2923a6db37818d917e124270a7f4cfd38ea576f5aa753a91c0ef5/tomli-2.5.0-cp313-cp313-win32.whl", hash = "sha256:abdbf6313b8d9efe157edeb7ab6eae4de064b1300ad31abf73755154b30abe68", size = 102628, upload-time = "2026-10-07T12:22:46.508Z" }, { url = "https://files.pythonhosted.org/packages/dc/98/d52024bb5b0ff68b4f0d276d867f634c84a67319a7e9f6b7708a37742333/tomli-2.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:fd4dc129784e0c5335bd4e61dfcc4487499a013419e655cf2da1d091b7e0efdc", size = 113301, upload-time = "2026-10-07T12:22:47.647Z" }, { url = "https://files.pythonhosted.org/packages/6f/f2/540db3a70572a8c23a28aba3e9c358ce0ffffbafc990905c1343aa265b31/tomli-2.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:69491c143d2fe063046e0301e62a810bed338fa4d1ce0fd870c27dc1e09b0d84", size = 109744, upload-time = "2026-10-07T12:22:48.925Z" }, { url = "https://files.pythonhosted.org/packages/e4/49/caf6b307766eb9567664a8707e9d6be5fcc0e8903f18781c6677a60d80c7/tomli-2.5.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d3182ee2d887e507bd67319a0a61105d1dd33facc111329559a233b772c1a105", size = 162899, upload-time = "2026-10-07T12:22:50.088Z" }, { url = "https://files.pythonhosted.org/packages/d3/c8/68cfce773a2733a49c74f99d627fb461bd990756860099eac25617889585/tomli-2.5.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:521345fd1f19d45b8df87657aaa38b6f2ca3800059fadf428e7ebf479a383646", size = 162080, upload-time = "2026-10-07T12:22:51.558Z" }, { url = "https://files.pythonhosted.org/packages/7e/b2/e5bb8651fdad593f670501a7d718b1a7f73f064d44dea15e04c04dfef45d/tomli-2.5.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e95c7614e705bfe2b04b27aa124adec59752d15813df37e2156747cab3a006b", size = 273380, upload-time = "2026-10-07T12:22:52.918Z" }, { url = "https://files.pythonhosted.org/packages/8d/d2/9e2d7f8b1dfe0e2b34c245986ebd55c4c553ea4ce6c47c443b332673253f/tomli-2.5.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7ac2027d37c3afbdf4bdd377f2676f6f1d2122a5be1f1137b49dced590b37e75", size = 283228, upload-time = "2026-10-07T12:22:54.173Z" }, { url = "https://files.pythonhosted.org/packages/ba/df/ec7b876b7b1a2718bd74a3743c076fff565b04029ba33e8f61fac262739f/tomli-2.5.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c414be4ed9d3cac80c42e348fa5a956117d1a48227f48026e31f59cb4a7671eb", size = 277189, upload-time = "2026-10-07T12:22:55.342Z" }, { url = "https://files.pythonhosted.org/packages/7d/7b/e192d9eed0b9cb80da799f4d77052297fb9a2c3cc9b19f571f56ea88add6/tomli-2.5.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9b03d7dc168353b4132965bde20feceabaa470e570c6f59660dfae59b1f9eeb3", size = 283632, upload-time = "2026-10-07T12:22:56.735Z" }, { url = "https://files.pythonhosted.org/packages/84/50/ff94454e75461d75623e47401ed323d65c10aab8fe9033242c20cd2fdf32/tomli-2.5.0-cp314-cp314-win32.whl", hash = "sha256:6f041843c4d3a37245c0c056fd955b186bf8b1fb85690cbe40b81230891dc34b", size = 103535, upload-time = "2026-10-07T12:22:58.084Z" }, { url = "https://files.pythonhosted.org/packages/54/0b/bdacf05f963bd6026ebf6eeb0beda847d1d60e03e440725c64a4e08a0afd/tomli-2.5.0-cp314-cp314-win_amd64.whl", hash = "sha256:f4b653094e18f9031102d3a1da5c729c8f222d85225b18037dac621695e46e1a", size = 114621, upload-time = "2026-10-07T12:22:59.2Z" }, { url = "https://files.pythonhosted.org/packages/61/99/53f438fa6ae4f9d4ed0ddde3e7242b3bdc34b48c8f9948b72b9e9b127676/tomli-2.5.0-cp314-cp314-win_arm64.whl", hash = "sha256:3f89d10c1ff6a38d992c27fc8a4816af71a909e08a40ec66934240b1e74347c3", size = 111572, upload-time = "2026-10-07T12:23:00.479Z" }, { url = "https://files.pythonhosted.org/packages/b9/20/1f88f19427d380a40e90a770e087489eaafe4aeee070ae88ed2bbec00acd/tomli-2.5.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:e9e15b4a6c7dd6b85b5fbab29488a73f1f70de516942308daa266bf0e0aeb0d4", size = 171814, upload-time = "2026-10-07T12:23:01.914Z" }, { url = "https://files.pythonhosted.org/packages/d0/56/cbe5079c9f9a54b9b3e27fc82f08f3cb36edee75561679f53d2380c801d6/tomli-2.5.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e12bbcd32897272fb05929110362ae9ff4c1b9bb26bd9e971e71dcd3275b4c3d", size = 171324, upload-time = "2026-10-07T12:23:03.18Z" }, { url = "https://files.pythonhosted.org/packages/2b/30/1d53fd3b0f1cb3ba542e345ec32c26aefdddc4e829e4f3429af8a4f27782/tomli-2.5.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:20aa36de8f2cf87237143bc1fa1aae8d6612c09118f4da21c6a684db5dd1f6f9", size = 297441, upload-time = "2026-10-07T12:23:04.345Z" }, { url = "https://files.pythonhosted.org/packages/66/d9/0800acb6a111686f764c1b91ef15cc42a20a66a46013bb42220f1d2c61c1/tomli-2.5.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22185fad8a1e622f064e78008018a0dd3323550dcb479cb7a1d296888d74024f", size = 307476, upload-time = "2026-10-07T12:23:05.671Z" }, { url = "https://files.pythonhosted.org/packages/e8/63/30a8f3cd51b5bec37f04744bad0b0dc6160df84aad4f27b0e9283d66f221/tomli-2.5.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:984012f71908165449a951de2050d52f276bfe3aa5d5f570f63ddad814370374", size = 296113, upload-time = "2026-10-07T12:23:07.202Z" }, { url = "https://files.pythonhosted.org/packages/ab/18/0b9ffc597e69c5a1e20a7823cb60d54b39a9f54e91edcb8574f022186758/tomli-2.5.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f79203b3965b4000e91808aaa7c040206093f2b8bf86f455982f2274c9ccf442", size = 307725, upload-time = "2026-10-07T12:23:08.508Z" }, { url = "https://files.pythonhosted.org/packages/ab/c7/18f8baae0b5607a60e8e19b4a7fedee43a8ff6458e3896dcbbadeeac9c22/tomli-2.5.0-cp314-cp314t-win32.whl", hash = "sha256:91294a9fb94a75542f6e46e4a2ae709bd8d9b51134098cae5cf3bea5478b6d03", size = 108546, upload-time = "2026-10-07T12:23:09.956Z" }, { url = "https://files.pythonhosted.org/packages/72/34/4cca9739254130627bde87500b3f2b512154fe2f278efa7e2a5e10ad4bcb/tomli-2.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f15e3e0b835a6d68b10c86bf80a3149780498d6911c93c3ffd1861d19f9200f1", size = 117814, upload-time = "2026-10-07T12:23:11.486Z" }, { url = "https://files.pythonhosted.org/packages/7d/fb/afa530d47dd80a78fce43beac6bc6e00f84558eafcffbc6f37b21e80d056/tomli-2.5.0-cp314-cp314t-win_arm64.whl", hash = "sha256:6664b7ae7af7294256c53960a6103077f4914cec8ff98479c352f622c6f6b2f0", size = 115188, upload-time = "2026-10-07T12:23:12.728Z" }, { url = "https://files.pythonhosted.org/packages/66/98/316fdc00f8c0939e6fe50461dd343c162d3ad51d1286eb25b7db54361d50/tomli-2.5.0-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:a525685c2f97da40762b8695eb7aa0af4c8344ca1905c73e4e29cb04d34607dc", size = 162775, upload-time = "2026-10-07T12:23:13.941Z" }, { url = "https://files.pythonhosted.org/packages/c5/22/7b10fa5bb01c9539f53f69b619361b19350acc73657772ea7ac70ba309a8/tomli-2.5.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:9dbb18c1cfb2f6517942fc9314437f66aa06d94436ffb1f06102ef3572f35276", size = 161406, upload-time = "2026-10-07T12:23:15.215Z" }, { url = "https://files.pythonhosted.org/packages/9c/e7/1a069d86dfd20f1f84f71c63faed9f83c1d890bc06c27d82dc7d888fb573/tomli-2.5.0-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:752e8b1aa6a4367ef8bf6a1a1e005540f7ed055ba36d7193796812ca5404eb52", size = 273855, upload-time = "2026-10-07T12:23:16.471Z" }, { url = "https://files.pythonhosted.org/packages/ae/83/d1ef43d1687d092ab9c235455c76e6e709483b346b056f086095c7c263a5/tomli-2.5.0-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c47300f9bf791808f77d82747691c4bb09cb14bdf3060cca99b42cdc4361d5a7", size = 284910, upload-time = "2026-10-07T12:23:18.166Z" }, { url = "https://files.pythonhosted.org/packages/cc/05/f4d9cf7de61822ece0c3873f30d291e324911c71a378b8bfe5ced13fd9f5/tomli-2.5.0-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:19b0dd8749f4ea2f112c5fcfb3c5248390c899d7e2e173f1d91abee1fa0ff391", size = 277723, upload-time = "2026-10-07T12:23:19.355Z" }, { url = "https://files.pythonhosted.org/packages/42/28/78262493141fa543151cf005760c3cb01d09fc28a11f993c05109902cb8c/tomli-2.5.0-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:57b1c3b01fab802e2899bc3d168dca320e14165e2fd9fd584760fb4ca5826859", size = 285115, upload-time = "2026-10-07T12:23:20.698Z" }, { url = "https://files.pythonhosted.org/packages/1a/b9/e1dab9a30bcb677b5cc5cee810609cfd64f24306a3055767dd3fda00b1e0/tomli-2.5.0-cp315-cp315-win32.whl", hash = "sha256:667e521b37a6c5ccaa044202c235b530f90177ffe2cd4a64ecc213c7dd535feb", size = 103475, upload-time = "2026-10-07T12:23:21.941Z" }, { url = "https://files.pythonhosted.org/packages/4c/bd/31a3790c11d6ea95fcf5e6022ac0f8d0543c9b61120b730fc481bd43d3b4/tomli-2.5.0-cp315-cp315-win_amd64.whl", hash = "sha256:d747252933c8a65ef6bd8da0fbb7ce28a90eb6119d8cd00772cd528aa07b68d5", size = 114589, upload-time = "2026-10-07T12:23:23.098Z" }, { url = "https://files.pythonhosted.org/packages/47/a2/4f6310fa699364f0e3af7ee3af88dddd9af066d33e716a0265bbe2b3ea84/tomli-2.5.0-cp315-cp315-win_arm64.whl", hash = "sha256:75dbcde8751b0a960aa3de173aa5e894d590755c6d7758b7e774c06f1dc3cbdd", size = 111493, upload-time = "2026-10-07T12:23:24.233Z" }, { url = "https://files.pythonhosted.org/packages/68/14/00853f0b396d8971107ae1921bb5b322fdee1650d2f16bf06c20adb532e5/tomli-2.5.0-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:2419c2a189551987b59d80e63ec355671283336f41c6b9b89462df679c7d0c57", size = 171380, upload-time = "2026-10-07T12:23:25.512Z" }, { url = "https://files.pythonhosted.org/packages/89/ad/fa6949321dadee46b27363974fb197b94c911c3b0f7a5fd26d7dc18fc2a0/tomli-2.5.0-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:0dc598040da8d42cf20f0be588ed7004f46db12a0ac6c32e03a59dccedaaadcd", size = 170553, upload-time = "2026-10-07T12:23:26.855Z" }, { url = "https://files.pythonhosted.org/packages/53/aa/3056c919eb3e084df3752b2cf5f865dcc04af0b27dba2f66d7b28af4633a/tomli-2.5.0-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49096930c8d886c9bbdab62d2d0d17ce823ddeea522309a190b36245d5b49e01", size = 294428, upload-time = "2026-10-07T12:23:28.132Z" }, { url = "https://files.pythonhosted.org/packages/96/b2/faeeb5d8769ea3832021d73e892c8391eae7b4b4f8b55a789127bd8b18a9/tomli-2.5.0-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8ade5023067f99fe72b88accd30d0ea05a158e9e32a11f124e731ea9695313f", size = 304909, upload-time = "2026-10-07T12:23:29.381Z" }, { url = "https://files.pythonhosted.org/packages/f6/52/f094c09e73fb654b621716d019acb5d29bdfd1be01df80c281d552bda48d/tomli-2.5.0-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:b69564772b5c8f22ea5f498dff08cfa825045b4d4c4400529000bdf818aa3b2a", size = 293220, upload-time = "2026-10-07T12:23:30.608Z" }, { url = "https://files.pythonhosted.org/packages/86/f5/0c30541078ca4b505ce3bd76ed931facbfec524dd018535d691d1af0a6d2/tomli-2.5.0-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:8ff3a2ca028c7eee0c777f9a092038d0a594a9fa04e215f929a22c329e2cb142", size = 305705, upload-time = "2026-10-07T12:23:32.181Z" }, { url = "https://files.pythonhosted.org/packages/05/74/590e7d19d6a118fc5cc5704ff358e21d95b8573f6b9443b1519f29ca8825/tomli-2.5.0-cp315-cp315t-win32.whl", hash = "sha256:62fc1bc8eb03e3a9cadfca713d65614ed8e09d974a283295ffe3a831976b4dc5", size = 108432, upload-time = "2026-10-07T12:23:33.496Z" }, { url = "https://files.pythonhosted.org/packages/1c/b8/63a75cfb27a17c38550e44025d3a6e7be64516fd8608a3b75703bf37d81b/tomli-2.5.0-cp315-cp315t-win_amd64.whl", hash = "sha256:f3fcbc57b1791fa6cbe5d8434179d51de12be1a4811469529f47f6e7487a2571", size = 117281, upload-time = "2026-10-07T12:23:34.648Z" }, { url = "https://files.pythonhosted.org/packages/72/01/e8c1debb2173973372934c68fc8e46170ab60ef23ed4592dff4dec6e8993/tomli-2.5.0-cp315-cp315t-win_arm64.whl", hash = "sha256:d2ba24db8a9376921b5e87b4762b9adb0f3f1deaea68f2b8b0bb2c11efb9c3e7", size = 115069, upload-time = "2026-10-07T12:23:35.77Z" }, { url = "https://files.pythonhosted.org/packages/60/3f/3e3f8fd0919249b0200c80fbc4f9a1e70be19f9883da71dfb7f8b9ab8aca/tomli-2.5.0-py3-none-any.whl", hash = "sha256:32a7b79ac57a2e83670ce329ccf675798bc5a2094783a63676866b70503f2e2b", size = 14765, upload-time = "2026-10-07T12:23:36.875Z" }, ] [[package]] name = "torch" version = "2.14.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cuda-bindings", marker = "python_full_version < '3.15' and sys_platform == 'linux'" }, { name = "cuda-toolkit", extra = ["cublas", "cudart", "cufft", "cufile", "cupti", "curand", "cusolver", "cusparse", "nvjitlink", "nvrtc", "nvtx"], marker = "sys_platform == 'linux'" }, { name = "filelock" }, { name = "fsspec" }, { name = "jinja2" }, { name = "networkx", version = "3.6.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, { name = "networkx", version = "3.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, { name = "nvidia-cudnn-cu13", marker = "sys_platform == 'linux'" }, { name = "nvidia-cusparselt-cu13", marker = "sys_platform == 'linux'" }, { name = "nvidia-nccl-cu13", marker = "sys_platform == 'linux'" }, { name = "nvidia-nvshmem-cu13", marker = "sys_platform == 'linux'" }, { name = "setuptools" }, { name = "sympy" }, { name = "triton", marker = "python_full_version < '3.15' and sys_platform == 'linux'" }, { name = "typing-extensions" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/5d/9b/fd1cd143a7bda5abc1fc352ed7b431f6f52aa3c454293211a33656db2cb5/torch-2.14.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:b6074b130fd26bc50f5d171f07dfed70db22dd0c354ab34767729249f9e0f042", size = 127281154, upload-time = "2026-09-30T17:43:58.328Z" }, { url = "https://files.pythonhosted.org/packages/8d/0e/21281ff4015779255229f487f4481c5bfba53b8c83e01eaa4a8a8f1180c9/torch-2.14.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:ef1276fd07adb8d463ac402a24ea7482e45c9a42df8ebdac211aa757779200ba", size = 453982557, upload-time = "2026-09-30T17:44:52.656Z" }, { url = "https://files.pythonhosted.org/packages/aa/4f/7af6fbada912b3023cc79b6ab30f89234b258a9a373880ea52ed914a2ae9/torch-2.14.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:305a61f61f35f128579f299c5bd33d475f6a01c6307336139632e30856c4854d", size = 554581699, upload-time = "2026-09-30T17:49:10.777Z" }, { url = "https://files.pythonhosted.org/packages/fe/54/4e0a71376b2fb15aaf65ed9e6a4c8043d36f554338c6daabc63059a5e157/torch-2.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:0bd2fb0c4098856bc5af59fe5988bf38bdbcdb6550b44273c12ae425cb8ec17e", size = 124096268, upload-time = "2026-09-30T17:44:04.362Z" }, { url = "https://files.pythonhosted.org/packages/4b/3c/379349820e9a6e713826de3d0b88f07728541bdcabe2a3afd128871cdc4b/torch-2.14.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:420dbf314c180ee4b86e9bc00aee5746a7d6e5bacdd7df925af671ed393f0b2e", size = 127307099, upload-time = "2026-09-30T17:44:10.421Z" }, { url = "https://files.pythonhosted.org/packages/a4/3e/474930ab971e306957ec763b7df695d659179e15ccab9e7073d47ae14ce8/torch-2.14.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:0b13acde294b401509830d85a8906cbf2fc97425a12a66cce1d9fa13c5106a2a", size = 453998918, upload-time = "2026-09-30T17:52:45.134Z" }, { url = "https://files.pythonhosted.org/packages/ba/fd/c470857d0dfc5d4c94430658b3eed60fd5292b0bf596a8aae7b9fd66d674/torch-2.14.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:23011fe29a99b591eabb3a31a25080c62e2c2f0690a3c798744e5489dae50451", size = 554618695, upload-time = "2026-09-30T17:53:06.8Z" }, { url = "https://files.pythonhosted.org/packages/ad/1a/b9648b0d228e513f69f8453ec3f90a8d436d78ff6d85a2773e539f0c07cf/torch-2.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:38bee9f2a2ccfc6898172a5075e4ba52522fbe143eeb099674fc67ab390e858d", size = 124113906, upload-time = "2026-09-30T17:52:21.377Z" }, { url = "https://files.pythonhosted.org/packages/7d/11/faaca4f8541c45127b7e0d6bb141221fe944c8466d89986b8466c6c195f9/torch-2.14.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:dbe359d705f4d67236743794c296c6dee93a922fd8117eff8c3e880d7d0fb2b9", size = 127315286, upload-time = "2026-09-30T17:52:27.43Z" }, { url = "https://files.pythonhosted.org/packages/60/1f/0330275c705b846882531c64e80d32b13fb572eeb9b995e87e84154b0712/torch-2.14.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:6d530bd11479fb574567af3a1f384af9a77bf5bb9550cde8080b356ca7220d5a", size = 453999200, upload-time = "2026-09-30T17:53:21.716Z" }, { url = "https://files.pythonhosted.org/packages/7c/cc/bb579ac0c80e077c58204e43b37a254b74dea5873635100bea25789a55d4/torch-2.14.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:c8f71aabc67bcbfc9373dc131537a5968d04edce73e88add21354a7cd0a76985", size = 554618164, upload-time = "2026-09-30T17:53:42.73Z" }, { url = "https://files.pythonhosted.org/packages/7b/4b/32c00cacbe682a4c08d9c6c3e7a7116c912184cc7155f06c64f545db97d1/torch-2.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:711713391d26a1ce5e9fbc6c996d954a8c12e8825374cc77b809a6af29539b8c", size = 124113754, upload-time = "2026-09-30T17:52:33.474Z" }, { url = "https://files.pythonhosted.org/packages/43/19/23a1aed488423a5055727256b25406e4b93bd2bcf1352bef582b9951c10c/torch-2.14.1-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:cee091caf2a6229e248daf41d18ceebf590ba02d9179205610062c64ee5fef03", size = 127325330, upload-time = "2026-09-30T17:52:54.752Z" }, { url = "https://files.pythonhosted.org/packages/93/f4/94219ada13edd62fda1f976163292b7b8595f1fd2f4ef74af24b3baad375/torch-2.14.1-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:f68f5476e2bc0e8f60b74f7ca21acda885c4477af6392f8977e4f0d1ea1aa162", size = 454016297, upload-time = "2026-09-30T17:54:03.078Z" }, { url = "https://files.pythonhosted.org/packages/fd/df/23c69e9b9fd19fe6563422f1bc59f89601bda47234a89a1cf432cfde3aee/torch-2.14.1-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:1d4df07be7338bbcc4d54085adee21363c91314702b9bd4d78ef72ffac9465ba", size = 554621744, upload-time = "2026-09-30T17:54:22.951Z" }, { url = "https://files.pythonhosted.org/packages/d9/dc/a36a4431ab5e3ad168a75f341e24677a4bbbf0c5dda59c97a7079262bb94/torch-2.14.1-cp314-cp314-win_amd64.whl", hash = "sha256:d02a4c48a2ca5fb7654e36e71f710f74494d83f1f10aaff8e059dd554adca956", size = 124110781, upload-time = "2026-09-30T17:53:31.141Z" }, { url = "https://files.pythonhosted.org/packages/2d/bc/1afbd1a22f6023eafcdb9295ac1d97137a7816f54091d693701072da2218/torch-2.14.1-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:06c3ec25f3b497f9a73dc0c36f293f295cfe8d5584fd446238d9a501b30a66d5", size = 127657364, upload-time = "2026-09-30T17:53:53.837Z" }, { url = "https://files.pythonhosted.org/packages/e4/94/b97e863c9ceef2bc6e082e967cbfb9065b5e232f2a60c5af0f5115a1bc31/torch-2.14.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:9113f94f70429f9f302bf55b090b5411269083e8a72a5d015ffcc5a7f83f2c69", size = 453998592, upload-time = "2026-09-30T17:54:38.268Z" }, { url = "https://files.pythonhosted.org/packages/03/d8/8272157c438cc26a199a8fa0caf87985477b8a1ed8a09084eb2ae40609d8/torch-2.14.1-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:e65d5fe136e533b23c2d134377f7f126721c7c78dd75b3dbb735af082a8aeb85", size = 554578730, upload-time = "2026-09-30T17:54:54.838Z" }, { url = "https://files.pythonhosted.org/packages/45/05/451a69a4287033d8f106f5c65f92c2c0c37229d81ea101d4b047caf758cc/torch-2.14.1-cp314-cp314t-win_amd64.whl", hash = "sha256:e07306caa1de2a4ac1467e11ecfc92fc44f523dd6a521145039aef46d913963c", size = 124400129, upload-time = "2026-09-30T17:54:12.306Z" }, ] [[package]] name = "tqdm" version = "4.70.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0d/ea/b2a5bd54b28a324dae8211928b2d730b6547500342c7e6c6dea08bd0a485/tqdm-4.70.1.tar.gz", hash = "sha256:cefd0eca11b2a37a3aee776544d4f4ae913f02688135b5556b8788dfa474afc4", size = 171846, upload-time = "2026-09-11T07:25:16.601Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl", hash = "sha256:c293e525e6fef9c20e8728fd4612df02a0aa31bb5fe91ecd93e123b1b7bffa73", size = 80199, upload-time = "2026-09-11T07:25:14.599Z" }, ] [[package]] name = "traitlets" version = "5.16.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/2c/2e/a7fbfe268c8a3b32546930c0297c101d65a4a14c304ad5790a9f478f0e4e/traitlets-5.16.1.tar.gz", hash = "sha256:ed900c2b631aa3a112811139fa97b8d2c3bad5e989656bba4b7e52c7852c18c1", size = 166137, upload-time = "2026-08-03T08:32:36.848Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ad/66/0d785f0bc5e4315a96c989bb476d0fc07ea4f85132550c7b156ca2035d52/traitlets-5.16.1-py3-none-any.whl", hash = "sha256:f775618166caa0396c8e337099240f2bd3e5e917d203b2e6fbe21a58d3cb1f6b", size = 86211, upload-time = "2026-08-03T08:32:34.48Z" }, ] [[package]] name = "triton" version = "3.8.0" source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/a3/cf/d21c9b1a4d1df9ba3aed218069f24f762a4b9565c5a362bef6f110c08e72/triton-3.8.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:372285307d4c44ee74cee32de0b4f04bd157e071427e38c6f4ee3e3beb2194f4", size = 226467015, upload-time = "2026-08-28T16:08:05.871Z" }, { url = "https://files.pythonhosted.org/packages/6f/9a/2c3d3823726d5ad5359f7065b02b984925158b74611c1e3987f6a37461fb/triton-3.8.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:68988ac85d5e7086baeda0ddc175af9667db7529b3c5e11a5c0601b8bef2200a", size = 247945226, upload-time = "2026-08-28T15:55:43.795Z" }, { url = "https://files.pythonhosted.org/packages/87/07/0f8cd8e8db0472334253efdaaab3d0819fea27aa99bf0e7f1aeea4ceb5ae/triton-3.8.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a9c404c69ed4a39e8ec632eaf6b9fe058a060bf98979c177f6ef666f06bb8d50", size = 226474486, upload-time = "2026-08-28T16:08:18.29Z" }, { url = "https://files.pythonhosted.org/packages/c1/09/b7012e5bfae67640f268aa584caa80fe1674f6b0da949046b679972c33e3/triton-3.8.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e91ffa46d095b252248297292dd22bcbacd53a125a0c2eefbbbf74925a320bc3", size = 247972921, upload-time = "2026-08-28T15:55:53.157Z" }, { url = "https://files.pythonhosted.org/packages/87/4d/4c564374bcdadb166fccbf3e45aee0d4a473f88d341761bd2fefe3b8e8c1/triton-3.8.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b7004666652f500ed854a86988e4b3d69d247188b5d2092b5df1e44f4a954099", size = 226476793, upload-time = "2026-08-28T16:08:30.956Z" }, { url = "https://files.pythonhosted.org/packages/b0/b6/3394d5548404c1cabd1dadadd28d0b3f9478db1dff8180da53bb3f0a1e19/triton-3.8.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f0497218e26b7d79773ad9c2a3fa3b539ee69f587a13fac2e552b1d322a8015", size = 247975122, upload-time = "2026-08-28T15:56:04.112Z" }, { url = "https://files.pythonhosted.org/packages/b8/59/bf0e9493118bb353ab59a5d6a65db3618d9b314417cc1459f0121e0ec5c9/triton-3.8.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f6b48d0591929a3867973acac3dccd4e058585f91bfb41022de496c9ffab304", size = 226488654, upload-time = "2026-08-28T16:08:47.141Z" }, { url = "https://files.pythonhosted.org/packages/93/d9/08c75f3459f19ad00425b564058e40efa4bcd79b816064cf27499303ea42/triton-3.8.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:387dae4cb0089a7b6ba1a428ae0782b65c4c58f57d94617cb22ca8593d8ccbca", size = 247972313, upload-time = "2026-08-28T15:56:14.007Z" }, { url = "https://files.pythonhosted.org/packages/7c/34/429c5592181cfb7361a0a8e0bff218e7224b726709d75da2472b3e819f70/triton-3.8.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b84e7d512490ba529111260fa6f7cad8b254a6bb5fbdf41d5ef9a5e57f52d0a", size = 226591133, upload-time = "2026-08-28T16:09:02.271Z" }, { url = "https://files.pythonhosted.org/packages/fe/d1/aa8a3e935c37efee7945984fdb64d7e0851bf6d920afd97b2d21f9d23360/triton-3.8.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:74217bb56ed8692759227758e4c4b3bd2d608a209c1a7a081bf361fb4c2c1bf9", size = 248077577, upload-time = "2026-08-28T15:56:24.94Z" }, ] [[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.5" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d9/68/f1b440335057bfce71b6e50a9d09445aa2ecbd08359a337976627b8409e7/tzdata-2026.5.tar.gz", hash = "sha256:8cc73c0a0bfca7dbfa59235d60b2eff82231dee33f53d206db1acd9173cfc0a7", size = 200404, upload-time = "2026-10-03T09:23:14.143Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/94/21/1e5995a1c920cce14e4bffae20c665ec10e7ed03ab25e006cd741092b718/tzdata-2026.5-py2.py3-none-any.whl", hash = "sha256:b683bd1b6659ddcd810ff02ad09ba821d4bf1065072805063eb35c49617905ac", size = 347996, upload-time = "2026-10-03T09:23:12.535Z" }, ] [[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 = "virtualenv" version = "21.14.11" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "distlib" }, { name = "filelock" }, { name = "packaging" }, { name = "platformdirs" }, { name = "python-discovery" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7f/be/4d1d59d309db76b5808fcfd78bd5996f4e7241366691c38fc331a3136398/virtualenv-21.14.11.tar.gz", hash = "sha256:593052d8477ea8c55a842387ce111bd08c72618f0c1133c302cafe335e570a57", size = 5503091, upload-time = "2026-10-18T07:06:34.716Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ce/6b/d85da8982b41190eafcb9df91dff9d83fc6989e98af4b5be4c8f85510c95/virtualenv-21.14.11-py3-none-any.whl", hash = "sha256:b319f8590a84e5de5f8f2c803ecd2237e9bc0ffa7c1e875e3169c107cecb7454", size = 5495268, upload-time = "2026-10-18T07:06:32.719Z" }, ] [[package]] name = "wcwidth" version = "0.9.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/69/4a/82d61476a1ccc20d43d0805724c5de4baa4971131a8db1816705ef53fe16/wcwidth-0.9.3.tar.gz", hash = "sha256:dfe7cfbd4cb59db9fe0931bd6091ab4a95b3acc5d56bfb50fa9fef0ccba5dc5c", size = 956320, upload-time = "2026-10-20T16:02:43.488Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/5c/6d/eec61b5edeb88e3ea2a714184eade38335722c4246d94be567977fc20caa/wcwidth-0.9.3-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:3b119ef60177a92b4f298b80e98464c2922a1fba3ed77fe9a2bcb69edf1b9af4", size = 605400, upload-time = "2026-10-20T16:02:02.523Z" }, { url = "https://files.pythonhosted.org/packages/8b/3c/714eba03905a23a46277cc96d3db8da6bd22d2cc0d09a4dead60a2bd1757/wcwidth-0.9.3-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:aab90ab489850f87633922c3064f6d0442d8f6ae5407a62f82bdb1f424179c05", size = 610124, upload-time = "2026-10-20T16:02:07.256Z" }, { url = "https://files.pythonhosted.org/packages/90/ad/8566e7cc712bea55eab0bb6d19581b7c727a58fcdd55f02365b309aaaccd/wcwidth-0.9.3-cp310-abi3-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:9e1cbe18c18d152e1e68e4e2561dab6c2bc988f8fd337a1fb2e1e0809c3fa568", size = 762700, upload-time = "2026-10-20T16:02:17.508Z" }, { url = "https://files.pythonhosted.org/packages/ea/7a/4e26574d032a1709bb1fd7d95d406b7b8f87363c60305a101e6e2d9285f5/wcwidth-0.9.3-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c12abd75ffcbad417e7770a6feb82413c102ccce5c435068c39a82e2218b00b3", size = 771850, upload-time = "2026-10-20T16:02:11.553Z" }, { url = "https://files.pythonhosted.org/packages/b8/d6/48dad66d577417ef8594000506fa8619d45d7282e20b4cdc916fcc68f95a/wcwidth-0.9.3-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9ab8bfee107e08de09e15f9f6afb9fe0f64c8d64fd296d0d8557bafe71ea3f93", size = 770047, upload-time = "2026-10-20T16:02:19.092Z" }, { url = "https://files.pythonhosted.org/packages/3f/61/5f1e02e588d289837d5312478cc9f0e7bca93f4c8a77807741f79fb6a31c/wcwidth-0.9.3-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2f875a4c9e62df2ecfa70d99b24c551f2245609858e179c3a40e74631b2d08a4", size = 782210, upload-time = "2026-10-20T16:02:12.753Z" }, { url = "https://files.pythonhosted.org/packages/e9/11/0da2720cba3f917148448c9bf73f3079d71f918308ee9e4d737a0b7acfd8/wcwidth-0.9.3-cp310-abi3-musllinux_1_2_i686.whl", hash = "sha256:70a2ca239b85a219324968993c76c117fe423d4e1a7c9d860c999c66192f2570", size = 783172, upload-time = "2026-10-20T16:02:20.663Z" }, { url = "https://files.pythonhosted.org/packages/f2/f6/b79407036ca4543bf708a6d4ca561f78620dc1e5443e685e094480c37753/wcwidth-0.9.3-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:537ea00b6792bb243cd09582322c54dbc848879e5d34ea4c5fee0147529685ab", size = 784806, upload-time = "2026-10-20T16:02:22.164Z" }, { url = "https://files.pythonhosted.org/packages/3c/86/ada6c2244b08a86c871d42f7cd85b5226515b5f3fa7e604d1e6e45590275/wcwidth-0.9.3-cp310-abi3-win32.whl", hash = "sha256:f2f943c4ef14e9baba730740265f4e5bf5fc8473550e36cd92828cd5663561a6", size = 593154, upload-time = "2026-10-20T16:02:34.301Z" }, { url = "https://files.pythonhosted.org/packages/5b/6e/46363d972b2b9f002fbfc3bf8e9ab0ff89f139c935a5f21d22016e7a2018/wcwidth-0.9.3-cp310-abi3-win_amd64.whl", hash = "sha256:569a0cdb826d3097b6dbacfaa45aa0002d72a2ba6fa8a63251ea43ac4dd7b6a4", size = 597685, upload-time = "2026-10-20T16:02:35.748Z" }, { url = "https://files.pythonhosted.org/packages/69/3d/5583cac85e233514c3906d5476b6a74160bc4dc82729dabef3485dbf3d52/wcwidth-0.9.3-cp310-abi3-win_arm64.whl", hash = "sha256:80557db1f77148b78e1b3c2a9cc4ebc4feabef42aaf69a555565057031c32367", size = 598774, upload-time = "2026-10-20T16:02:30.016Z" }, { url = "https://files.pythonhosted.org/packages/91/b2/53e0838babc6b87505b9504ce62b72c79403642f88d3e568e05d0ef04825/wcwidth-0.9.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:6f3e855d3a09af8b7b6d56e76bc270681032f8a37d527a8d5707a441958e3730", size = 606640, upload-time = "2026-10-20T16:02:04.01Z" }, { url = "https://files.pythonhosted.org/packages/f0/fb/27c94facff5c4a39b954a41fac20c238647f0aad32452d0d9e33fc05e852/wcwidth-0.9.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1bbc8ebf133422cadfefea95a9f89d6c9e9a1ae19930bef7862a9b59b20bbad", size = 610956, upload-time = "2026-10-20T16:02:08.764Z" }, { url = "https://files.pythonhosted.org/packages/38/61/38e6236356d25966d34636ef6f49ee83a66513e051c4a3b1e19c8b9ec806/wcwidth-0.9.3-cp314-cp314t-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:7a95d8c784cbccbbcb808eaadfd156cd282b2bdd95e89b32505e3443381ce61d", size = 775967, upload-time = "2026-10-20T16:02:23.765Z" }, { url = "https://files.pythonhosted.org/packages/7b/87/c8f9295cd14a058dc27be0360fcc5ec70ce71b0d2e6a018871f585f23126/wcwidth-0.9.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a44acbb23b525070a0b8c343dd7cab7a4020aff73b38804f7a66d6a66e16e3fc", size = 787147, upload-time = "2026-10-20T16:02:14.095Z" }, { url = "https://files.pythonhosted.org/packages/c6/c0/238c135e283b1b0e16fef8b082d432dda1fe7e568d6dd85d5c7fc5e83859/wcwidth-0.9.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a7c0405a3bf3c564e481d6b2d55c99cc231bb68cf8f4a0995944bbce5ebf1a5d", size = 784548, upload-time = "2026-10-20T16:02:25.189Z" }, { url = "https://files.pythonhosted.org/packages/a1/ed/33e3080fe32f6f8f86334b2c5adde243b9a3a3a46cef97694dbed73b9dc4/wcwidth-0.9.3-cp314-cp314t-win32.whl", hash = "sha256:457f986e4867111cb037ccbf0d97ae100b1ecad030d43a020e7207f1e29649d5", size = 600761, upload-time = "2026-10-20T16:02:37.097Z" }, { url = "https://files.pythonhosted.org/packages/27/62/6684a59147c1f86d58d0138f3109f506a6761b815dcb3d86b74d9af3a723/wcwidth-0.9.3-cp314-cp314t-win_amd64.whl", hash = "sha256:f11789e520ade8017fa93b01a4b8985571bb433eaefc2f857b57e36875e2e1d8", size = 605316, upload-time = "2026-10-20T16:02:38.513Z" }, { url = "https://files.pythonhosted.org/packages/94/24/3ebcfd772d273e43e28447dd1946d88b8625db57b6a23496ea4eb9e1dbb7/wcwidth-0.9.3-cp314-cp314t-win_arm64.whl", hash = "sha256:eef39f3260991d8767189d296f0116fa4b45ad9c3a9a16d5af9187fb66b27564", size = 606392, upload-time = "2026-10-20T16:02:31.333Z" }, { url = "https://files.pythonhosted.org/packages/76/fe/f90b9444bbc2d566634f91756bd11c2bd39d50c2c9077551711b10d8d03f/wcwidth-0.9.3-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:52a13869704d43a4add59c68ebc892198e53063883114783bf0b7457e250e3f4", size = 606655, upload-time = "2026-10-20T16:02:05.816Z" }, { url = "https://files.pythonhosted.org/packages/ab/63/edffb23938f4e27c28400c7d8d5a8715381d77f5db96bf80cf5dd6687f88/wcwidth-0.9.3-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:9470169fcb4e5340269175ebb3642dd5bfc8f82da8c86f29fc1fefc6c2b9bc1b", size = 611217, upload-time = "2026-10-20T16:02:10.252Z" }, { url = "https://files.pythonhosted.org/packages/f9/e6/0e4b5c81c238fac47eb66902f058a39ccdeacd7b2c5ab0c559066f203262/wcwidth-0.9.3-cp315-cp315t-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:c4531d93344441a7948e665854f0c40e3a8342ee106436d1531efa7a9fa7641e", size = 778155, upload-time = "2026-10-20T16:02:27.141Z" }, { url = "https://files.pythonhosted.org/packages/f2/16/745439326544b2a6d65facbdf8462ee9d31e09c64830a764d2526c6c80d6/wcwidth-0.9.3-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:658dcbce546e7f28ee361f88e4a8e591dd56f46bff6084e11b4ad8310ed99946", size = 786757, upload-time = "2026-10-20T16:02:15.569Z" }, { url = "https://files.pythonhosted.org/packages/08/a4/47193dc9902c30e187d81feaa7a5bc2672c41fe07093ca1ce5381395b85c/wcwidth-0.9.3-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e9362be098c43d076aa43754face3cc0180fa81cea9ba304240b15490f2617e8", size = 785088, upload-time = "2026-10-20T16:02:28.784Z" }, { url = "https://files.pythonhosted.org/packages/11/6a/9727002b938c28ab4456fc43ba31a3159ebff040021ce8dbd70e904c7cc9/wcwidth-0.9.3-cp315-cp315t-win32.whl", hash = "sha256:16d09df90b3a8f799ea14c726a41d9b906c3104f95f46d158e1ebe45cf4d547b", size = 600787, upload-time = "2026-10-20T16:02:39.766Z" }, { url = "https://files.pythonhosted.org/packages/7c/db/0e24c2ff1e82cf298dd40a29e022da31b79be2589f0b8d865488e49140e1/wcwidth-0.9.3-cp315-cp315t-win_amd64.whl", hash = "sha256:3e3e31d6c17d6da3051f7eb854d5e4bebdc52a08a7a52adc2da6f15af51304e8", size = 605298, upload-time = "2026-10-20T16:02:41.479Z" }, { url = "https://files.pythonhosted.org/packages/84/71/b470bd1dec14cbe6cee0c2e142787a8d99ac01711d5a1b533dda90754b48/wcwidth-0.9.3-cp315-cp315t-win_arm64.whl", hash = "sha256:5d3b0b6c37f40e8d8298941ec373a426a892bb9a514328abcc9226cdc60ae6eb", size = 606346, upload-time = "2026-10-20T16:02:32.662Z" }, { url = "https://files.pythonhosted.org/packages/bf/12/e10aad98050389ef674c9f69409e38ae086c2104912644e1f9143b394301/wcwidth-0.9.3-py3-none-any.whl", hash = "sha256:e3c9069c54a2da0bf4f6c7e65a735cb1da0f47601a15cb5fef7e4b6ffca4cf60", size = 301629, upload-time = "2026-10-20T16:02:00.861Z" }, ]