From 0834f80cd6cca44342e2faa6b4192a5a4c6e26b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20S=C3=A1nchez-Gallego?= Date: Mon, 29 Dec 2025 20:51:38 -0800 Subject: [PATCH 1/9] Mostly blank slate for v3 with stub documentation --- .gitignore | 2 + CHANGELOG.md | 143 ++ CHANGELOG.rst | 178 --- cookiecutter.json | 20 - docs/sphinx/Makefile | 20 - docs/sphinx/_static/custom.css | 100 +- docs/sphinx/_static/pygments.css | 77 - docs/sphinx/_templates/layout.html | 5 - docs/sphinx/changelog.md | 4 + docs/sphinx/changelog.rst | 2 - docs/sphinx/conf.py | 353 +---- docs/sphinx/index.rst | 472 +----- docs/sphinx/requirements.txt | 7 + docs/sphinx/requirements_template_docs.txt | 3 - docs/sphinx/standards.rst | 3 - docs/sphinx/v1/v1.rst | 316 ---- hooks/post_gen_project.py | 127 -- hooks/pre_gen_project.py | 15 - noxfile.py | 49 + pyproject.toml | 52 + readthedocs.yml | 21 +- STYLE.rst => style/STYLE_v1.rst | 6 +- style/STYLE_v2.md | 3 + uv.lock | 1385 +++++++++++++++++ .../.github/workflows/test.yml | 61 - {{cookiecutter.repo_name}}/.gitignore | 115 -- {{cookiecutter.repo_name}}/.pylintrc | 425 ----- {{cookiecutter.repo_name}}/.travis.yml | 38 - {{cookiecutter.repo_name}}/CHANGELOG.rst | 27 - {{cookiecutter.repo_name}}/CODEOWNERS | 38 - {{cookiecutter.repo_name}}/LICENSE.md | 29 - {{cookiecutter.repo_name}}/README.md | 8 - .../bin/{{cookiecutter.package_name}} | 41 - {{cookiecutter.repo_name}}/cextern/README.txt | 1 - .../docs/sphinx/CHANGELOG.rst | 2 - .../docs/sphinx/Makefile | 20 - .../docs/sphinx/_static/custom.css | 43 - .../docs/sphinx/_static/custom_bootstrap.css | 107 -- .../docs/sphinx/_static/favicon.ico | Bin 1150 -> 0 bytes .../docs/sphinx/_static/favicon_sdssv.ico | Bin 1150 -> 0 bytes .../docs/sphinx/_static/sdss_logo.png | Bin 24816 -> 0 bytes .../docs/sphinx/_static/sdssv_logo.png | Bin 42239 -> 0 bytes .../docs/sphinx/_static/sdssv_logo_small.png | Bin 7404 -> 0 bytes .../docs/sphinx/_templates/fulltoc.html | 3 - .../docs/sphinx/_templates/layout.html | 3 - .../docs/sphinx/api.rst | 15 - .../docs/sphinx/conf.py | 326 ---- .../docs/sphinx/index.rst | 35 - .../docs/sphinx/intro.rst | 7 - .../docs/sphinx/requirements.txt | 1 - {{cookiecutter.repo_name}}/etc/config.ini | 8 - .../etc/{{cookiecutter.package_name}}.module | 74 - {{cookiecutter.repo_name}}/poetry/.flake8 | 11 - {{cookiecutter.repo_name}}/poetry/__main__.py | 46 - {{cookiecutter.repo_name}}/poetry/build.py | 26 - .../poetry/create_setup.py | 59 - .../poetry/pyproject.toml | 87 -- .../__init__.py | 18 - .../etc/{{cookiecutter.package_name}}.yml | 9 - .../exceptions.py | 74 - .../main.py | 82 - {{cookiecutter.repo_name}}/readthedocs.yml | 11 - .../setup_cfg/MANIFEST.in | 2 - .../setup_cfg/setup.cfg | 109 -- {{cookiecutter.repo_name}}/setup_cfg/setup.py | 9 - {{cookiecutter.repo_name}}/tests/__init__.py | 0 {{cookiecutter.repo_name}}/tests/conftest.py | 11 - {{cookiecutter.repo_name}}/tests/test_main.py | 17 - 68 files changed, 1754 insertions(+), 3607 deletions(-) create mode 100644 CHANGELOG.md delete mode 100644 CHANGELOG.rst delete mode 100644 cookiecutter.json delete mode 100644 docs/sphinx/Makefile delete mode 100644 docs/sphinx/_static/pygments.css delete mode 100644 docs/sphinx/_templates/layout.html create mode 100644 docs/sphinx/changelog.md delete mode 100644 docs/sphinx/changelog.rst create mode 100644 docs/sphinx/requirements.txt delete mode 100644 docs/sphinx/requirements_template_docs.txt delete mode 100644 docs/sphinx/standards.rst delete mode 100644 docs/sphinx/v1/v1.rst delete mode 100644 hooks/post_gen_project.py delete mode 100644 hooks/pre_gen_project.py create mode 100644 noxfile.py create mode 100644 pyproject.toml rename STYLE.rst => style/STYLE_v1.rst (99%) create mode 100644 style/STYLE_v2.md create mode 100644 uv.lock delete mode 100644 {{cookiecutter.repo_name}}/.github/workflows/test.yml delete mode 100644 {{cookiecutter.repo_name}}/.gitignore delete mode 100644 {{cookiecutter.repo_name}}/.pylintrc delete mode 100644 {{cookiecutter.repo_name}}/.travis.yml delete mode 100644 {{cookiecutter.repo_name}}/CHANGELOG.rst delete mode 100644 {{cookiecutter.repo_name}}/CODEOWNERS delete mode 100644 {{cookiecutter.repo_name}}/LICENSE.md delete mode 100644 {{cookiecutter.repo_name}}/README.md delete mode 100755 {{cookiecutter.repo_name}}/bin/{{cookiecutter.package_name}} delete mode 100644 {{cookiecutter.repo_name}}/cextern/README.txt delete mode 100644 {{cookiecutter.repo_name}}/docs/sphinx/CHANGELOG.rst delete mode 100644 {{cookiecutter.repo_name}}/docs/sphinx/Makefile delete mode 100644 {{cookiecutter.repo_name}}/docs/sphinx/_static/custom.css delete mode 100644 {{cookiecutter.repo_name}}/docs/sphinx/_static/custom_bootstrap.css delete mode 100644 {{cookiecutter.repo_name}}/docs/sphinx/_static/favicon.ico delete mode 100644 {{cookiecutter.repo_name}}/docs/sphinx/_static/favicon_sdssv.ico delete mode 100644 {{cookiecutter.repo_name}}/docs/sphinx/_static/sdss_logo.png delete mode 100644 {{cookiecutter.repo_name}}/docs/sphinx/_static/sdssv_logo.png delete mode 100644 {{cookiecutter.repo_name}}/docs/sphinx/_static/sdssv_logo_small.png delete mode 100644 {{cookiecutter.repo_name}}/docs/sphinx/_templates/fulltoc.html delete mode 100644 {{cookiecutter.repo_name}}/docs/sphinx/_templates/layout.html delete mode 100644 {{cookiecutter.repo_name}}/docs/sphinx/api.rst delete mode 100644 {{cookiecutter.repo_name}}/docs/sphinx/conf.py delete mode 100644 {{cookiecutter.repo_name}}/docs/sphinx/index.rst delete mode 100644 {{cookiecutter.repo_name}}/docs/sphinx/intro.rst delete mode 100644 {{cookiecutter.repo_name}}/docs/sphinx/requirements.txt delete mode 100644 {{cookiecutter.repo_name}}/etc/config.ini delete mode 100644 {{cookiecutter.repo_name}}/etc/{{cookiecutter.package_name}}.module delete mode 100644 {{cookiecutter.repo_name}}/poetry/.flake8 delete mode 100644 {{cookiecutter.repo_name}}/poetry/__main__.py delete mode 100644 {{cookiecutter.repo_name}}/poetry/build.py delete mode 100644 {{cookiecutter.repo_name}}/poetry/create_setup.py delete mode 100644 {{cookiecutter.repo_name}}/poetry/pyproject.toml delete mode 100644 {{cookiecutter.repo_name}}/python/{{cookiecutter.package_name|lower}}/__init__.py delete mode 100644 {{cookiecutter.repo_name}}/python/{{cookiecutter.package_name|lower}}/etc/{{cookiecutter.package_name}}.yml delete mode 100644 {{cookiecutter.repo_name}}/python/{{cookiecutter.package_name|lower}}/exceptions.py delete mode 100644 {{cookiecutter.repo_name}}/python/{{cookiecutter.package_name|lower}}/main.py delete mode 100644 {{cookiecutter.repo_name}}/readthedocs.yml delete mode 100644 {{cookiecutter.repo_name}}/setup_cfg/MANIFEST.in delete mode 100644 {{cookiecutter.repo_name}}/setup_cfg/setup.cfg delete mode 100644 {{cookiecutter.repo_name}}/setup_cfg/setup.py delete mode 100644 {{cookiecutter.repo_name}}/tests/__init__.py delete mode 100644 {{cookiecutter.repo_name}}/tests/conftest.py delete mode 100644 {{cookiecutter.repo_name}}/tests/test_main.py diff --git a/.gitignore b/.gitignore index f2f5437..f81e90c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,8 @@ __pycache__/ # C extensions *.so +.DS_Store + # Distribution / packaging .Python env/ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..031caca --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,143 @@ +# Change Log + +This document records the main changes to the `python-template` code. + +## main + +[View commits since the last tag](https://github.com/sdss/python_template/compare/2.1.0...HEAD) + + +## 2.1.0 (2021-03-24) + +### πŸš€ Added + +* GitHub workflow for testing. + +### ✨ Changed + +* Updated dependencies. +* Removed the requirements `docs` extra. Instead, documentation extra packages are defined in a `requirements.txt` in `docs/sphinx` and automatically installed in the RTD build. + +### πŸ”§ Fixed + +* Link to the standards in the README. + +[View commits](https://github.com/sdss/python_template/compare/2.0.0...2.1.0) + + +## 2.0.0 (2020-04-13) + +### ✨ Changed + +* Dropped support for Python 2. +* Move style guide to root level. +* Use `setup.cfg` for packaging and configuration of `pytest`, `flake8`, `isort`, and `coverage`. +* Move `tests` outside of the package to simplify packaging. +* Replace `utils` with [sdsstools](https://github.com/sdss/sdsstools). +* Remove use of `bumpversion`. Instead, get the package version using `sdsstools.get_package_version`. +* Updated the template Sphinx docs. +* Updated style guide and documentation. +* Allow to choose between setuptools and poetry. +* Allow to choose between `sphinx-bootstrap-theme` and `alabaster`. + +[View commits](https://github.com/sdss/python_template/compare/1.0.6...2.0.0) + + +## 1.0.6 (2019-12-31) + +### πŸš€ Added + +* Avoid connecting more than one console handler to the warnings log. + +### πŸ”§ Fixed + +* Do not modify the record when formatting it, in case that record is also output in other handlers. + +[View commits](https://github.com/sdss/python_template/compare/1.0.5...1.0.6) + + +## 1.0.5 (2019-05-13) + +### Backward incompatible changes + +* The default path for the user configuration file is now `~/.config//.yml`. + +### πŸš€ Added + +* Better handling of configuration files. An environment variable `$_CONFIG_PATH` (e.g., `$MYPYTHON_CONFIG_PATH`) can be defined to point to the user configuration file. If defined, this path overrides the default location. + +### ✨ Changed + +* Modified logger to deal with warnings. Added critical level printing. Fixes #12 and #13. + +### πŸ”§ Fixed + +* Bug causing Python 2.7 templates to fail because `PercentStyle` is not available in `logging` module (thanks to @andycasey). + +[View commits](https://github.com/sdss/python_template/compare/1.0.4...1.0.5) + + +## 1.0.4 (2019-01-18) + +### ✨ Changed + +* Updated year in template to 2019. + +### πŸ”§ Fixed + +* More fixes to quotes in `module-whatis` in module file. + +[View commits](https://github.com/sdss/python_template/compare/1.0.3...1.0.4) + + +## 1.0.3 (2018-12-10) + +### πŸ”§ Fixed + +* Quotes in `module-whatis` in module file. + +[View commits](https://github.com/sdss/python_template/compare/1.0.2...1.0.3) + + +## 1.0.2 (2018-10-01) + +### πŸ”§ Fixed + +* Remove `from __future__ import unicode_literals` that made the package install fail under Python 2. See [#9](https://github.com/sdss/python_template/issues/9) for details. + +[View commits](https://github.com/sdss/python_template/compare/1.0.1...1.0.2) + + +## 1.0.1 (2018-07-30) + +### πŸš€ Added + +* Added W0621 to disabled list in pylint. + +### ✨ Changed + +* Changed documentation font size. +* Modified code and readthedocs configuration to use Python 3.6. +* Remove logger warning monkeypatching since it conflicted when used with packages that provide a similar monkeypatching. Replaced with a custom `logging.warning` method that produces coloured warning output. +* The `package_name` specified when cookiecutting the template is applied in lowercase when creating the package but in ucfirst case when creating classes. +* Renamed `misc` to `utils`. + +### πŸ”§ Fixed + +* Problem importing matplotlib in docs. +* A typo in the definition of the warning format in the logger. +* A typo in the definition of the API exception. + +[View commits](https://github.com/sdss/python_template/compare/1.0.0...1.0.1) + + +## 1.0.0 (2018-01-31) + +### πŸš€ Added + +* Initial release. +* Includes Travis CI, Read The Docs, Coverage, and Bumpversion integrations. +* Includes a logger and configuration library. +* Examples for Sphinx documentation and pytest. + +[View commits](https://github.com/sdss/python_template/compare/b726b904a601fe051b9db8dfd24fee59f70bc866...1.0.0) diff --git a/CHANGELOG.rst b/CHANGELOG.rst deleted file mode 100644 index b250906..0000000 --- a/CHANGELOG.rst +++ /dev/null @@ -1,178 +0,0 @@ -.. _python-template-changelog: - -========== -Change Log -========== - -This document records the main changes to the python-template code. - - -.. _python-template-main: - -main ----- - -`View commits since the last tag `__. - - -.. _python-template-2.1.0: - -2.1.0 (2021-03-24) ------------------- - -Added -^^^^^ -* GitHub workflow for testing. - -Changed -^^^^^^^ -* Updated dependencies. -* Removed the requirements ``docs`` extra. Instead, documentation extra packages are defined in a ``requirements.txt`` in ``docs/sphinx`` and automatically installed in the RTD build. - -Fixed -^^^^^ -* Link to the standards in the README. - -`View commits `__. - - -.. _python-template-2.0.0: - -2.0.0 (2020-04-13) ------------------- - -Changed -^^^^^^^ -* Dropped support for Python 2. -* Move style guide to root level. -* Use ``setup.cfg`` for packaging and configuration of ``pytest``, ``flake8``, ``isort``, and ``coverage``. -* Move ``tests`` outside of the package to simplify packaging. -* Replace ``utils`` with `sdsstools `__. -* Remove use of ``bumpversion``. Instead, get the package version using ``sdsstools.get_package_version``. -* Updated the template Sphinx docs. -* Updated style guide and documentation. -* Allow to choose between setuptools and poetry. -* Allow to choose between ``sphinx-bootstrap-theme`` and ``alabaster``. - -`View commits `__. - - -.. _python-template-1.0.6: - -1.0.6 (2019-12-31) ------------------- - -Added -^^^^^ -* Avoid connecting more than one console handler to the warnings log. - -Fixed -^^^^^ -* Do not modify the record when formatting it, in case that record is also output in other handlers. - -`View commits `__. - - -.. _python-template-1.0.5: - -1.0.5 (2019-05-13) ------------------- - -Backward incompatible changes -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -* The default path for the user configuration file is now ``~/.config//.yml``. - -Added -^^^^^ -* Better handling of configuration files. An environment variable ``$_CONFIG_PATH`` (e.g., ``$MYPYTHON_CONFIG_PATH``) can be defined to point to the user configuration file. If defined, this path overrides the default location. - -Changed -^^^^^^^ -* Modified logger to deal with warnings. Added critical level printing. Fixes :issue:`12,13`. - -Fixed -^^^^^ -* Bug causing Python 2.7 templates to fail because ``PercentStyle`` is not available in ``logging`` module (thanks to :user:`andycasey`). - -`View commits `__. - - -.. _python-template-1.0.4: - -1.0.4 (2019-01-18) ------------------- - -Changed -^^^^^^^ -* Updated year in template to 2019. - -Fixed -^^^^^ -* More fixes to quotes in ``module-whatis`` in module file. - -`View commits `__. - - -.. _python-template-1.0.3: - -1.0.3 (2018-12-10) ------------------- - -Fixed -^^^^^ -* Quotes in ``module-whatis`` in module file. - -`View commits `__. - - -.. _python-template-1.0.2: - -1.0.2 (2018-10-01) ------------------- - -Fixed -^^^^^ -* Remove ``from __future__ import unicode_literals`` that made the package install fail under Python 2. See `#9 `__ for details. - -`View commits `__. - - -.. _python-template-1.0.1: - -1.0.1 (2018-07-30) ------------------- - -Added -^^^^^ -* Added W0621 to disabled list in pylint. - -Changed -^^^^^^^ -* Changed documentation font size. -* Modified code and readthedocs configuration to use Python 3.6. -* Remove logger warning monkeypatching since it conflicted when used with packages that provide a similar monkeypatching. Replaced with a custom ``logging.warning`` method that produces coloured warning output. -* The ``package_name`` specified when cookiecutting the template is applied in lowercase when creating the package but in ucfirst case when creating classes. -* Renamed ``misc`` to ``utils``. - -Fixed -^^^^^ -* Problem importing matplotlib in docs. -* A typo in the definition of the warning format in the logger. -* A typo in the definition of the API exception. - -`View commits `__. - - -.. _python-template-1.0.0: - -1.0.0 (2018-01-31) ------------------- - -Added -^^^^^ -* Initial release. -* Includes Travis CI, Read The Docs, Coverage, and Bumpversion integrations. -* Includes a logger and configuration library. -* Examples for Sphinx documentation and pytest. - -`View commits `__. diff --git a/cookiecutter.json b/cookiecutter.json deleted file mode 100644 index 248b13d..0000000 --- a/cookiecutter.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "full_name": "John Doe", - "email": "myemail@here.com", - "package_name": "myproject", - "repo_name": "{{ cookiecutter.package_name }}", - "pip_name": "sdss-{{ cookiecutter.package_name }}", - "version": "0.1.0-alpha.0", - "year": "{% now 'utc', '%Y' %}", - "short_description": "Simple Template package for creating SDSS Python projects", - "packaging_system": ["setuptools", "poetry"], - "sphinx_template": ["sphinx-bootstrap", "alabaster"], - "use_releases": ["no", "yes"], - "create_git_repo": ["yes", "no"], - "exists_on_github": ["no", "yes"], - "github_organisation": "sdss", - "_copy_without_render": [ - "*/_templates/*.html", - ".github/workflows/*" - ] -} diff --git a/docs/sphinx/Makefile b/docs/sphinx/Makefile deleted file mode 100644 index 5145a85..0000000 --- a/docs/sphinx/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = python -msphinx -SPHINXPROJ = BMO -SOURCEDIR = . -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/sphinx/_static/custom.css b/docs/sphinx/_static/custom.css index c400728..9ea0f78 100644 --- a/docs/sphinx/_static/custom.css +++ b/docs/sphinx/_static/custom.css @@ -1,107 +1,43 @@ -body { color: #444444 !important; font-size: 14px} - -div.custom-warning { - background-color: #f7c589; - border-color: #f7c589; -} - -div.custom-warning { - background-color: #f7c589; - border-color: #f7c589; -} +/* This is the custom CSS for alabaster. The theme does not allow for it to be set differently. */ .red { - color: red; + color: red; } .green { - color: green; + color: green; } .pink { - color: pink; + color: pink; } .orange { - color: orange; + color: orange; } .purple { - color: purple; -} - -dl.attribute, dl.method { - display: block; - margin-left: 50px; -} - -footer a{ - - color: #4c72b0 !important; -} -a.reference { - color: #4c72b0 !important; + color: purple; } -blockquote p { - font-size: 14px !important; +a.reference > em { + font-style: normal !important; } -blockquote { - padding-top: 4px !important; - padding-bottom: 4px !important; - margin: 0 0 0px !important; +a.reference > code { + font-weight: inherit !important; + color: inherit; + background-color: inherit; } -code { - color: #49759c !important; - background-color: #ffffff !important; +ul, ol { + margin: 0px 0 0px 30px; } -.alert-info { - background-color: #adb8cb !important; - border-color: #adb8cb !important; - color: #2c3e50 !important; -} - -code.descname, code.descclassname { - color: #c42850 !important; -} - -code.descclassname + code.descname { - margin-left: -4px; - padding-left: 0px; -} - -span.sig-paren ~ em { - font-weight: 600; - font-family: sans-serif; - font-size: 9.5pt; +a.reference { + border-bottom: 0px; } -em.property { - font-weight: 600; - font-family: sans-serif; - font-size: 9.5pt; +td.field-body > ul > li > em { + font-style: normal !important; } - -/* .function dt { - padding-top: 150px; - margin-top: -150px; - -webkit-background-clip: content-box; - background-clip: content-box; -} */ - -.rubric > .class-header-no-toc { - font-size: 240%; - font-weight: 400; - /* padding-bottom: 20px; */ - display: inline-block; -} - -h1 { font-size: 240%; } -h2 { font-size: 180%; } -h3 { font-size: 150%; } -h4 { font-size: 120%; } -h5 { font-size: 90%; } -h6 { font-size: 80%; } diff --git a/docs/sphinx/_static/pygments.css b/docs/sphinx/_static/pygments.css deleted file mode 100644 index 0fa0bea..0000000 --- a/docs/sphinx/_static/pygments.css +++ /dev/null @@ -1,77 +0,0 @@ -.highlight .hll { background-color: #ffffcc } -.highlight { background: #f8f8f8; } -.highlight .c { color: #8f5902; font-style: italic } /* Comment */ -.highlight .err { color: #a40000; border: 1px solid #ef2929 } /* Error */ -.highlight .g { color: #000000 } /* Generic */ -.highlight .k { color: #204a87; font-weight: bold } /* Keyword */ -.highlight .l { color: #000000 } /* Literal */ -.highlight .n { color: #000000 } /* Name */ -.highlight .o { color: #ce5c00; font-weight: bold } /* Operator */ -.highlight .x { color: #000000 } /* Other */ -.highlight .p { color: #000000; font-weight: bold } /* Punctuation */ -.highlight .ch { color: #8f5902; font-style: italic } /* Comment.Hashbang */ -.highlight .cm { color: #8f5902; font-style: italic } /* Comment.Multiline */ -.highlight .cp { color: #8f5902; font-style: italic } /* Comment.Preproc */ -.highlight .cpf { color: #8f5902; font-style: italic } /* Comment.PreprocFile */ -.highlight .c1 { color: #8f5902; font-style: italic } /* Comment.Single */ -.highlight .cs { color: #8f5902; font-style: italic } /* Comment.Special */ -.highlight .gd { color: #a40000 } /* Generic.Deleted */ -.highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */ -.highlight .gr { color: #ef2929 } /* Generic.Error */ -.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ -.highlight .gi { color: #00A000 } /* Generic.Inserted */ -.highlight .go { color: #000000; font-style: italic } /* Generic.Output */ -.highlight .gp { color: #8f5902 } /* Generic.Prompt */ -.highlight .gs { color: #000000; font-weight: bold } /* Generic.Strong */ -.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ -.highlight .gt { color: #a40000; font-weight: bold } /* Generic.Traceback */ -.highlight .kc { color: #204a87; font-weight: bold } /* Keyword.Constant */ -.highlight .kd { color: #204a87; font-weight: bold } /* Keyword.Declaration */ -.highlight .kn { color: #204a87; font-weight: bold } /* Keyword.Namespace */ -.highlight .kp { color: #204a87; font-weight: bold } /* Keyword.Pseudo */ -.highlight .kr { color: #204a87; font-weight: bold } /* Keyword.Reserved */ -.highlight .kt { color: #204a87; font-weight: bold } /* Keyword.Type */ -.highlight .ld { color: #000000 } /* Literal.Date */ -.highlight .m { color: #0000cf; font-weight: bold } /* Literal.Number */ -.highlight .s { color: #4e9a06 } /* Literal.String */ -.highlight .na { color: #c4a000 } /* Name.Attribute */ -.highlight .nb { color: #204a87 } /* Name.Builtin */ -.highlight .nc { color: #000000 } /* Name.Class */ -.highlight .no { color: #000000 } /* Name.Constant */ -.highlight .nd { color: #5c35cc; font-weight: bold } /* Name.Decorator */ -.highlight .ni { color: #ce5c00 } /* Name.Entity */ -.highlight .ne { color: #cc0000; font-weight: bold } /* Name.Exception */ -.highlight .nf { color: #000000 } /* Name.Function */ -.highlight .nl { color: #f57900 } /* Name.Label */ -.highlight .nn { color: #000000 } /* Name.Namespace */ -.highlight .nx { color: #000000 } /* Name.Other */ -.highlight .py { color: #000000 } /* Name.Property */ -.highlight .nt { color: #204a87; font-weight: bold } /* Name.Tag */ -.highlight .nv { color: #000000 } /* Name.Variable */ -.highlight .ow { color: #204a87; font-weight: bold } /* Operator.Word */ -.highlight .w { color: #f8f8f8; text-decoration: underline } /* Text.Whitespace */ -.highlight .mb { color: #0000cf; font-weight: bold } /* Literal.Number.Bin */ -.highlight .mf { color: #0000cf; font-weight: bold } /* Literal.Number.Float */ -.highlight .mh { color: #0000cf; font-weight: bold } /* Literal.Number.Hex */ -.highlight .mi { color: #0000cf; font-weight: bold } /* Literal.Number.Integer */ -.highlight .mo { color: #0000cf; font-weight: bold } /* Literal.Number.Oct */ -.highlight .sa { color: #4e9a06 } /* Literal.String.Affix */ -.highlight .sb { color: #4e9a06 } /* Literal.String.Backtick */ -.highlight .sc { color: #4e9a06 } /* Literal.String.Char */ -.highlight .dl { color: #4e9a06 } /* Literal.String.Delimiter */ -.highlight .sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */ -.highlight .s2 { color: #4e9a06 } /* Literal.String.Double */ -.highlight .se { color: #4e9a06 } /* Literal.String.Escape */ -.highlight .sh { color: #4e9a06 } /* Literal.String.Heredoc */ -.highlight .si { color: #4e9a06 } /* Literal.String.Interpol */ -.highlight .sx { color: #4e9a06 } /* Literal.String.Other */ -.highlight .sr { color: #4e9a06 } /* Literal.String.Regex */ -.highlight .s1 { color: #4e9a06 } /* Literal.String.Single */ -.highlight .ss { color: #4e9a06 } /* Literal.String.Symbol */ -.highlight .bp { color: #3465a4 } /* Name.Builtin.Pseudo */ -.highlight .fm { color: #000000 } /* Name.Function.Magic */ -.highlight .vc { color: #000000 } /* Name.Variable.Class */ -.highlight .vg { color: #000000 } /* Name.Variable.Global */ -.highlight .vi { color: #000000 } /* Name.Variable.Instance */ -.highlight .vm { color: #000000 } /* Name.Variable.Magic */ -.highlight .il { color: #0000cf; font-weight: bold } /* Literal.Number.Integer.Long */ diff --git a/docs/sphinx/_templates/layout.html b/docs/sphinx/_templates/layout.html deleted file mode 100644 index 56464be..0000000 --- a/docs/sphinx/_templates/layout.html +++ /dev/null @@ -1,5 +0,0 @@ -{# layout.html #} -{# Import the theme's layout. #} -{% extends "!layout.html" %} - -{% set css_files = css_files + ['_static/custom.css', '_static/pygments.css'] %} diff --git a/docs/sphinx/changelog.md b/docs/sphinx/changelog.md new file mode 100644 index 0000000..ea758b9 --- /dev/null +++ b/docs/sphinx/changelog.md @@ -0,0 +1,4 @@ +(template-changelog)= + +```{include} ../../CHANGELOG.md +``` diff --git a/docs/sphinx/changelog.rst b/docs/sphinx/changelog.rst deleted file mode 100644 index fee2d8a..0000000 --- a/docs/sphinx/changelog.rst +++ /dev/null @@ -1,2 +0,0 @@ - -.. include:: ../../CHANGELOG.rst diff --git a/docs/sphinx/conf.py b/docs/sphinx/conf.py index 72129a9..1d3f6d4 100644 --- a/docs/sphinx/conf.py +++ b/docs/sphinx/conf.py @@ -1,83 +1,75 @@ -# -*- coding: utf-8 -*- -# -# Marvin documentation build configuration file, created by -# sphinx-quickstart on Sun Apr 10 08:50:42 2016. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - import os -# Comment if you do not want to use bootstrap themes. -import sphinx_bootstrap_theme # Are we building in RTD? -on_rtd = os.environ.get('READTHEDOCS') == 'True' +on_rtd = os.environ.get("READTHEDOCS") == "True" + -# -- General configuration ------------------------------------------------ +# matplotlib.use('agg') -# If your documentation needs a minimal Sphinx version, state it here. -# needs_sphinx = '1.0' -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. extensions = [ - 'IPython.sphinxext.ipython_console_highlighting', - 'IPython.sphinxext.ipython_directive', 'sphinx_issues'] + "sphinx.ext.autodoc", + "sphinx.ext.napoleon", + "sphinx.ext.autosummary", + "sphinx_autodoc_typehints", + "sphinx.ext.todo", + "sphinx.ext.viewcode", + "sphinx.ext.mathjax", + "sphinx.ext.intersphinx", + "myst_parser", + "sphinx_copybutton", +] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] + +pygments_style = "lovelace" +pygments_dark_style = "one-dark" # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: -# source_parsers = {'.md': 'recommonmark.parser.CommonMarkParser'} -source_suffix = ['.rst', '.md'] -# source_suffix = '.rst' +# source_suffix = ['.rst', '.md'] +source_suffix = ".rst" -# The encoding of source files. -# source_encoding = 'utf-8-sig' +source_parsers = { + # '.md': 'recommonmark.parser.CommonMarkParser', +} # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = u'SDSS Python Template' -copyright = u'2017, SDSS Collaboration' -author = u'JosΓ© SΓ‘nchez-Gallego et al.' +project = "python_template" +copyright = "{0}, {1}".format("2018-", "SDSS Collaboration") +author = "SDSS Collaboration" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. -# + +# The full version, including alpha/beta/rc tags. +release = "3.0.0" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -# today = '' -# Else, today_fmt is used as the format for a strftime call. -# today_fmt = '%B %d, %Y' +language = "en" # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = [ + "_build", + "Thumbs.db", + ".DS_Store", +] # The reST default role (used for this markup: `text`) to use for all # documents. -# default_role = 'py:obj' +default_role = "obj" # If true, '()' will be appended to :func: etc. cross-reference text. # add_function_parentheses = True @@ -91,7 +83,7 @@ # show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] @@ -99,116 +91,46 @@ # If true, keep warnings as "system message" paragraphs in the built documents. # keep_warnings = False +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + # Intersphinx mappings -intersphinx_mapping = {'python': ('https://docs.python.org/3.6', None), - 'astropy': ('http://docs.astropy.org/en/latest', None), - 'numpy': ('http://docs.scipy.org/doc/numpy/', None), - 'pandas': ('http://pandas.pydata.org/pandas-docs/stable/', None)} +intersphinx_mapping = {} -autodoc_member_order = 'groupwise' +autodoc_mock_imports = ["_tkinter"] +autodoc_member_order = "groupwise" +autodoc_default_options = {"members": None, "show-inheritance": None} +# autodoc_typehints = "description" -napoleon_use_rtype = False -napoleon_use_ivar = True +simplify_optional_unions = True +typehints_use_signature_return = True -# Github repo -issues_github_path = 'sdss/python_template' +# napoleon_use_rtype = False +# napoleon_use_ivar = True + +copybutton_prompt_text = r">>> |\$ " +copybutton_prompt_is_regexp = True rst_epilog = """ -.. |numpy_array| replace:: Numpy array -.. _numpy_array: http://example.com/ -.. |HDUList| replace:: :class:`~astropy.io.fits.HDUList` +.. |python_template_version| replace:: 3.0.0 +.. default-role:: py:obj """ + # -- 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 = 'bootstrap' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. +html_theme = "furo" +html_title = "Python template documentation" +html_logo = "_static/sdssv_logo.png" +html_favicon = "./_static/favicon.ico" html_theme_options = { - # Navigation bar title. (Default: ``project`` value) - 'navbar_title': "SDSS Python Template", - - # Tab name for entire site. (Default: "Site") - 'navbar_site_name': "Site", - - # A list of tuples containing pages or urls to link to. - # Valid tuples should be in the following forms: - # (name, page) # a link to a page - # (name, "/aa/bb", 1) # a link to an arbitrary relative url - # (name, "http://example.com", True) # arbitrary absolute url - # Note the "1" or "True" value above as the third argument to indicate - # an arbitrary url. - 'navbar_links': [ - ], - - # Render the next and previous page links in navbar. (Default: true) - 'navbar_sidebarrel': False, - - # Render the current pages TOC in the navbar. (Default: true) - 'navbar_pagenav': False, - - # Tab name for the current pages TOC. (Default: "Page") - 'navbar_pagenav_name': "Page", - - # Global TOC depth for "site" navbar tab. (Default: 1) - # Switching to -1 shows all levels. - 'globaltoc_depth': 2, - - # Include hidden TOCs in Site navbar? - # - # Note: If this is "false", you cannot have mixed ``:hidden:`` and - # non-hidden ``toctree`` directives in the same page, or else the build - # will break. - # - # Values: "true" (default) or "false" - 'globaltoc_includehidden': "false", - - # HTML navbar class (Default: "navbar") to attach to
element. - # For black navbar, do "navbar navbar-inverse" - 'navbar_class': "navbar", - - # Fix navigation bar to top of page? - # Values: "true" (default) or "false" - 'navbar_fixed_top': "false", - - # Location of link to source. - # Options are "nav" (default), "footer" or anything else to exclude. - 'source_link_position': "", - - # Bootswatch (http://bootswatch.com/) theme. - # - # Options are nothing (default) or the name of a valid theme - # such as "amelia" or "cosmo". - 'bootswatch_theme': "paper", - - # Choose Bootstrap version. - # Values: "3" (default) or "2" (in quotes) - 'bootstrap_version': "3", + "source_repository": "https://github.com/sdss/python_template/", + "source_branch": "main", + "source_directory": "docs/sphinx", } -# Add any paths that contain custom themes here, relative to this directory. -html_theme_path = sphinx_bootstrap_theme.get_html_theme_path() - -# The name for this set of Sphinx documents. -# " v documentation" by default. -# html_title = u'Marvin v2.0.0' - -# A shorter title for the navigation bar. Default is the same as html_title. -# html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -html_logo = '_static/sdssv_logo_small.png' - -# The name of an image file (relative to this directory) to use as a favicon of -# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -html_favicon = '_static/favicon_sdssv.ico' - # 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". @@ -217,151 +139,4 @@ if on_rtd: html_static_path = [] else: - html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -# html_extra_path = [] - -# If not None, a 'Last updated on:' timestamp is inserted at every page -# bottom, using the given strftime format. -# The empty string is equivalent to '%b %d, %Y'. -# html_last_updated_fmt = None - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -# html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -# html_sidebars = {'**': ['globaltoc.html', 'sourcelink.html', 'searchbox.html']} -html_sidebars = {'**': ['localtoc.html']} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -# html_additional_pages = {} - -# If false, no module index is generated. -# html_domain_indices = True - -# If false, no index is generated. -# html_use_index = True - -# If true, the index is split into individual pages for each letter. -# html_split_index = False - -# If true, links to the reST sources are added to the pages. -# html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -# html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -# html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -# html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -# html_file_suffix = None - -# Language to be used for generating the HTML full-text search index. -# Sphinx supports the following languages: -# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' -# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh' -# html_search_language = 'en' - -# A dictionary with options for the search language support, empty by default. -# 'ja' uses this config value. -# 'zh' user can custom change `jieba` dictionary path. -# html_search_options = {'type': 'default'} - -# The name of a javascript file (relative to the configuration directory) that -# implements a search results scorer. If empty, the default will be used. -# html_search_scorer = 'scorer.js' - -# Output file base name for HTML help builder. -htmlhelp_basename = 'Templatedoc' - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # 'preamble': '', - - # Latex figure (float) alignment - # 'figure_align': 'htbp', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -# latex_documents = [ -# (master_doc, 'Marvin.tex', u'Marvin Documentation', -# u'Brian Cherinka, Brett Andrews, and JosΓ© SΓ‘nchez-Gallego', 'manual'), -# ] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -# latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -# latex_use_parts = False - -# If true, show page references after internal links. -# latex_show_pagerefs = False - -# If true, show URL addresses after external links. -# latex_show_urls = False - -# Documents to append as an appendix to all manuals. -# latex_appendices = [] - -# If false, no module index is generated. -# latex_domain_indices = True - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -# man_pages = [ -# (master_doc, 'marvin', u'Marvin Documentation', -# [author], 1) -# ] - -# If true, show URL addresses after external links. -# man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -# texinfo_documents = [ -# (master_doc, 'Marvin', u'Marvin Documentation', -# author, 'Marvin', 'One line description of project.', -# 'Miscellaneous'), -# ] - -# Documents to append as an appendix to all manuals. -# texinfo_appendices = [] - -# If false, no module index is generated. -# texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -# texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -# texinfo_no_detailmenu = False + html_static_path = ["_static"] diff --git a/docs/sphinx/index.rst b/docs/sphinx/index.rst index 0ddb7d5..367e4af 100644 --- a/docs/sphinx/index.rst +++ b/docs/sphinx/index.rst @@ -1,473 +1,25 @@ -.. title:: SDSS Python Template documentation SDSS Python Template ==================== -.. note:: - This is the documentation for Python Template 2. The documentation for version 1 can be found :doc:`here `. +Contents +-------- -This page describes the `SDSS Python Template `_ as well as the :doc:`coding standards <../standards>`. - -See :doc:`what's new <../changelog>`. - - -.. contents:: **Table of Contents** - - -Major changes since version 1 ------------------------------ - -Python Template v2 provides the following major features: - -* Dropped support for Python 2. -* Replace ``utils`` with `sdsstools `__. -* Remove use of ``bumpversion``. Instead, get the package version using ``sdsstools.get_package_version``. -* Allow to choose between `setuptools `__ and `poetry `__. -* Allow to choose between ``sphinx-bootstrap-theme`` and ``alabaster``. - - -What you get with this template -------------------------------- - -* Python 3 compatibility (if you need Python 2/3 compatibility, check the :ref:`template version 1 `). -* `Pytest `_ testing framework. -* Continuous Integration with :ref:`Travis ` and `codecov `_. -* :ref:`pip `-ready product. -* Dependency and metadata handling using :ref:`setuptools or poetry `. -* :ref:`Sphinx Documentation ` with :ref:`Read The Docs ` integration. -* SDSS-compliant `license file `_. -* `Module file `_. -* :ref:`Configuration file ` and improved :ref:`logging `. -* Pre-defined scripts for frequently used :ref:`tasks `. -* The SDSS :ref:`tree and sdss_access ` python packages. - - -Creating a new product ----------------------- - -To install and initialize a new product from the template run :: - - pip install invoke - pip install cookiecutter - cookiecutter https://github.com/sdss/python_template.git - -During the installation `cookiecutter `__ will ask you a series of prompts to specify options and variable names, e.g. your name, the repository/folder name, the package name (which can be identical to the repository name), etc. These definitions will be inserted into the package in designated places to customise it for you. - -After asking for your name and emails, the cookiecutter process will prompt you for a **package_name**, a **repo_name**, and a **pip_name**. The former is the name that you want to use when *importing* the product (``from package_name import main``). repo_name is the repository name for your project (for example, the name of the product in GitHub); in most cases you'll want to make it the same as the package_name. Finally, pip_name is the name you want to use to publish your product to PyPI and make it pip-installable (``pip install pip_name``). While ``package_name`` and ``pip_name`` could be the same, normally we prefix the ``package_name`` with ``sdss-`` when publishing it. So, if your product is called ``mycamera``, its pip/PyPI name would be ``sdss-mycamera``. We talk about it in detail in :ref:`deploying-section-v2`. - -The **create_git_repo** prompt asks ``do you want to create a git repository out of your new package?``. If you answer ``yes``, the product will be initialised as a git repository. The final prompts ask ``did you already create a new repository on Github?`` and ``what is your Github organisation?``. If you answer ``yes``, and specify a name, a remote origin will be added to your new git repository and will be pushed to Github. If not, `create a blank GitHub repository `_ (either at the `SDSS organisation `_ or in your personal account) and copy the URL provided by GitHub. Make sure the Github repository is initially empty. In the root of your local product run :: - - git remote add origin GITHUB_URL - git push - -The new product can be installed in your system by running ``pip install .``. For development, however, it is usually better to add the product path to your ``PYTHONPATH`` or create a virtual environment. We talk about it in the :ref:`developing-section-v2` section. To modify your PYTHONPATH, in bash, add the following line to your ``~/.bashrc`` (modify accordingly for csh or other shells) :: - - export PYTHONPATH=/path/to/your/product/python:$PYTHONPATH - -Now you have a totally functional, if very simple, Python package connected to a GitHub repository. The following sections explain how to use the features included in the template and how to connect it with different online services. Before you continue, this may be a good time to read the :doc:`SDSS coding standards <../standards>` and make sure your code complies with them. - - -Directory Contents ------------------- - -* **cextern**: The directory for placing C code to be compiled -* **docs**: The directory for Sphinx documentation and other docu-related files -* **etc**: The directory containing your SDSS modulefile and other etc -* **python**: Your new python package directory -* **python/package_name/exceptions**: A custom python Exceptions. -* **python/package_name/etc**: An etc directory with text files that will be installed with the product. Contains a YAML configuration file that is ready by the package when imported. -* **tests**: The directory containing the tests for the package. Includes a ``conftest.py`` file with basic configuration using `pytest `_. -* **CHANGELOG.rst**: A file documenting changes to your code, e.g. new features, fixed issues, or bug-fixes. -* **CODEOWNERS**: A file assigning ownership of the code to the package or components of the package to various users -* **README.md**: A file describing your package. This will be the main display on Github. -* **LICENSE.md**: The open source license for your product. DO NOT DELETE. -* **readthedocs.yml**: The configuration file for Read The Docs. -* **.travis.yml**: The configuration file for Travis CI. - -Depending or whether you choose to use setuptools or poetry, you will also get the relevant ``setup.cfg``, ``setup.py``, and ``pyproject.toml``. - - -.. _packaging-section-v2: - -Packaging and dependency management ------------------------------------ - -During the cutting process you'll be asked what packaging system, setuptools or poetry, you want to use. This is an important decision that will change the files provided with the template and how you manage your dependencies and packaging. While it's possible to switch between systems after cutting the product, it's not totally trivial so it's worth spending some time reading this section before making a decision. - -Setuptools -^^^^^^^^^^ - -The default packaging system for the Python Template (and for Python, in general) is `setuptools `__, i.e., the well-known ``setup.py`` file. We refer to `their documentation `__ for details on how the system works. - -Starting with version 30, setuptools provides the option of using a ``setup.cfg`` file to consolidate all the necessary information for packaging, that used to be distributed across multiple files. ``setup.cfg`` includes the package metadata (its name, which matches the ``repo_name`` defined when initialising the product, version, author name and email, keywords, URLs, etc) but also the dependencies (which used to be included in ``requirements`` files), and package data (the ``MANIFEST.in`` file), etc. - -The ``setup.cfg`` provided with the template is a ready-to-deploy file which includes both the production and development dependencies. We also include sensible configurations for many tools such as `isort `__, `flake8 `__ `pytest `__, `coverage `__, etc. Using a ``setup.cfg`` dramatically reduces the number of files needed to configure your package and makes it easier to know where to go to change a parameter. - -To install your package, just run ``pip install .`` or (less preferred) ``python setup.py install``. - -Poetry -^^^^^^ - -Until recently, setuptools and its deprecated predecessor, `distutils `__, were the only options for packaging and publication of Python products. This has changed with the publication of `PEP-517 `__ and `PEP-518 `__, which define a framework for creating custom build systems that can still be used with pip and PyPI. While the implementation of these standards is still incomplete, their publication opened the door for a number of new build frameworks that aim to address several shortcomings in setuptools. - -One such build system is `poetry `__. poetry aims to provide a better development environment, integrating virtual environments with a robust dependency resolution. - -The Python ecosystem is very large and somehow convolved, with packages depending on each other in sometimes complicated and conflicting ways. Say, for example, that you have a package ``projectA`` that dependes on ``projectB>=1.0.0`` and ``projectC>=2.0.0`` but it also happens that ``projectB`` depends on ``projectC<2.0.0``. This is obviously a conflict and it should not be possible to publish ``projectA`` in such way. setuptools and pip provide ways to define the previous dependency versions but they are quite bad at making sure that all the dependencies are coherent: their purpose is to install the requested products, not to look for conflicts. - -In the case above, if you pip install ``productB==2.1.2``, it will also install ``productC==1.1.1``. But if you now install ``productC==2.7.1``, that won't change the already installed ``productB``. Depending on the order of the installations you may see a warning while running pip, but you have ended up with a broken dependency tree. This is even more likely to happen if you are not using a dedicated virtual environment for development. - -Poetry tries to avoid that by always installing dependencies in a virtual environment (and making it easy to manage) and by running a dependency resolution algorithm on each new dependency. If the dependency versions you are trying to use conflict, as in the earlier example, poetry will uncompromisingly prevent you from adding the new dependency. - -Now that we have examined the motivations, let's see how poetry works. PEP-517 defines a new file ``pyproject.toml`` to store the metadata and dependencies. Similar to ``setup.cfg``, the template provides a flight-ready ``pyproject.toml`` for the cookiecut project, along with configurations for tools such as flake8, pytest, etc. To add a new dependency, one simple does :: - - poetry add - -and, if there are no conflicts, the dependency is added to ``pyproject.toml``. There are two sections for production dependencies and development ones. The poetry build system does not use a ``setup.py`` file. Instead, the build backend is defined in the ``[build-system]`` section of ``pyproject.toml``. You can still do ``pip install .`` or ``pip install sdss-mypackage`` and pip will know to use poetry to install your product. - -In addition to these core components, poetry provides a number of nice features such as easy packaging and publication to PyPI, version bumping, etc. We refer to `its documentation `__ for details. - -At the time of this writing, poetry has reached version 1.0.0 and is quite stable, but there are some features still missing. The main caveats to consider when thinking about adopting poetry are: - -- Poetry does not allow to do editable install with ``pip install -e .`` (although doing ``poetry install`` does an editable install of your product, more on this in the :ref:`developing-section-v2` section). - -- Poetry does not provide a good build system for `extensions `__ (e.g., Cython). - -The first issue is caused by the incomplete implementation of PEP-517 in pip and it can be expected to be fixed at some point during 2020. The second is expected to be addressed by poetry itself at some point (note that there is a `workaround `__ to build extensions, but it comes with some caveats). - -To deal with these issues, the Python Template provides a ``create_setup.py`` script that generates a ``setup.py`` file based on the poetry information. We talk about it in detail in the :ref:`developing-section-v2` section. +.. toctree:: + :maxdepth: 2 + Changelog -.. _tools-section-v2: -Tools +Links ----- -The template comes with some tools for logging, configuration parsing, version management, and task handling. In version 1 of the template these code for these tools was included with the template. This was suboptimal because any bug fixes or improvements to those tools could not be propagated to already cut projects. If, for example, a bug was discovered in the logging tool, you'd need to manually modify each of your cookiecut products to fix it. - -For version 2 we have moved those tools to a small, external repository called `sdsstools `__. The template depends on it to provide these features so that if ``sdsstools`` gets update, you can simply do ``pip install --upgrade sdsstools`` and get all any new feature or bug fix. You can also use ``sdsstools`` for any project, even if it's not derived from this template. - -Normally, ``sdsstools`` will be installed as part of the cookiecut process, but depending on your Python installation and whether you are using virtual environments you may need to manually pip install it. - -.. _versioning-section-v2: - -Version management -^^^^^^^^^^^^^^^^^^ - -:ref:`Version 1 ` of the template used `bumpversion `__ for version bumping. ``bumpversion`` is, however, not totally trivial to use, and the project has been abandoned. - -In version 2 we simplify the process of handling the version of your product by using the `sdsstools.metadata `__ module. The version of the product is defined *only* in your ``pyproject.toml`` or ``setup.cfg``. The cookiecut template uses the ``sdsstools.get_package_version`` function to determine the version and stores it in the ``__version__`` attribute so you can do :: - - >>> from mypackage import __version__ - >>> print(__version__) - 0.1.0-alpha.0 - -To modify or bump the version, just go to the ``pyproject.toml`` or ``setup.cfg`` file and change it manually. Or, if using poetry, you can use `poetry version `__. - -The :ref:`Sphinx documentation ` includes a `substitution `__, ``|mypackage_version|`` that you can use anywhere in your rST files to include the product version. - -.. _conf-log-section-v2: - -Configuration file and logging -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Your new product contains a `YAML `_ configuration file in the ``python/[product_name]/etc/`` directory. YAML is significantly superior to other alternatives such as `configparser `__; it provides typed values, a clear data structure, and powerful parsing libraries. When you import the package, the configuration can be accessed as a dictionary using the ``config`` attribute. For example :: - - import mypython - print(mypython.config['option1']['suboption1']) - >>> 2.0 - print(mypython.config['option1']['suboption2']) - >>> 'some text' - -If the user creates a custom configuration file in ``~/.config/sdss/mypython.yaml``, the contents of that file will be used to update the default options. For instance, if you create a file with the contents - -.. code-block:: yaml - - option1: - suboption2: "a different text" - -the code above would return :: - - print(mypython.config['option1']['suboption1']) - >>> 2.0 - print(mypython.config['option1']['suboption2']) - >>> 'a different text' - -Another possibility is to define an environment variable ``$MYPYTHON_CONFIG_PATH`` pointing to the user configuration file to use. If the environment variable is set, it overrides the default location for the user configuration file. - -The package also includes a logging object built around Python's `logging `__ module. Our custom logger allows to file and screen at the same time and provides more colourful tracebacks and warnings. From anywhere in your code you can do :: - - from mypython import log - log.info('Some information that we want to log') - >>> [INFO]: Some information that we want to log - -Available levels are ``.debug``, ``.info``, ``.error``, and ``.critical``. For warnings, use the `warnings `__ module. Warnings will be redirected to all the available logging handlers after being formatter and coloured. - -By default, the file logger is not enabled. To start logging to file do :: - - log.start_file_logger('~/.mypython/mypython.log') - -where ``'~/.mypython/mypython.log'`` is the path of the file to which we want to log. If the file exists, the previous file is backed up by adding a timestamp to the extension. File logs are automatically backed up at midnight (see `TimedRotatingFileHandler `__). - -On initialisation, the screen logger will only show messages with level ``INFO`` or above. The file logger default level is ``DEBUG``. Levels can be changed in runtime :: - - # Sets the screen minimum level to DEBUG - import logging - log.sh.setLevel(logging.DEBUG) - - # Sets the file level to CRITICAL - log.fh.setLevel(logging.CRITICAL) - -The current log can be saved as :: - - log.save_log('~/Downloads/copy_of_log.log') - -The logging and configuration features are provided by the modules `sdsstools.logger `__ and `sdsstools.configuration `__, respectively. - -.. _tasks-section-v2: - -Using tasks -^^^^^^^^^^^ - -``sdsstools`` comes with a command line script, ``sdss`` that you can call from anywhere. This CLI is a simple wrapper around a series of `Invoke `__ tasks. You can think of them as macros for frequently used operations. - -If you run ``sdss`` you'll get a list of available tasks, such as :ref:`build documentation `, or clean the workspace. A full list is available `here `__, and we'll mention them in the following sections. - -Note that the CLI requires ``sdsstools`` to be installed for development :: - - pip install sdsstools[dev] - -Currently there is no procedure to extend the list of tasks in ``sdsstools``, but you can always create your own ``tasks.py`` file on the root of the project and use Invoke natively. - - -.. _deploying-section-v2: - -Deploying your product ----------------------- - -This section explains how to deploy a new version of your product to `PyPI `_ so that it becomes `pip `_-installable. - -The first step is to make sure that your project is ready to be deployed. This includes checking that the version is correct (i.e., not a pre-release or beta) and tagging the product. If using poetry, you may want to run a final ``poetry update`` to make sure all dependencies are correct. - - -Next, you will need to create a ``~/.pypirc`` file with the following content :: +* `Repository `__ +* `Issue tracking `__ - [distutils] - index-servers= - pypi - [pypi] - repository = https://pypi.python.org/pypi - username = [username] - password = [password] - -Here you have two options; you can either use your own account in PyPI to deploy the product, or use the SDSS one. For the latter, you'll need to ask for the username and password by emailing ``admin[at]sdss[dot]org``. If you use your own account, and after the new project has been created, remember to go to the management options and make ``sdss`` an **owner** of the project. This will allow other people in SDSS to edit it or contribute new versions if you stop being a maintainer. - -To deploy a new release you will need `twine `_. To install it :: - - pip install twine - -Then, from the root of your product, run :: - - sdss deploy - -which will create source and `wheel `_ distributions of your package and upload them to PyPI. The command above is equivalent to running :: - - python setup.py sdist bdist_wheel --universal - twine upload dist/* - -The ``pip_name`` that you selected when you cookiecut the new project specifies the name of the package as it appears in PyPI and how it will be installed. To avoid potential conflicts with existing packages, all SDSS package pip-names should adhere to the format ``sdss-[pkgname]``. E.g. the Python package ``tree`` would be called ``sdss-tree``. The python package ``sdss_access`` would be called ``sdss-access``. - -If you are using poetry this procedure may fail so it's better to use poetry's own publication system. Simply do :: - - poetry build - poetry publish - -which are equivalent to the build and upload steps above. - - -.. _tests-section-v2: - -Writing and running tests -------------------------- - -The ``tests`` directory contains some examples on how to write and run tests for your package using `pytest`_. Use the `conftest.py `__ file to define `fixtures `__ and other `pytest`_-specific features. cd'ing to the ``tests`` directory and typing ``pytest`` will recursively run all the tests in files whose filename starts with ``test_``. - -If you prefer to use `unittest `_ or `nose `_ feel free to remove those files. - -.. _travis-section-v2: - -Connecting your product to Travis -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The template includes a basic setup for `Travis CI `__ and `codecov `_. The configuration is defined in the `.travis.yml `__. `Coverage `__ configuration is included in your ``pyproject.toml`` or ``setup.cfg`` files. - -Once you have created the GitHub repository for the product, you can go to your `Travis CI `__ account (create one if you don't have it) and click on ``Add a new repository``. Then search for the new product and flip the switch to initiate the integration. You can do the same for codecov_. Each new push to the repository will trigger a Travis run that, if successful, will update the coverage report (to see it, you will also need to go to to codecov_, sign with your GitHub account, and turn on the repository). - -.. _github-actions-v2: - -Running the GitHub Action -^^^^^^^^^^^^^^^^^^^^^^^^^ - -The template also includes a basic `GitHub Actions `__ workflow in `.github/workflows/test.yml `__. The workflow will run on each commit as long as your repository has Actions enabled and will check linting using ``flake8``, import sorting with ``isort``, and will run the tests using ``pytest``. To push the results to `codecov`_ uncomment the section at the bottom of the file. - -.. _sphinx-section-v2: - -How to build Sphinx Documentation ---------------------------------- - -This template includes `Sphinx `_ documentation, written using the `reStructuredText `_ format. The documentation is located inside your python package, in a ``docs/sphinx/`` directory. You can build the existing Sphinx documentation using invoke :: - - sdss docs.build - -Alternatively, navigate to your python package's ``docs/sphinx/`` directory and type :: - - make html - -If you are using the ``sphinx-bootstrap-theme`` package, you'll need to install it manually or by going to ``docs/sphinx`` and running :: - - pip install -r requirements.txt - -You can add packages that your documentation needs to that file. The documentation dependencies in ``requirements.txt`` are automatically installed in the Read The Docs build. - -This will build your documentation, converting the rst files into html files. The output html files live in the ``docs/sphinx/_build`` subdirectory. To both build and display the documentation, type:: - - # builds and displays - sdss docs.show - -The main page of your documentation lives at ``docs/sphinx/_build/html/index.html``. New documentation must be written in the rst syntax for Sphinx to understand and properly build html files. - -The template includes an example on how to automatically document the docstrings in your code. In ``docs/sphinx/api.rst`` you'll see the lines :: - - .. automodule:: mypython.main - :members: - :undoc-members: - :show-inheritance: - -You can add similar blocks of code for other modules. See the Sphinx `autodoc `_ for more details. The :ref:`coding standards ` include a section on how to write good docstrings to document your code. - -.. _rtd-section-v2: - -Connecting your product to Read The Docs -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The cookiecut product documentation is ready to be built and integrated with Read The Docs. As with Travis and Coveralls above, you will need to commit the products to a GitHub repository first. As with PyPI, SDSS has a `Read The Docs `__ account to which you can request access by emailing ``admin[at]sdss[dot]org``. Alternatively, you can deploy your product in your own Read the Docs account and add the user ``sdss`` as a maintainer from the admin menu. The expected address of your documentation will be ``https://.readthedocs.org``. - -You may receive a message saying that the integration of the product is not complete and that you need to set up a webhook. To do that, got to the admin setting of the new Read The Docs project. In ``Intergations`` add a new integration and copy the link to the webhook. Then go to the GitHub repository settings and in the ``Webhooks`` section add a new webhook with the URL you just copied. Once you submit, any push to the main branch of the GitHub repo should produce a new built of the documentation. You can find more details on the webhook set up `here `_. - -The product configuration for Read The Docs can be found in `readthedocs.yml `_. By default, the Sphinx documentation will be built using Python 3.7 and will install the product with all its production requirements. If you have dependencies that are needed only for building the documentation (for example, a custom Sphinx theme), your can add them to the ``docs`` extras section of ``pyproject.toml`` or ``setup.cfg``. - - -.. _sdsspy-v2: - -SDSS tree and sdss_access -------------------------- - -This template includes the SDSS `tree `__ and `sdss_access `__ Python packages. This template adds these products as required dependencies in your installed project's `requirements.txt` file. We encourage you to use these packages inside your code. The ``tree`` package is designed to set up the SDSS SAS environment system dynamically within your Python environment. The ``sdss_access`` package is designed to provide local and remote filesystem path generation and downloading. To use these yourself, you may need to install them:: - - pip install sdss-tree - pip install sdss-access - -See the `tree `__ and `sdss_access `__ `readthedocs` for full documentation on each package, but in brief, to use the ``tree``:: - - # loads the full SAS using the sdsswork configuration. You only need to do this one per Python session. - from tree import Tree - my_tree = Tree() - -and to use ``sdss_access``:: - - # generate a local path to a file - from sdss_access.path import Path - path = Path() - filepath = path.full('mangacube', drpver='v2_3_1', plate='8485', '1901') - - -.. _developing-section-v2: - -Developing your product ------------------------ - -Now that we have seen what's included with your new product, how should you develop it? This, of course, depends on your habits and preferences, but here we list a few good advice. - -The most important thing to do is to **always develop your product in a virtual environment**. You can use `virtualenv `__ or `pyenv `__ to create and activate a new environment for your new product. This makes sure that you don't have conflicting products installing dependencies: for example, assume that your package needs ``numpy`` but numpy is already present in your global installation of Python; because all your ``import numpy`` work you may forget about it and not add it as dependency. This will cause a problem when somebody else tries to use it. - -In general, if working on a project that only depends on other Python products, you should not need to use modules or set the ``PYTHONPATH`` variable. Those are only necessary if you depend on non-Python products (for example, an IDL product, or a configuration directory). - -While working on a virtual environment, every time you install a new package remember to also add it to ``pyproject.toml`` or ``setup.cfg``, making sure you define the version ranges correctly. If you are using poetry, things are simpler since poetry enforces the use of a virtual environment; in that case just run ``poetry add `` and it will be added to ``pyproject.toml``. - -It is a good practice to set up Travis early on during your project development. Each Travis run is executed on an isolated environment so, in addition of running your tests on each commit, you may find issues with your dependency declaration that way. - -Sometimes you'll be developing on several project at the same time, each one depending on some of the others. In that case `pip editable installs `__ can be useful. By doing :: - - pip install -e - -you can make ``projectB`` available to your project A, but if you make changes directly in ````, those changes will reflect also in ``projectA`` without having to run pip install again. - -Considerations when using poetry -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Poetry provides a very nice framework for development but comes with some caveat and frequent confusions. When you run ``poetry install`` you product will be installed in the virtual environment as an *editable install*. This means that if you then change the code, you can see the results without having to install it again. - -Remember that after doing ``poetry install`` you either need to activate the virtual environment to run commands such as ``pytest`` or do ``poetry run pytest`` to make sure the command is execute inside the product environment. - -When you run ``poetry install`` or ``poetry add``, a `poetry.lock file `__ is generated. This file contains the exact versions that are installed in your environment and *you must commit it*. When you run ``poetry install`` with the lock file present, poetry install those specific version, providing a method to define a completely reproducible environment. If you want to update the versions of your dependencies (always with the constrains defined in ``pyproject.toml``) you can do ``poetry update``, which will also update the lock file. - -The main caveat when working with poetry has to do with the incomplete implementation of PEP-517 in pip. Because of that, you cannot do pip editable installs on your poetry product with ``pip install -e .`` (note that you **can** do ``pip install .`` for a normal installation). - -The second caveat is that the build system for C extensions is quite experimental at this point, as described :ref:`here `. - -To solve both those issues you may want to manually generate a ``setup.py`` file with the build information. The template provides a ``create_setup.py`` script that uses poetry itself to generate the ``setup.py``. If you do this, you need to run the script after each change to ``pyproject.toml`` or when you run a ``poetry add`` command. Remember to commit the ``setup.py`` file and treat it as a lock file. - -In this case, you may also want to comment the following lines in ``pyproject.toml`` - -.. code-block:: toml - - [build-system] - build-backend = "poetry.masonry.api" - requires = ["poetry>=1.0.0"] - -This will tell pip to not use poetry for installations, and instead use the ``setup.py`` with setuptools. You can still continue developing and deploying you code with poetry; this is only relevant for how other users will install your software. - - -How to modify this template ---------------------------- - -This template is built using `Cookiecutter `_. To add content to or expand this template, you must first check out the main template product using git:: - - git clone https://github.com/sdss/python_template - -Now you have the development version of this template. The two main components need are a `cookiecutter.json` file and a `{{cookiecutter.package_name}}` directory. Cookiecutter templates use the `Jinja2 `_ templating language to define variable substitution, using double bracket notation, e.g. `{{variable_name}}`. All customizable content to be inserted by the user is defined using this notation. - -* **{{cookiecutter.package_name}}**: the top-level directory defining the installed python package. Everything below this directory belongs to the Python package that gets installed by the user. -* **cookiecutter.json**: A JSON file containing a dictionary of key:value pairs of variables defined in the template, with their default values. These keys are referenced throughout the template with `{{cookiecutter.key}}`. - -Upon installation of the template by a user, the variables defined in the `cookiecutter.json` file, or by the user during install, get substituted into their respective reference places. - -Please, *do not* modify the main branch directly unless otherwise instructed. Instead, develop your changes in a branch or fork and, when ready to merge, create a pull request. - - -.. _faq-section-v2: - -Frequently Asked Questions --------------------------- - -**How do I install the just the requirement packages from setup.cfg?** - - Normally you'll want to install your package along with its requirements by doing ``pip install .`` (or, in editable mode, ``pip install -e .``). But what if you only want to install the dependencies but not the main product. In that case you can still do ``pip install .`` and then ``pip uninstall ``, which will leave the dependencies installed. - - Alternatively, you can use the ``sdss install-deps`` :ref:`task ` to install only the dependencies. You can even pass an ``--extras`` flag to tell it to install extras, for example :: - - sdss install-deps --extras dev - -.. _poetry-extensions: - -**What if I need to build C/C++ extensions with poetry?** - - Poetry provides a fairly immature system to build extensions. You can add your extensions to a file called ``build.py`` and then tell ``pyproject.toml`` to use it for extension building. See `this thread `__ for details. The template already includes a placeholder ``build.py``; just add your `Extension `__ instances there. Note that, as discussed :ref:`here `, this will require using the ``create_setup.py`` script and handling the generated ``setup.py`` as a lock file. - - -.. toctree:: - :hidden: +Indices and tables +------------------ - v1/v1 - standards - changelog +* :ref:`genindex` +* :ref:`modindex` diff --git a/docs/sphinx/requirements.txt b/docs/sphinx/requirements.txt new file mode 100644 index 0000000..b621cbc --- /dev/null +++ b/docs/sphinx/requirements.txt @@ -0,0 +1,7 @@ +Sphinx>=8.0.0 +furo>=2025.12.19 +myst-parser>=2.0.0 +nox>=2025.11.12 +sphinx-autobuild>=2021.3.14 +sphinx-copybutton>=0.4.0 +sphinx-autodoc-typehints>=1.23.2 diff --git a/docs/sphinx/requirements_template_docs.txt b/docs/sphinx/requirements_template_docs.txt deleted file mode 100644 index cce2a19..0000000 --- a/docs/sphinx/requirements_template_docs.txt +++ /dev/null @@ -1,3 +0,0 @@ -sphinx_bootstrap_theme>=0.4.12 -ipython>=5.0.0 -sphinx-issues>=1.2.0 diff --git a/docs/sphinx/standards.rst b/docs/sphinx/standards.rst deleted file mode 100644 index 0c5bbd0..0000000 --- a/docs/sphinx/standards.rst +++ /dev/null @@ -1,3 +0,0 @@ -.. _standards: - -.. include:: ../../STYLE.rst diff --git a/docs/sphinx/v1/v1.rst b/docs/sphinx/v1/v1.rst deleted file mode 100644 index 2662d8c..0000000 --- a/docs/sphinx/v1/v1.rst +++ /dev/null @@ -1,316 +0,0 @@ -.. title:: SDSS Python Template documentation v1 - -.. _template-v1: - -SDSS Python Template version 1 -============================== - -.. warning:: - This documentation is for version 1 of the Python Template. Python Template 2 provides multiple new features. The documentation for version 2 can be found :doc:`here <../index>`. - -This page describes the `SDSS Python Template `_ as well as the :doc:`coding standards <../standards>`. - -See :doc:`what's new <../changelog>`. - -What you get with this template -------------------------------- - -* Python 2/3 compatibility -* `Pytest `_ testing framework -* Continuous Integration with :ref:`Travis ` and `Coveralls `_ -* :ref:`Pip `-ready product -* :ref:`Sphinx Documentation ` with :ref:`Read The Docs ` integration -* Versioning with :ref:`BumpVersion `. -* :ref:`Invoke ` for shell tasks -* SDSS-compliant `license file `_. -* `Module file `_. -* :ref:`Configuration file ` and improved :ref:`logging `. -* the SDSS :ref:`tree and sdss_access ` python packages. - -Directory Contents ------------------- - -* **cextern**: The directory for placing C code to be compiled -* **docs**: The directory for Sphinx documentation and other docu-related files -* **etc**: The directory containing your SDSS modulefile and other etc -* **python**: Your new python package directory -* **python/package_name/core**: A directory for high-level core classes used in your product. Contains a set of custom python Exceptions. -* **python/package_name/etc**: An etc directory with text files that will be installed with the product. Contains a YAML configuration file that is ready by the package when imported. -* **python/package_name/utils**: General-use tools, including a custom logger and colour printing routines. -* **python/package_name/tests**: The directory containing the tests for the package. Includes a ``conftest.py`` file with basic configuration using `pytest `_. -* **CHANGELOG.rst**: A file documenting changes to your code, e.g. new features, fixed issues, or bug-fixes. -* **CODEOWNERS**: A file assigning ownership of the code to the package or components of the package to various users -* **README.rst**: A file describing your package. This will be the main display on Github. -* **STYLE.rst**: The SDSS style guide for best coding practices. -* **LICENSE.md**: The open source license for your product. DO NOT DELETE. -* **setup.py**: The setup for your pip-deployable product. Also used when installing manually with `python setup.py install`. -* **tasks.py**: A list of all invoke tasks available. -* **requirements[_xxx].txt**: These files list all Python packages that are dependencies for your product. Needed by pip. -* **readthedocs.yml**: The configuration file for Read The Docs. -* **.travis.yml**: The configuration file for Travis CI. -* **.bumpversion.cfg**: The configuration file for Bumpversion. -* **.coveragerc**: The configuration file for python code coverage and Coveralls. - - -Creating a new product ----------------------- - -To install and initialize a new product from the template run :: - - pip install invoke - pip install bumpversion - pip install cookiecutter - cookiecutter https://github.com/sdss/python_template.git --checkout python-template-v1 - -During the installation `cookiecutter `__ will ask you a series of prompts to specify options and variable names, e.g. your name, the repository/folder name, the package name (which can be identical to the repository name), etc. These definitions will be inserted into the package in designated places to customise it for you. - -The **create_git_repo** prompt asks ``do you want to create a git repository out of your new package?``. If you answer ``yes``, the product will be initialised as a git repository. The final prompts ask ``did you already create a new repository on Github?`` and ``what is your Github username?``. If you answer ``yes``, and specify a name, a remote origin will be added to your new git repository and will be pushed to Github. If not, `create a blank GitHub repository `_ (either at the `SDSS organisation `_ or in your personal account) and copy the URL provided by GitHub. Make sure the Github repository is initially empty. In the root of your local product run :: - - git remote add origin GITHUB_URL - git push - -The new product can be installed in your system by running ``python setup.py install``. For development, however, it is usually better to add the product path to your ``PYTHONPATH``. In bash add the following line to your ``~/.bashrc`` (modify accordingly for csh or other shells) :: - - export PYTHONPATH=/path/to/your/product/python:$PYTHONPATH - -Now you have a totally functional, if very simple, Python package connected to a GitHub repository. The following sections explain how to use the features included in the template and how to connect it with different online services. Before you continue, this may be a good time to read the :doc:`SDSS coding standards <../standards>` and make sure your code complies with them. - - -.. _bumpversion-section-v1: - -Bumping a version ------------------ - -The python template you cookiecut uses `bumpversion `_ to increase the version of your product. First, you need to install ``bumpversion`` by doing :: - - pip install bumpversion - -The bumpversion configuration is defined in the `.bumpversion.cfg `_ file in your new product. You should read the bumpversion documentation for details, but usually your workflow will be as follows: once you are ready to start working on a new version do :: - - bumpversion patch - -This will increase your version from ``X.Y.Z`` to ``X.Y.(Z+1)dev`` (e.g., ``1.2.3`` to ``1.2.4dev``) everywhere in your product and commit the changes. You can alternatively do ``bumpversion minor`` or ``bumpversion major`` to change the minor or major version. Once you are ready to release the version, do :: - - bumpversion release - -to remove the ``dev`` suffix. You can also do ``bumpversion patch release`` to release a new patch version without passing through the ``dev`` step. - -It is recommended to always do a dry run of your bump before the real thing to make sure it will go smoothly. You can do it with:: - - bumpversion patch --dry-run --verbose - -The default configuration of bumpversion is to always perform a commit whenever you bump to the next version. You can specify to also create a new tag of your version with:: - - bumpversion patch --tag - -This will create a new tag locally with the new bumped version as the tag name. You can push the tag to Github with:: - - git push origin [tagname] - -If you release and tag a new version, don't forget to do ``bumpversion patch`` to increment to the next `dev` version. - - -.. _tests-section-v1: - -Writing and running tests -------------------------- - -The ``tests`` directory contains some examples on how to write and run tests for your package using `pytest`_. Use the `conftest.py `_ file to define `fixtures `__ and other `pytest`_-specific features. cd'ing to the ``tests`` directory and typing ``pytest`` will recursively run all the tests in files whose filename starts with ``test_``. - -If you prefer to use `unittest `_ or `nose `_ feel free to remove those files. - - -.. _travis-section-v1: - -Connecting your product to Travis ---------------------------------- - -The template includes a basic setup for `Travis CI `__ and `Coveralls `_. The configuration is defined in the `.travis.yml `_ and `.coveragerc `_ files. - -Once you have created the GitHub repository for the product, you can go to your `Travis CI `__ account (create one if you don't have it) and click on ``Add a new repository``. Then search for the new product and flip the switch to initiate the integration. You can do the same for `Coveralls `_. Each new push to the repository will trigger a Travis run that, if successful, will update the coverage report. - - -.. _invoke-section-v1: - -Using invoke ------------- - -The product includes several macros to automate frequent tasks using `Invoke `_. To get a list of all the available tasks, from the root of your cookiecut project, do :: - - invoke -l - -The documentation can be compiled by doing ``invoke docs.build`` and then shown in your browser with ``invoke docs.show``. Another useful macro, ``invoke deploy``, automates the process of deploying a new version by creating new distribution packages and uploading them to PyPI (see deploying-section-v1_). - -You can add new tasks to the `tasks.py `__ file. - - -.. _sphinx-section-v1: - -How to build Sphinx Documentation ---------------------------------- - -This template includes `Sphinx `_ documentation, written using the `reStructuredText `_ format. The documentation is located inside your python package, in a `docs/sphinx/` directory. You can build the existing Sphinx documentation using invoke :: - - invoke docs.build - -Alternatively, navigate to your python package's `docs/sphinx/` directory and type:: - - make html - -This will build your documentation, converting the rst files into html files. The output html files live in the `docs/sphinx/_build` subdirectory. To both build and display the documentation, type:: - - # builds and displays - invoke docs.show - -The main page of your documentation lives at `docs/sphinx/_build/html/index.html`. New documentation must be written in the rst syntax for Sphinx to understand and properly build html files. - -The template includes an example on how to automatically document the docstrings in your code. In `docs/sphinx/api.rst` you'll see the lines :: - - .. automodule:: mypython.main - :members: - :undoc-members: - :show-inheritance: - -You can add similar blocks of code for other modules. See the Sphinx `autodoc `_ for more details. The :ref:`coding standards ` include a section on how to write good docstrings to document your code. - - -.. _rtd-section-v1: - -Connecting your product to Read The Docs ----------------------------------------- - -The cookiecut product documentation is ready to be built and integrated with Read The Docs. As with Travis and Coveralls above, you will need to commit the products to a GitHub repository first. SDSS has a `Read The Docs `_ account that is the preferred place to integrate the documentation. You can request access to the account by emailing ``admin[at]sdss[dot]org``. Alternatively, you can deploy your product in your own Read the Docs account and add the user ``sdss`` as a maintainer from the admin menu. - -Probably you will receive a message saying that the integration of the product is not complete and that you need to set up a webhook. To do that, got to the admin setting of the new Read The Docs project. In ``Intergations`` add a new integration and copy the link to the webhook. Then go to the GitHub repository settings and in the ``Webhooks`` section add a new webhook with the URL you just copied. Once you submit, any push to the main branch of the GitHub repo should produce a new built of the documentation. You can find more details on the webhook set up `here `_. - -The product configuration for Read The Docs can be found in `readthedocs.yml `_. By default, the Sphinx documentation will be built using Python 3.6 and using the requirements specified in `requirements_doc.txt `_. You can change those settings easily. - - -.. _conf-log-section-v1: - -Configuration file and logging ------------------------------- - -Your new product contains a `YAML `_ configuration file in the ``python/[product_name]/etc/`` directory. YAML is significantly superior to other alternatives such as `configparser `__; it provides typed values, a clear data structure, and powerful parsing libraries. When you import the package, the configuration can be accessed as a dictionary using the ``config`` attribute. For example :: - - import mypython - print(mypython.config['option1']['suboption1']) - >>> 2.0 - print(mypython.config['option1']['suboption2']) - >>> 'some text' - -If the user creates a custom configuration file in ``~/.config/mypython/mypython.yml``, the contents of that file will be used to update the default options. For instance, if you create a file with the contents - -.. code-block:: yaml - - option1: - suboption2: "a different text" - -the code above would return :: - - print(mypython.config['option1']['suboption1']) - >>> 2.0 - print(mypython.config['option1']['suboption2']) - >>> 'a different text' - -Another possibility is to define an environment variable ``$MYPYTHON_CONFIG_PATH`` pointing to the user configuration file to use. If the environment variable is set, it overrides the default location for the user configuration file. - -The package also includes a logging object built around Python's `logging `__ module. Our custom logger allows to file and screen at the same time and provides more colourful tracebacks and warnings. From anywhere in your code you can do :: - - from mypython import log - log.info('Some information that we want to log') - >>> [INFO]: Some information that we want to log - -Available levels are ``.debug``, ``.info``, ``.error``, and ``.critical``. For warnings, use `warnings `__ module. - -By default, the file logger is not enabled. To start logging to file do :: - - log.start_file_logger('~/.mypython/mypython.log') - -where ``'~/.mypython/mypython.log'`` is the path of the file to which we want to log. If the file exists, the previous file is backed up by adding a timestamp to the extension. File logs are automatically backed up at midnight (see `TimedRotatingFileHandler `__). - -On initialisation, the screen logger will only show messages with level ``INFO`` or above. The file logger default level is ``DEBUG``. Levels can be changed in runtime :: - - # Sets the screen minimum level to DEBUG - import logging - log.sh.setLevel(logging.DEBUG) - - # Sets the file level to CRITICAL - log.fh.setLevel(logging.CRITICAL) - -The current log can be saved as :: - - log.save_log('~/Downloads/copy_of_log.log') - - -.. _deploying-section-v1: - -Deploying your product ----------------------- - -This section explains how to deploy a new version of your product to `PyPI `_ so that it becomes `pip `_-installable. All SDSS products should be deployed to the SDSS dedicated PyPI account, access to which can be requested to ``admin[at]sdss[dot]org``. First you will need to create a ``~/.pypirc`` file with the following content :: - - [distutils] - index-servers= - pypi - - [pypi] - repository = https://pypi.python.org/pypi - username = sdss - password = [request this password] - -To deploy a new release you will need `twine `_. To install it :: - - pip install twine - -Then, from the root of your product, run :: - - invoke deploy - -which will create source and `wheel `_ distributions of your package and upload them to PyPI. The command above is equivalent to running :: - - python setup.py sdist bdist_wheel --universal - twine upload dist/* - -The ``NAME`` argument inside your ``setup.py`` specifies the name of the package as it appears in `PyPi` and how it will be installed. To avoid potential conflicts with existing packages, all SDSS package pip-names should adhere to the format ``sdss-[pkgname]``. E.g. the Python package -``tree`` would be called ``sdss-tree``. The python package ``sdss_access`` would be called ``sdss-access``. - - -How to modify this template ---------------------------- - -This template is built using `Cookiecutter `_. To add content to or expand this template, you must first check out the main template product using git:: - - git clone https://github.com/sdss/python_template - -Now you have the development version of this template. The two main components need are a `cookiecutter.json` file and a `{{cookiecutter.package_name}}` directory. Cookiecutter templates use the `Jinja2 `_ templating language to define variable substitution, using double bracket notation, e.g. `{{variable_name}}`. All customizable content to be inserted by the user is defined using this notation. - -* **{{cookiecutter.package_name}}**: the top-level directory defining the installed python package. Everything below this directory belongs to the Python package that gets installed by the user. -* **cookiecutter.json**: A JSON file containing a dictionary of key:value pairs of variables defined in the template, with their default values. These keys are referenced throughout the template with `{{cookiecutter.key}}`. - -Upon installation of the template by a user, the variables defined in the `cookiecutter.json` file, or by the user during install, get substituted into their respective reference places. - -Please, *do not* modify the main branch directly unless otherwise instructed. Instead, develop your changes in a branch or fork and, when ready to merge, create a pull request. - -.. _sdsspy-v1: - -SDSS tree and sdss_access -------------------------- - -This template includes the SDSS `tree `__ and `sdss_access `__ Python packages. This template adds these products as required dependencies in your installed project's `requirements.txt` file. We encourage you to use these packages inside your code. The ``tree`` package is designed to set up the SDSS SAS environment system dynamically within your Python environment. The ``sdss_access`` package is designed to provide local and remote filesystem path generation and downloading. To use these yourself, you may need to install them:: - - pip install sdss-tree - pip install sdss-access - -See the `tree `__ and `sdss_access `__ `readthedocs` for full documentation on each package, but in brief, to use the ``tree``:: - - # loads the full SAS using the sdsswork configuration. You only need to do this one per Python session. - from tree import Tree - my_tree = Tree() - -and to use ``sdss_access``:: - - # generate a local path to a file - from sdss_access.path import Path - path = Path() - filepath = path.full('mangacube', drpver='v2_3_1', plate='8485', '1901') diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py deleted file mode 100644 index 2d1ceb3..0000000 --- a/hooks/post_gen_project.py +++ /dev/null @@ -1,127 +0,0 @@ -# !usr/bin/env python -# -*- coding: utf-8 -*- -# -# Licensed under a 3-clause BSD license. - -import os -import shutil - -import invoke -from invoke.exceptions import UnexpectedExit - -# -# This script runs after the cookiecutter template has been installed -# - -PACKAGING_SYSTEM = '{{ cookiecutter.packaging_system }}' - -GITUSER = '{{ cookiecutter.github_organisation }}' -PIPNAME = '{{ cookiecutter.pip_name }}' -PKGNAME = '{{ cookiecutter.package_name }}' - -CURRENTDIR = os.path.abspath(os.curdir) -PYTHONDIR = os.path.join(CURRENTDIR, 'python') - - -def copy_packaging_system(): - """Copies the appropriate files to use setup.cfg or poetry.""" - - # Initially the repo is created with two directories, setup_cfg and poetry - # that contain the files needed for each packaging system. Here, depending - # on the cookiecutter configuration, we move the appropriate files and - # remove the other ones. - - if PACKAGING_SYSTEM == 'setuptools': - pack_dir = 'setup_cfg' - elif PACKAGING_SYSTEM == 'poetry': - pack_dir = 'poetry' - else: - raise ValueError(f'invalid packaging system {PACKAGING_SYSTEM!r}.') - - files = os.listdir(pack_dir) - for file_ in files: - if file_ == '__main__.py': - shutil.move(os.path.join(pack_dir, file_), os.path.join(PYTHONDIR, PKGNAME)) - else: - shutil.move(os.path.join(pack_dir, file_), CURRENTDIR) - - # Delete both directories - for dir_ in ['setup_cfg', 'poetry']: - shutil.rmtree(dir_, ignore_errors=True) - - -@invoke.task -def install(ctx): - ''' Cleans and installs the new repo ''' - - os.chdir(CURRENTDIR) - print('Installing {0}'.format(PKGNAME)) - ctx.run("python setup.py clean") - try: - ctx.run("python -d setup.py install", hide='both') - except UnexpectedExit as e: - print('Unexpected failure during install:\n {0}'.format(e.result.stderr)) - permden = '[Errno 13] Permission denied' in e.result.stderr - if permden: - print('Permission denied during install. Trying again with sudo') - ctx.run('sudo python -d setup.py install') - - -@invoke.task -def addgit(ctx): - ''' Cleans and installs the new repo ''' - - os.chdir(CURRENTDIR) - print('Initializing git repo {0}'.format(PKGNAME)) - ctx.run("git init .") - ctx.run("git add .") - ctx.run("git commit -m 'Initial skeleton.'") - - -@invoke.task -def addremote(ctx): - ''' Adds a new remote to your git repo and pushes to Github ''' - - if GITUSER: - ctx.run('git remote add origin https://github.com/{0}/{1}.git' - .format(GITUSER, PKGNAME)) - try: - print('Pushing to github ..') - ctx.run("git push -u origin main") - except Exception: - print('Could not push to github. ERROR: Repository not found. ' - 'Make sure to add the repo to your github account. ') - else: - print('No GitHub username specified during setup') - - -@invoke.task -def install_sdsstools(ctx): - """Tries to install sdsstools.""" - - try: - print('Installing sdsstools[dev]') - ctx.run('pip install sdsstools[dev]') - except Exception: - print('Could install sdsstools. Try running ' - '"pip install sdsstools[dev]" manually.') - - -col = invoke.Collection(install, addgit, addremote, install_sdsstools) -ex = invoke.executor.Executor(col) - -copy_packaging_system() -ex.execute('install_sdsstools') - -# setup intial git repo -creategit = '{{ cookiecutter.create_git_repo }}' -if creategit in ['yes', 'y']: - ex.execute('addgit') - -# exists on Github? -exists_github = '{{ cookiecutter.exists_on_github }}' -if exists_github in ['yes', 'y']: - ex.execute('addremote') - - -print('Please add {0} into your PYTHONPATH!'.format(PYTHONDIR)) diff --git a/hooks/pre_gen_project.py b/hooks/pre_gen_project.py deleted file mode 100644 index ebe0ddc..0000000 --- a/hooks/pre_gen_project.py +++ /dev/null @@ -1,15 +0,0 @@ -# !usr/bin/env python -# -*- coding: utf-8 -*- -# -# Licensed under a 3-clause BSD license. - -# -# This script runs before the cookiecutter template has been installed -# - -# Checks that invoke is installed. - -try: - import invoke # noqa -except ImportError: - raise ImportError('cannot import invoke. Did you run \'pip install invoke\'?') diff --git a/noxfile.py b/noxfile.py new file mode 100644 index 0000000..47ca30f --- /dev/null +++ b/noxfile.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# @Author: JosΓ© SΓ‘nchez-Gallego (gallegoj@uw.edu) +# @Date: 2021-06-20 +# @Filename: noxfile.py +# @License: BSD 3-clause (http://www.opensource.org/licenses/BSD-3-Clause) + +import contextlib +import os +import tempfile + +import nox + + +@contextlib.contextmanager +def cd(path): + CWD = os.getcwd() + + os.chdir(path) + + try: + yield + finally: + os.chdir(CWD) + + +@nox.session(name="docs-live", reuse_venv=True) +def docs_live(session): + if session.posargs: + docs_dir = session.posargs[0] + else: + docs_dir = "." + + with cd(os.path.join(os.path.dirname(__file__), "docs/sphinx")): + with tempfile.TemporaryDirectory() as destination: + session.run( + "sphinx-autobuild", + # for sphinx-autobuild + "--port=0", + "--open-browser", + # for sphinx + "-b=dirhtml", + "-a", + "--watch=../../style", + docs_dir, + destination, + external=True, + ) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..73f5436 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,52 @@ +[project] +name = "python_template" +version = "3.0.0a1" +description = "SDSS Python package template" +authors = [ + { name = "JosΓ© SΓ‘nchez-Gallego", email = "gallegoj@uw.edu" }, + { name = "Brian Cherinka", email = "bcherinka@stsci.edu" } +] +license = { text = "BSD-3-Clause" } +readme = "README.md" +requires-python = ">=3.10,<4" + +dependencies = [ + "ipython>=8.0.0", + "ipdb>=0.12.3", + "ruff>=0.14.10", + "Sphinx>=8.0.0", + "furo>=2025.12.19", + "myst-parser>=2.0.0", + "nox>=2025.11.12", + "sphinx-autobuild>=2021.3.14", + "sphinx-copybutton>=0.4.0", + "sphinx-autodoc-typehints>=1.23.2", +] + +[project.urls] +Homepage = "https://github.com/sdss/python-template" +Repository = "https://github.com/sdss/python-template" +Documentation = "https://sdss-python-template.readthedocs.io/en/latest/" + +[tool.uv] +package = false + +[tool.ruff] +line-length = 88 +target-version = 'py312' + +[tool.ruff.lint] +select = ["E", "F", "I"] +unfixable = ["F841"] + +[tool.ruff.lint.per-file-ignores] +"__init__.py" = ["F403", "E402", "F401"] + +[tool.ruff.lint.isort] +known-first-party = ["python_template"] +lines-after-imports = 2 +section-order = ["future", "standard-library", "typing", "third-party", "sdss", "first-party", "local-folder"] + +[tool.ruff.lint.isort.sections] +typing = ["typing"] +sdss = ["sdsstools"] diff --git a/readthedocs.yml b/readthedocs.yml index bc6d0bb..a2f370f 100644 --- a/readthedocs.yml +++ b/readthedocs.yml @@ -1,12 +1,15 @@ -build: - image: latest +version: 2 -python: - version: 3.8 - setup_py_install: false +build: + os: ubuntu-24.04 + tools: + python: '3.13' -requirements_file: docs/sphinx/requirements_template_docs.txt +sphinx: + configuration: docs/sphinx/conf.py -# Don't build any extra formats -formats: - - none +python: + install: + - requirements: docs/sphinx/requirements.txt + - method: pip + path: . diff --git a/STYLE.rst b/style/STYLE_v1.rst similarity index 99% rename from STYLE.rst rename to style/STYLE_v1.rst index 7b9051b..b56e429 100644 --- a/STYLE.rst +++ b/style/STYLE_v1.rst @@ -1,5 +1,5 @@ -SDSS coding standards -===================== +SDSS coding standards (version 1) +================================= So you want to write some Python code. Congratulations, you've arrived at the right place! This repository has a dual purpose: it provides a `template `__ for a basic but complete Python package; and lists the coding standards and recommendations for developing code for SDSS. Please, read this document carefully and suggest modifications by opening an `new issue `__. @@ -121,7 +121,7 @@ It is beyond the scope of this document to summarise the PEP8 conventions, but h - No trailing spaces. You can configure your editor to strip the lines automatically for you. - Imports go on the top of the file. Do **not** import more than one package in the same line (``import os, sys``). Maintain the namespace, do **not** import all functions in a package (``from os import *``). You can import multiple functions from the same package at the same time (``from os.path import dirname, basename``). - Use single quotes for strings. Double quotes must be reserved for docstrings and string blocks. -- For inline comments, at least two spaces between the statement and the beginning of the comment (``a = 1Β­Β­Β Β # This is a comment about a``). +- For inline comments, at least two spaces between the statement and the beginning of the comment (``a = 1 # This is a comment about a``). - Class names must be in camelcase (``class MyClass``). Function, method, and variable names should be all lowercase separated by underscores for legibility (``def a_function_that_does_something``, ``my_variable = 1``). For the latter ones, PEP8 allows some flexibility. The general rule of thumb is to make your function, method, and variable names descriptive and readable (avoid multiple words in all lowercase). As such, if you prefer to use camelcase (``aFunctionThatDoesSomething``, ``myVariable = 1``) for your project that is accepted, as long as you are consistent throughout the project. When modifying somebody else's code, stick to their naming decisions. - Use ``is`` for comparisons with ``None``, ``True``, or ``False``: ``if foo is not None:``. diff --git a/style/STYLE_v2.md b/style/STYLE_v2.md new file mode 100644 index 0000000..f83530b --- /dev/null +++ b/style/STYLE_v2.md @@ -0,0 +1,3 @@ +# SDSS coding standards (version 2) + +This is the current version of the SDSS coding standards. For the previous version, see [STYLE_v1](STYLE_v1.rst). diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..ecfd09f --- /dev/null +++ b/uv.lock @@ -0,0 +1,1385 @@ +version = 1 +revision = 3 +requires-python = ">=3.10, <4" +resolution-markers = [ + "python_full_version >= '3.11'", + "python_full_version < '3.11'", +] + +[[package]] +name = "accessible-pygments" +version = "0.0.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bc/c1/bbac6a50d02774f91572938964c582fff4270eee73ab822a4aeea4d8b11b/accessible_pygments-0.0.5.tar.gz", hash = "sha256:40918d3e6a2b619ad424cb91e556bd3bd8865443d9f22f1dcdf79e33c8046872", size = 1377899, upload-time = "2024-05-10T11:23:10.216Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8d/3f/95338030883d8c8b91223b4e21744b04d11b161a3ef117295d8241f50ab4/accessible_pygments-0.0.5-py3-none-any.whl", hash = "sha256:88ae3211e68a1d0b011504b2ffc1691feafce124b845bd072ab6f9f66f34d4b7", size = 1395903, upload-time = "2024-05-10T11:23:08.421Z" }, +] + +[[package]] +name = "alabaster" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/f8/d9c74d0daf3f742840fd818d69cfae176fa332022fd44e3469487d5a9420/alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e", size = 24210, upload-time = "2024-07-26T18:15:03.762Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b", size = 13929, upload-time = "2024-07-26T18:15:02.05Z" }, +] + +[[package]] +name = "anyio" +version = "4.12.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "idna" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/16/ce/8a777047513153587e5434fd752e89334ac33e379aa3497db860eeb60377/anyio-4.12.0.tar.gz", hash = "sha256:73c693b567b0c55130c104d0b43a9baf3aa6a31fc6110116509f27bf75e21ec0", size = 228266, upload-time = "2025-11-28T23:37:38.911Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/9c/36c5c37947ebfb8c7f22e0eb6e4d188ee2d53aa3880f3f2744fb894f0cb1/anyio-4.12.0-py3-none-any.whl", hash = "sha256:dad2376a628f98eeca4881fc56cd06affd18f659b17a747d3ff0307ced94b1bb", size = 113362, upload-time = "2025-11-28T23:36:57.897Z" }, +] + +[[package]] +name = "argcomplete" +version = "3.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/38/61/0b9ae6399dd4a58d8c1b1dc5a27d6f2808023d0b5dd3104bb99f45a33ff6/argcomplete-3.6.3.tar.gz", hash = "sha256:62e8ed4fd6a45864acc8235409461b72c9a28ee785a2011cc5eb78318786c89c", size = 73754, upload-time = "2025-10-20T03:33:34.741Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/74/f5/9373290775639cb67a2fce7f629a1c240dce9f12fe927bc32b2736e16dfc/argcomplete-3.6.3-py3-none-any.whl", hash = "sha256:f5007b3a600ccac5d25bbce33089211dfd49eab4a7718da3f10e3082525a92ce", size = 43846, upload-time = "2025-10-20T03:33:33.021Z" }, +] + +[[package]] +name = "asttokens" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308, upload-time = "2025-11-15T16:43:48.578Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047, upload-time = "2025-11-15T16:43:16.109Z" }, +] + +[[package]] +name = "attrs" +version = "25.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" }, +] + +[[package]] +name = "babel" +version = "2.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852, upload-time = "2025-02-01T15:17:41.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" }, +] + +[[package]] +name = "beautifulsoup4" +version = "4.14.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "soupsieve" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c3/b0/1c6a16426d389813b48d95e26898aff79abbde42ad353958ad95cc8c9b21/beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86", size = 627737, upload-time = "2025-11-30T15:08:26.084Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721, upload-time = "2025-11-30T15:08:24.087Z" }, +] + +[[package]] +name = "certifi" +version = "2025.11.12" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/8c/58f469717fa48465e4a50c014a0400602d3c437d7c0c468e17ada824da3a/certifi-2025.11.12.tar.gz", hash = "sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316", size = 160538, upload-time = "2025-11-12T02:54:51.517Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438, upload-time = "2025-11-12T02:54:49.735Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/b8/6d51fc1d52cbd52cd4ccedd5b5b2f0f6a11bbf6765c782298b0f3e808541/charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d", size = 209709, upload-time = "2025-10-14T04:40:11.385Z" }, + { url = "https://files.pythonhosted.org/packages/5c/af/1f9d7f7faafe2ddfb6f72a2e07a548a629c61ad510fe60f9630309908fef/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8", size = 148814, upload-time = "2025-10-14T04:40:13.135Z" }, + { url = "https://files.pythonhosted.org/packages/79/3d/f2e3ac2bbc056ca0c204298ea4e3d9db9b4afe437812638759db2c976b5f/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad", size = 144467, upload-time = "2025-10-14T04:40:14.728Z" }, + { url = "https://files.pythonhosted.org/packages/ec/85/1bf997003815e60d57de7bd972c57dc6950446a3e4ccac43bc3070721856/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8", size = 162280, upload-time = "2025-10-14T04:40:16.14Z" }, + { url = "https://files.pythonhosted.org/packages/3e/8e/6aa1952f56b192f54921c436b87f2aaf7c7a7c3d0d1a765547d64fd83c13/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d", size = 159454, upload-time = "2025-10-14T04:40:17.567Z" }, + { url = "https://files.pythonhosted.org/packages/36/3b/60cbd1f8e93aa25d1c669c649b7a655b0b5fb4c571858910ea9332678558/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313", size = 153609, upload-time = "2025-10-14T04:40:19.08Z" }, + { url = "https://files.pythonhosted.org/packages/64/91/6a13396948b8fd3c4b4fd5bc74d045f5637d78c9675585e8e9fbe5636554/charset_normalizer-3.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e", size = 151849, upload-time = "2025-10-14T04:40:20.607Z" }, + { url = "https://files.pythonhosted.org/packages/b7/7a/59482e28b9981d105691e968c544cc0df3b7d6133152fb3dcdc8f135da7a/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93", size = 151586, upload-time = "2025-10-14T04:40:21.719Z" }, + { url = "https://files.pythonhosted.org/packages/92/59/f64ef6a1c4bdd2baf892b04cd78792ed8684fbc48d4c2afe467d96b4df57/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0", size = 145290, upload-time = "2025-10-14T04:40:23.069Z" }, + { url = "https://files.pythonhosted.org/packages/6b/63/3bf9f279ddfa641ffa1962b0db6a57a9c294361cc2f5fcac997049a00e9c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84", size = 163663, upload-time = "2025-10-14T04:40:24.17Z" }, + { url = "https://files.pythonhosted.org/packages/ed/09/c9e38fc8fa9e0849b172b581fd9803bdf6e694041127933934184e19f8c3/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e", size = 151964, upload-time = "2025-10-14T04:40:25.368Z" }, + { url = "https://files.pythonhosted.org/packages/d2/d1/d28b747e512d0da79d8b6a1ac18b7ab2ecfd81b2944c4c710e166d8dd09c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db", size = 161064, upload-time = "2025-10-14T04:40:26.806Z" }, + { url = "https://files.pythonhosted.org/packages/bb/9a/31d62b611d901c3b9e5500c36aab0ff5eb442043fb3a1c254200d3d397d9/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6", size = 155015, upload-time = "2025-10-14T04:40:28.284Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f3/107e008fa2bff0c8b9319584174418e5e5285fef32f79d8ee6a430d0039c/charset_normalizer-3.4.4-cp310-cp310-win32.whl", hash = "sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f", size = 99792, upload-time = "2025-10-14T04:40:29.613Z" }, + { url = "https://files.pythonhosted.org/packages/eb/66/e396e8a408843337d7315bab30dbf106c38966f1819f123257f5520f8a96/charset_normalizer-3.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d", size = 107198, upload-time = "2025-10-14T04:40:30.644Z" }, + { url = "https://files.pythonhosted.org/packages/b5/58/01b4f815bf0312704c267f2ccb6e5d42bcc7752340cd487bc9f8c3710597/charset_normalizer-3.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69", size = 100262, upload-time = "2025-10-14T04:40:32.108Z" }, + { url = "https://files.pythonhosted.org/packages/ed/27/c6491ff4954e58a10f69ad90aca8a1b6fe9c5d3c6f380907af3c37435b59/charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8", size = 206988, upload-time = "2025-10-14T04:40:33.79Z" }, + { url = "https://files.pythonhosted.org/packages/94/59/2e87300fe67ab820b5428580a53cad894272dbb97f38a7a814a2a1ac1011/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0", size = 147324, upload-time = "2025-10-14T04:40:34.961Z" }, + { url = "https://files.pythonhosted.org/packages/07/fb/0cf61dc84b2b088391830f6274cb57c82e4da8bbc2efeac8c025edb88772/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3", size = 142742, upload-time = "2025-10-14T04:40:36.105Z" }, + { url = "https://files.pythonhosted.org/packages/62/8b/171935adf2312cd745d290ed93cf16cf0dfe320863ab7cbeeae1dcd6535f/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc", size = 160863, upload-time = "2025-10-14T04:40:37.188Z" }, + { url = "https://files.pythonhosted.org/packages/09/73/ad875b192bda14f2173bfc1bc9a55e009808484a4b256748d931b6948442/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897", size = 157837, upload-time = "2025-10-14T04:40:38.435Z" }, + { url = "https://files.pythonhosted.org/packages/6d/fc/de9cce525b2c5b94b47c70a4b4fb19f871b24995c728e957ee68ab1671ea/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381", size = 151550, upload-time = "2025-10-14T04:40:40.053Z" }, + { url = "https://files.pythonhosted.org/packages/55/c2/43edd615fdfba8c6f2dfbd459b25a6b3b551f24ea21981e23fb768503ce1/charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815", size = 149162, upload-time = "2025-10-14T04:40:41.163Z" }, + { url = "https://files.pythonhosted.org/packages/03/86/bde4ad8b4d0e9429a4e82c1e8f5c659993a9a863ad62c7df05cf7b678d75/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0", size = 150019, upload-time = "2025-10-14T04:40:42.276Z" }, + { url = "https://files.pythonhosted.org/packages/1f/86/a151eb2af293a7e7bac3a739b81072585ce36ccfb4493039f49f1d3cae8c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161", size = 143310, upload-time = "2025-10-14T04:40:43.439Z" }, + { url = "https://files.pythonhosted.org/packages/b5/fe/43dae6144a7e07b87478fdfc4dbe9efd5defb0e7ec29f5f58a55aeef7bf7/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4", size = 162022, upload-time = "2025-10-14T04:40:44.547Z" }, + { url = "https://files.pythonhosted.org/packages/80/e6/7aab83774f5d2bca81f42ac58d04caf44f0cc2b65fc6db2b3b2e8a05f3b3/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89", size = 149383, upload-time = "2025-10-14T04:40:46.018Z" }, + { url = "https://files.pythonhosted.org/packages/4f/e8/b289173b4edae05c0dde07f69f8db476a0b511eac556dfe0d6bda3c43384/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569", size = 159098, upload-time = "2025-10-14T04:40:47.081Z" }, + { url = "https://files.pythonhosted.org/packages/d8/df/fe699727754cae3f8478493c7f45f777b17c3ef0600e28abfec8619eb49c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224", size = 152991, upload-time = "2025-10-14T04:40:48.246Z" }, + { url = "https://files.pythonhosted.org/packages/1a/86/584869fe4ddb6ffa3bd9f491b87a01568797fb9bd8933f557dba9771beaf/charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a", size = 99456, upload-time = "2025-10-14T04:40:49.376Z" }, + { url = "https://files.pythonhosted.org/packages/65/f6/62fdd5feb60530f50f7e38b4f6a1d5203f4d16ff4f9f0952962c044e919a/charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016", size = 106978, upload-time = "2025-10-14T04:40:50.844Z" }, + { url = "https://files.pythonhosted.org/packages/7a/9d/0710916e6c82948b3be62d9d398cb4fcf4e97b56d6a6aeccd66c4b2f2bd5/charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1", size = 99969, upload-time = "2025-10-14T04:40:52.272Z" }, + { url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" }, + { url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" }, + { url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" }, + { url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497, upload-time = "2025-10-14T04:40:57.217Z" }, + { url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240, upload-time = "2025-10-14T04:40:58.358Z" }, + { url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471, upload-time = "2025-10-14T04:40:59.468Z" }, + { url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864, upload-time = "2025-10-14T04:41:00.623Z" }, + { url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647, upload-time = "2025-10-14T04:41:01.754Z" }, + { url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110, upload-time = "2025-10-14T04:41:03.231Z" }, + { url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839, upload-time = "2025-10-14T04:41:04.715Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667, upload-time = "2025-10-14T04:41:05.827Z" }, + { url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535, upload-time = "2025-10-14T04:41:06.938Z" }, + { url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816, upload-time = "2025-10-14T04:41:08.101Z" }, + { url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694, upload-time = "2025-10-14T04:41:09.23Z" }, + { url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131, upload-time = "2025-10-14T04:41:10.467Z" }, + { url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390, upload-time = "2025-10-14T04:41:11.915Z" }, + { url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" }, + { url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" }, + { url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" }, + { url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" }, + { url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" }, + { url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" }, + { url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" }, + { url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" }, + { url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" }, + { url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" }, + { url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" }, + { url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" }, + { url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" }, + { url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" }, + { url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" }, + { url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" }, + { url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" }, + { url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" }, + { url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779, upload-time = "2025-10-14T04:41:37.229Z" }, + { url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035, upload-time = "2025-10-14T04:41:38.368Z" }, + { url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542, upload-time = "2025-10-14T04:41:39.862Z" }, + { url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524, upload-time = "2025-10-14T04:41:41.319Z" }, + { url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395, upload-time = "2025-10-14T04:41:42.539Z" }, + { url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680, upload-time = "2025-10-14T04:41:43.661Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045, upload-time = "2025-10-14T04:41:44.821Z" }, + { url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687, upload-time = "2025-10-14T04:41:46.442Z" }, + { url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014, upload-time = "2025-10-14T04:41:47.631Z" }, + { url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044, upload-time = "2025-10-14T04:41:48.81Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" }, + { url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" }, + { url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, +] + +[[package]] +name = "click" +version = "8.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "colorlog" +version = "6.10.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a2/61/f083b5ac52e505dfc1c624eafbf8c7589a0d7f32daa398d2e7590efa5fda/colorlog-6.10.1.tar.gz", hash = "sha256:eb4ae5cb65fe7fec7773c2306061a8e63e02efc2c72eba9d27b0fa23c94f1321", size = 17162, upload-time = "2025-10-16T16:14:11.978Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/c1/e419ef3723a074172b68aaa89c9f3de486ed4c2399e2dbd8113a4fdcaf9e/colorlog-6.10.1-py3-none-any.whl", hash = "sha256:2d7e8348291948af66122cff006c9f8da6255d224e7cf8e37d8de2df3bad8c9c", size = 11743, upload-time = "2025-10-16T16:14:10.512Z" }, +] + +[[package]] +name = "decorator" +version = "5.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, +] + +[[package]] +name = "dependency-groups" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/62/55/f054de99871e7beb81935dea8a10b90cd5ce42122b1c3081d5282fdb3621/dependency_groups-1.3.1.tar.gz", hash = "sha256:78078301090517fd938c19f64a53ce98c32834dfe0dee6b88004a569a6adfefd", size = 10093, upload-time = "2025-05-02T00:34:29.452Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/99/c7/d1ec24fb280caa5a79b6b950db565dab30210a66259d17d5bb2b3a9f878d/dependency_groups-1.3.1-py3-none-any.whl", hash = "sha256:51aeaa0dfad72430fcfb7bcdbefbd75f3792e5919563077f30bc0d73f4493030", size = 8664, upload-time = "2025-05-02T00:34:27.085Z" }, +] + +[[package]] +name = "distlib" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, +] + +[[package]] +name = "docutils" +version = "0.21.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444, upload-time = "2024-04-23T18:57:18.24Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408, upload-time = "2024-04-23T18:57:14.835Z" }, +] + +[[package]] +name = "exceptiongroup" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, +] + +[[package]] +name = "executing" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488, upload-time = "2025-09-01T09:48:10.866Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" }, +] + +[[package]] +name = "filelock" +version = "3.20.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a7/23/ce7a1126827cedeb958fc043d61745754464eb56c5937c35bbf2b8e26f34/filelock-3.20.1.tar.gz", hash = "sha256:b8360948b351b80f420878d8516519a2204b07aefcdcfd24912a5d33127f188c", size = 19476, upload-time = "2025-12-15T23:54:28.027Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e3/7f/a1a97644e39e7316d850784c642093c99df1290a460df4ede27659056834/filelock-3.20.1-py3-none-any.whl", hash = "sha256:15d9e9a67306188a44baa72f569d2bfd803076269365fdea0934385da4dc361a", size = 16666, upload-time = "2025-12-15T23:54:26.874Z" }, +] + +[[package]] +name = "furo" +version = "2025.12.19" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "accessible-pygments" }, + { name = "beautifulsoup4" }, + { name = "pygments" }, + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "sphinx-basic-ng" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ec/20/5f5ad4da6a5a27c80f2ed2ee9aee3f9e36c66e56e21c00fde467b2f8f88f/furo-2025.12.19.tar.gz", hash = "sha256:188d1f942037d8b37cd3985b955839fea62baa1730087dc29d157677c857e2a7", size = 1661473, upload-time = "2025-12-19T17:34:40.889Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/b2/50e9b292b5cac13e9e81272c7171301abc753a60460d21505b606e15cf21/furo-2025.12.19-py3-none-any.whl", hash = "sha256:bb0ead5309f9500130665a26bee87693c41ce4dbdff864dbfb6b0dae4673d24f", size = 339262, upload-time = "2025-12-19T17:34:38.905Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "humanize" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/66/a3921783d54be8a6870ac4ccffcd15c4dc0dd7fcce51c6d63b8c63935276/humanize-4.15.0.tar.gz", hash = "sha256:1dd098483eb1c7ee8e32eb2e99ad1910baefa4b75c3aff3a82f4d78688993b10", size = 83599, upload-time = "2025-12-20T20:16:13.19Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/7b/bca5613a0c3b542420cf92bd5e5fb8ebd5435ce1011a091f66bb7693285e/humanize-4.15.0-py3-none-any.whl", hash = "sha256:b1186eb9f5a9749cd9cb8565aee77919dd7c8d076161cf44d70e59e3301e1769", size = 132203, upload-time = "2025-12-20T20:16:11.67Z" }, +] + +[[package]] +name = "idna" +version = "3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, +] + +[[package]] +name = "imagesize" +version = "1.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a7/84/62473fb57d61e31fef6e36d64a179c8781605429fd927b5dd608c997be31/imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a", size = 1280026, upload-time = "2022-07-01T12:21:05.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769, upload-time = "2022-07-01T12:21:02.467Z" }, +] + +[[package]] +name = "ipdb" +version = "0.13.13" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "decorator" }, + { name = "ipython", version = "8.37.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "ipython", version = "9.8.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/1b/7e07e7b752017f7693a0f4d41c13e5ca29ce8cbcfdcc1fd6c4ad8c0a27a0/ipdb-0.13.13.tar.gz", hash = "sha256:e3ac6018ef05126d442af680aad863006ec19d02290561ac88b8b1c0b0cfc726", size = 17042, upload-time = "2023-03-09T15:40:57.487Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/4c/b075da0092003d9a55cf2ecc1cae9384a1ca4f650d51b00fc59875fe76f6/ipdb-0.13.13-py3-none-any.whl", hash = "sha256:45529994741c4ab6d2388bfa5d7b725c2cf7fe9deffabdb8a6113aa5ed449ed4", size = 12130, upload-time = "2023-03-09T15:40:55.021Z" }, +] + +[[package]] +name = "ipython" +version = "8.37.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11'", +] +dependencies = [ + { name = "colorama", marker = "python_full_version < '3.11' and sys_platform == 'win32'" }, + { name = "decorator", marker = "python_full_version < '3.11'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "jedi", marker = "python_full_version < '3.11'" }, + { name = "matplotlib-inline", marker = "python_full_version < '3.11'" }, + { name = "pexpect", marker = "python_full_version < '3.11' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "prompt-toolkit", marker = "python_full_version < '3.11'" }, + { name = "pygments", marker = "python_full_version < '3.11'" }, + { name = "stack-data", marker = "python_full_version < '3.11'" }, + { name = "traitlets", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/85/31/10ac88f3357fc276dc8a64e8880c82e80e7459326ae1d0a211b40abf6665/ipython-8.37.0.tar.gz", hash = "sha256:ca815841e1a41a1e6b73a0b08f3038af9b2252564d01fc405356d34033012216", size = 5606088, upload-time = "2025-05-31T16:39:09.613Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/d0/274fbf7b0b12643cbbc001ce13e6a5b1607ac4929d1b11c72460152c9fc3/ipython-8.37.0-py3-none-any.whl", hash = "sha256:ed87326596b878932dbcb171e3e698845434d8c61b8d8cd474bf663041a9dcf2", size = 831864, upload-time = "2025-05-31T16:39:06.38Z" }, +] + +[[package]] +name = "ipython" +version = "9.8.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.11'", +] +dependencies = [ + { name = "colorama", marker = "python_full_version >= '3.11' and sys_platform == 'win32'" }, + { name = "decorator", marker = "python_full_version >= '3.11'" }, + { name = "ipython-pygments-lexers", marker = "python_full_version >= '3.11'" }, + { name = "jedi", marker = "python_full_version >= '3.11'" }, + { name = "matplotlib-inline", marker = "python_full_version >= '3.11'" }, + { name = "pexpect", marker = "python_full_version >= '3.11' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "prompt-toolkit", marker = "python_full_version >= '3.11'" }, + { name = "pygments", marker = "python_full_version >= '3.11'" }, + { name = "stack-data", marker = "python_full_version >= '3.11'" }, + { name = "traitlets", marker = "python_full_version >= '3.11'" }, + { name = "typing-extensions", marker = "python_full_version == '3.11.*'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/12/51/a703c030f4928646d390b4971af4938a1b10c9dfce694f0d99a0bb073cb2/ipython-9.8.0.tar.gz", hash = "sha256:8e4ce129a627eb9dd221c41b1d2cdaed4ef7c9da8c17c63f6f578fe231141f83", size = 4424940, upload-time = "2025-12-03T10:18:24.353Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/df/8ee1c5dd1e3308b5d5b2f2dfea323bb2f3827da8d654abb6642051199049/ipython-9.8.0-py3-none-any.whl", hash = "sha256:ebe6d1d58d7d988fbf23ff8ff6d8e1622cfdb194daf4b7b73b792c4ec3b85385", size = 621374, upload-time = "2025-12-03T10:18:22.335Z" }, +] + +[[package]] +name = "ipython-pygments-lexers" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pygments", marker = "python_full_version >= '3.11'" }, +] +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.19.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "parso" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" }, +] + +[[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 = "markdown-it-py" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", size = 11631, upload-time = "2025-09-27T18:36:05.558Z" }, + { url = "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", size = 12057, upload-time = "2025-09-27T18:36:07.165Z" }, + { url = "https://files.pythonhosted.org/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", size = 22050, upload-time = "2025-09-27T18:36:08.005Z" }, + { url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", size = 20681, upload-time = "2025-09-27T18:36:08.881Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", size = 20705, upload-time = "2025-09-27T18:36:10.131Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", size = 21524, upload-time = "2025-09-27T18:36:11.324Z" }, + { url = "https://files.pythonhosted.org/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", size = 20282, upload-time = "2025-09-27T18:36:12.573Z" }, + { url = "https://files.pythonhosted.org/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", size = 20745, upload-time = "2025-09-27T18:36:13.504Z" }, + { url = "https://files.pythonhosted.org/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", size = 14571, upload-time = "2025-09-27T18:36:14.779Z" }, + { url = "https://files.pythonhosted.org/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", size = 15056, upload-time = "2025-09-27T18:36:16.125Z" }, + { url = "https://files.pythonhosted.org/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", size = 13932, upload-time = "2025-09-27T18:36:17.311Z" }, + { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631, upload-time = "2025-09-27T18:36:18.185Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058, upload-time = "2025-09-27T18:36:19.444Z" }, + { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287, upload-time = "2025-09-27T18:36:20.768Z" }, + { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940, upload-time = "2025-09-27T18:36:22.249Z" }, + { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887, upload-time = "2025-09-27T18:36:23.535Z" }, + { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692, upload-time = "2025-09-27T18:36:24.823Z" }, + { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471, upload-time = "2025-09-27T18:36:25.95Z" }, + { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923, upload-time = "2025-09-27T18:36:27.109Z" }, + { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572, upload-time = "2025-09-27T18:36:28.045Z" }, + { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077, upload-time = "2025-09-27T18:36:29.025Z" }, + { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876, upload-time = "2025-09-27T18:36:29.954Z" }, + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, + { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, + { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, + { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, + { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, + { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, + { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, + { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, + { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, + { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, + { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, + { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, + { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, + { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, + { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, + { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, + { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, + { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, + { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, + { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, + { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, + { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, + { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, + { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, + { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, + { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, + { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, + { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, + { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, + { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, + { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, + { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, +] + +[[package]] +name = "matplotlib-inline" +version = "0.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c7/74/97e72a36efd4ae2bccb3463284300f8953f199b5ffbc04cbbb0ec78f74b1/matplotlib_inline-0.2.1.tar.gz", hash = "sha256:e1ee949c340d771fc39e241ea75683deb94762c8fa5f2927ec57c83c4dffa9fe", size = 8110, upload-time = "2025-10-23T09:00:22.126Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/af/33/ee4519fa02ed11a94aef9559552f3b17bb863f2ecfe1a35dc7f548cde231/matplotlib_inline-0.2.1-py3-none-any.whl", hash = "sha256:d56ce5156ba6085e00a9d54fead6ed29a9c47e215cd1bba2e976ef39f5710a76", size = 9516, upload-time = "2025-10-23T09:00:20.675Z" }, +] + +[[package]] +name = "mdit-py-plugins" +version = "0.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b2/fd/a756d36c0bfba5f6e39a1cdbdbfdd448dc02692467d83816dff4592a1ebc/mdit_py_plugins-0.5.0.tar.gz", hash = "sha256:f4918cb50119f50446560513a8e311d574ff6aaed72606ddae6d35716fe809c6", size = 44655, upload-time = "2025-08-11T07:25:49.083Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/86/dd6e5db36df29e76c7a7699123569a4a18c1623ce68d826ed96c62643cae/mdit_py_plugins-0.5.0-py3-none-any.whl", hash = "sha256:07a08422fc1936a5d26d146759e9155ea466e842f5ab2f7d2266dd084c8dab1f", size = 57205, upload-time = "2025-08-11T07:25:47.597Z" }, +] + +[[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 = "myst-parser" +version = "4.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "docutils" }, + { name = "jinja2" }, + { name = "markdown-it-py" }, + { name = "mdit-py-plugins" }, + { name = "pyyaml" }, + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/a5/9626ba4f73555b3735ad86247a8077d4603aa8628537687c839ab08bfe44/myst_parser-4.0.1.tar.gz", hash = "sha256:5cfea715e4f3574138aecbf7d54132296bfd72bb614d31168f48c477a830a7c4", size = 93985, upload-time = "2025-02-12T10:53:03.833Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/df/76d0321c3797b54b60fef9ec3bd6f4cfd124b9e422182156a1dd418722cf/myst_parser-4.0.1-py3-none-any.whl", hash = "sha256:9134e88959ec3b5780aedf8a99680ea242869d012e8821db3126d427edc9c95d", size = 84579, upload-time = "2025-02-12T10:53:02.078Z" }, +] + +[[package]] +name = "nox" +version = "2025.11.12" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "argcomplete" }, + { name = "attrs" }, + { name = "colorlog" }, + { name = "dependency-groups" }, + { name = "humanize" }, + { name = "packaging" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "virtualenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b4/a8/e169497599266d176832e2232c08557ffba97eef87bf8a18f9f918e0c6aa/nox-2025.11.12.tar.gz", hash = "sha256:3d317f9e61f49d6bde39cf2f59695bb4e1722960457eee3ae19dacfe03c07259", size = 4030561, upload-time = "2025-11-12T18:39:03.319Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/34/434c594e0125a16b05a7bedaea33e63c90abbfbe47e5729a735a8a8a90ea/nox-2025.11.12-py3-none-any.whl", hash = "sha256:707171f9f63bc685da9d00edd8c2ceec8405b8e38b5fb4e46114a860070ef0ff", size = 74447, upload-time = "2025-11-12T18:39:01.575Z" }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "parso" +version = "0.8.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d4/de/53e0bcf53d13e005bd8c92e7855142494f41171b34c2536b86187474184d/parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a", size = 401205, upload-time = "2025-08-23T15:15:28.028Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668, upload-time = "2025-08-23T15:15:25.663Z" }, +] + +[[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 = "platformdirs" +version = "4.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715, upload-time = "2025-12-05T13:52:58.638Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" }, +] + +[[package]] +name = "prompt-toolkit" +version = "3.0.52" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wcwidth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" }, +] + +[[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.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "python-template" +version = "3.0.0a1" +source = { virtual = "." } +dependencies = [ + { name = "furo" }, + { name = "ipdb" }, + { name = "ipython", version = "8.37.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "ipython", version = "9.8.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "myst-parser" }, + { name = "nox" }, + { name = "ruff" }, + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "sphinx-autobuild", version = "2024.10.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "sphinx-autobuild", version = "2025.8.25", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "sphinx-autodoc-typehints", version = "3.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "sphinx-autodoc-typehints", version = "3.5.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "sphinx-copybutton" }, +] + +[package.metadata] +requires-dist = [ + { name = "furo", specifier = ">=2025.12.19" }, + { name = "ipdb", specifier = ">=0.12.3" }, + { name = "ipython", specifier = ">=8.0.0" }, + { name = "myst-parser", specifier = ">=2.0.0" }, + { name = "nox", specifier = ">=2025.11.12" }, + { name = "ruff", specifier = ">=0.14.10" }, + { name = "sphinx", specifier = ">=8.0.0" }, + { name = "sphinx-autobuild", specifier = ">=2021.3.14" }, + { name = "sphinx-autodoc-typehints", specifier = ">=1.23.2" }, + { name = "sphinx-copybutton", specifier = ">=0.4.0" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227, upload-time = "2025-09-25T21:31:46.04Z" }, + { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019, upload-time = "2025-09-25T21:31:47.706Z" }, + { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646, upload-time = "2025-09-25T21:31:49.21Z" }, + { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793, upload-time = "2025-09-25T21:31:50.735Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293, upload-time = "2025-09-25T21:31:51.828Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872, upload-time = "2025-09-25T21:31:53.282Z" }, + { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828, upload-time = "2025-09-25T21:31:54.807Z" }, + { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415, upload-time = "2025-09-25T21:31:55.885Z" }, + { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561, upload-time = "2025-09-25T21:31:57.406Z" }, + { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, + { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, + { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, + { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, + { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, + { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, + { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, + { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, +] + +[[package]] +name = "roman-numerals" +version = "4.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ae/f9/41dc953bbeb056c17d5f7a519f50fdf010bd0553be2d630bc69d1e022703/roman_numerals-4.1.0.tar.gz", hash = "sha256:1af8b147eb1405d5839e78aeb93131690495fe9da5c91856cb33ad55a7f1e5b2", size = 9077, upload-time = "2025-12-17T18:25:34.381Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/54/6f679c435d28e0a568d8e8a7c0a93a09010818634c3c3907fc98d8983770/roman_numerals-4.1.0-py3-none-any.whl", hash = "sha256:647ba99caddc2cc1e55a51e4360689115551bf4476d90e8162cf8c345fe233c7", size = 7676, upload-time = "2025-12-17T18:25:33.098Z" }, +] + +[[package]] +name = "roman-numerals-py" +version = "4.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "roman-numerals", marker = "python_full_version >= '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cb/b5/de96fca640f4f656eb79bbee0e79aeec52e3e0e359f8a3e6a0d366378b64/roman_numerals_py-4.1.0.tar.gz", hash = "sha256:f5d7b2b4ca52dd855ef7ab8eb3590f428c0b1ea480736ce32b01fef2a5f8daf9", size = 4274, upload-time = "2025-12-17T18:25:41.153Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/2c/daca29684cbe9fd4bc711f8246da3c10adca1ccc4d24436b17572eb2590e/roman_numerals_py-4.1.0-py3-none-any.whl", hash = "sha256:553114c1167141c1283a51743759723ecd05604a1b6b507225e91dc1a6df0780", size = 4547, upload-time = "2025-12-17T18:25:40.136Z" }, +] + +[[package]] +name = "ruff" +version = "0.14.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/57/08/52232a877978dd8f9cf2aeddce3e611b40a63287dfca29b6b8da791f5e8d/ruff-0.14.10.tar.gz", hash = "sha256:9a2e830f075d1a42cd28420d7809ace390832a490ed0966fe373ba288e77aaf4", size = 5859763, upload-time = "2025-12-18T19:28:57.98Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/01/933704d69f3f05ee16ef11406b78881733c186fe14b6a46b05cfcaf6d3b2/ruff-0.14.10-py3-none-linux_armv6l.whl", hash = "sha256:7a3ce585f2ade3e1f29ec1b92df13e3da262178df8c8bdf876f48fa0e8316c49", size = 13527080, upload-time = "2025-12-18T19:29:25.642Z" }, + { url = "https://files.pythonhosted.org/packages/df/58/a0349197a7dfa603ffb7f5b0470391efa79ddc327c1e29c4851e85b09cc5/ruff-0.14.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:674f9be9372907f7257c51f1d4fc902cb7cf014b9980152b802794317941f08f", size = 13797320, upload-time = "2025-12-18T19:29:02.571Z" }, + { url = "https://files.pythonhosted.org/packages/7b/82/36be59f00a6082e38c23536df4e71cdbc6af8d7c707eade97fcad5c98235/ruff-0.14.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d85713d522348837ef9df8efca33ccb8bd6fcfc86a2cde3ccb4bc9d28a18003d", size = 12918434, upload-time = "2025-12-18T19:28:51.202Z" }, + { url = "https://files.pythonhosted.org/packages/a6/00/45c62a7f7e34da92a25804f813ebe05c88aa9e0c25e5cb5a7d23dd7450e3/ruff-0.14.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6987ebe0501ae4f4308d7d24e2d0fe3d7a98430f5adfd0f1fead050a740a3a77", size = 13371961, upload-time = "2025-12-18T19:29:04.991Z" }, + { url = "https://files.pythonhosted.org/packages/40/31/a5906d60f0405f7e57045a70f2d57084a93ca7425f22e1d66904769d1628/ruff-0.14.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:16a01dfb7b9e4eee556fbfd5392806b1b8550c9b4a9f6acd3dbe6812b193c70a", size = 13275629, upload-time = "2025-12-18T19:29:21.381Z" }, + { url = "https://files.pythonhosted.org/packages/3e/60/61c0087df21894cf9d928dc04bcd4fb10e8b2e8dca7b1a276ba2155b2002/ruff-0.14.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7165d31a925b7a294465fa81be8c12a0e9b60fb02bf177e79067c867e71f8b1f", size = 14029234, upload-time = "2025-12-18T19:29:00.132Z" }, + { url = "https://files.pythonhosted.org/packages/44/84/77d911bee3b92348b6e5dab5a0c898d87084ea03ac5dc708f46d88407def/ruff-0.14.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:c561695675b972effb0c0a45db233f2c816ff3da8dcfbe7dfc7eed625f218935", size = 15449890, upload-time = "2025-12-18T19:28:53.573Z" }, + { url = "https://files.pythonhosted.org/packages/e9/36/480206eaefa24a7ec321582dda580443a8f0671fdbf6b1c80e9c3e93a16a/ruff-0.14.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4bb98fcbbc61725968893682fd4df8966a34611239c9fd07a1f6a07e7103d08e", size = 15123172, upload-time = "2025-12-18T19:29:23.453Z" }, + { url = "https://files.pythonhosted.org/packages/5c/38/68e414156015ba80cef5473d57919d27dfb62ec804b96180bafdeaf0e090/ruff-0.14.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f24b47993a9d8cb858429e97bdf8544c78029f09b520af615c1d261bf827001d", size = 14460260, upload-time = "2025-12-18T19:29:27.808Z" }, + { url = "https://files.pythonhosted.org/packages/b3/19/9e050c0dca8aba824d67cc0db69fb459c28d8cd3f6855b1405b3f29cc91d/ruff-0.14.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59aabd2e2c4fd614d2862e7939c34a532c04f1084476d6833dddef4afab87e9f", size = 14229978, upload-time = "2025-12-18T19:29:11.32Z" }, + { url = "https://files.pythonhosted.org/packages/51/eb/e8dd1dd6e05b9e695aa9dd420f4577debdd0f87a5ff2fedda33c09e9be8c/ruff-0.14.10-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:213db2b2e44be8625002dbea33bb9c60c66ea2c07c084a00d55732689d697a7f", size = 14338036, upload-time = "2025-12-18T19:29:09.184Z" }, + { url = "https://files.pythonhosted.org/packages/6a/12/f3e3a505db7c19303b70af370d137795fcfec136d670d5de5391e295c134/ruff-0.14.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b914c40ab64865a17a9a5b67911d14df72346a634527240039eb3bd650e5979d", size = 13264051, upload-time = "2025-12-18T19:29:13.431Z" }, + { url = "https://files.pythonhosted.org/packages/08/64/8c3a47eaccfef8ac20e0484e68e0772013eb85802f8a9f7603ca751eb166/ruff-0.14.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1484983559f026788e3a5c07c81ef7d1e97c1c78ed03041a18f75df104c45405", size = 13283998, upload-time = "2025-12-18T19:29:06.994Z" }, + { url = "https://files.pythonhosted.org/packages/12/84/534a5506f4074e5cc0529e5cd96cfc01bb480e460c7edf5af70d2bcae55e/ruff-0.14.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:c70427132db492d25f982fffc8d6c7535cc2fd2c83fc8888f05caaa248521e60", size = 13601891, upload-time = "2025-12-18T19:28:55.811Z" }, + { url = "https://files.pythonhosted.org/packages/0d/1e/14c916087d8598917dbad9b2921d340f7884824ad6e9c55de948a93b106d/ruff-0.14.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5bcf45b681e9f1ee6445d317ce1fa9d6cba9a6049542d1c3d5b5958986be8830", size = 14336660, upload-time = "2025-12-18T19:29:16.531Z" }, + { url = "https://files.pythonhosted.org/packages/f2/1c/d7b67ab43f30013b47c12b42d1acd354c195351a3f7a1d67f59e54227ede/ruff-0.14.10-py3-none-win32.whl", hash = "sha256:104c49fc7ab73f3f3a758039adea978869a918f31b73280db175b43a2d9b51d6", size = 13196187, upload-time = "2025-12-18T19:29:19.006Z" }, + { url = "https://files.pythonhosted.org/packages/fb/9c/896c862e13886fae2af961bef3e6312db9ebc6adc2b156fe95e615dee8c1/ruff-0.14.10-py3-none-win_amd64.whl", hash = "sha256:466297bd73638c6bdf06485683e812db1c00c7ac96d4ddd0294a338c62fdc154", size = 14661283, upload-time = "2025-12-18T19:29:30.16Z" }, + { url = "https://files.pythonhosted.org/packages/74/31/b0e29d572670dca3674eeee78e418f20bdf97fa8aa9ea71380885e175ca0/ruff-0.14.10-py3-none-win_arm64.whl", hash = "sha256:e51d046cf6dda98a4633b8a8a771451107413b0f07183b2bef03f075599e44e6", size = 13729839, upload-time = "2025-12-18T19:28:48.636Z" }, +] + +[[package]] +name = "snowballstemmer" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/75/a7/9810d872919697c9d01295633f5d574fb416d47e535f258272ca1f01f447/snowballstemmer-3.0.1.tar.gz", hash = "sha256:6d5eeeec8e9f84d4d56b847692bacf79bc2c8e90c7f80ca4444ff8b6f2e52895", size = 105575, upload-time = "2025-05-09T16:34:51.843Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/78/3565d011c61f5a43488987ee32b6f3f656e7f107ac2782dd57bdd7d91d9a/snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064", size = 103274, upload-time = "2025-05-09T16:34:50.371Z" }, +] + +[[package]] +name = "soupsieve" +version = "2.8.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/89/23/adf3796d740536d63a6fbda113d07e60c734b6ed5d3058d1e47fc0495e47/soupsieve-2.8.1.tar.gz", hash = "sha256:4cf733bc50fa805f5df4b8ef4740fc0e0fa6218cf3006269afd3f9d6d80fd350", size = 117856, upload-time = "2025-12-18T13:50:34.655Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/f3/b67d6ea49ca9154453b6d70b34ea22f3996b9fa55da105a79d8732227adc/soupsieve-2.8.1-py3-none-any.whl", hash = "sha256:a11fe2a6f3d76ab3cf2de04eb339c1be5b506a8a47f2ceb6d139803177f85434", size = 36710, upload-time = "2025-12-18T13:50:33.267Z" }, +] + +[[package]] +name = "sphinx" +version = "8.1.3" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11'", +] +dependencies = [ + { name = "alabaster", marker = "python_full_version < '3.11'" }, + { name = "babel", marker = "python_full_version < '3.11'" }, + { name = "colorama", marker = "python_full_version < '3.11' and sys_platform == 'win32'" }, + { name = "docutils", marker = "python_full_version < '3.11'" }, + { name = "imagesize", marker = "python_full_version < '3.11'" }, + { name = "jinja2", marker = "python_full_version < '3.11'" }, + { name = "packaging", marker = "python_full_version < '3.11'" }, + { name = "pygments", marker = "python_full_version < '3.11'" }, + { name = "requests", marker = "python_full_version < '3.11'" }, + { name = "snowballstemmer", marker = "python_full_version < '3.11'" }, + { name = "sphinxcontrib-applehelp", marker = "python_full_version < '3.11'" }, + { name = "sphinxcontrib-devhelp", marker = "python_full_version < '3.11'" }, + { name = "sphinxcontrib-htmlhelp", marker = "python_full_version < '3.11'" }, + { name = "sphinxcontrib-jsmath", marker = "python_full_version < '3.11'" }, + { name = "sphinxcontrib-qthelp", marker = "python_full_version < '3.11'" }, + { name = "sphinxcontrib-serializinghtml", marker = "python_full_version < '3.11'" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/be0b61178fe2cdcb67e2a92fc9ebb488e3c51c4f74a36a7824c0adf23425/sphinx-8.1.3.tar.gz", hash = "sha256:43c1911eecb0d3e161ad78611bc905d1ad0e523e4ddc202a58a821773dc4c927", size = 8184611, upload-time = "2024-10-13T20:27:13.93Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/60/1ddff83a56d33aaf6f10ec8ce84b4c007d9368b21008876fceda7e7381ef/sphinx-8.1.3-py3-none-any.whl", hash = "sha256:09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2", size = 3487125, upload-time = "2024-10-13T20:27:10.448Z" }, +] + +[[package]] +name = "sphinx" +version = "8.2.3" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.11'", +] +dependencies = [ + { name = "alabaster", marker = "python_full_version >= '3.11'" }, + { name = "babel", marker = "python_full_version >= '3.11'" }, + { name = "colorama", marker = "python_full_version >= '3.11' and sys_platform == 'win32'" }, + { name = "docutils", marker = "python_full_version >= '3.11'" }, + { name = "imagesize", marker = "python_full_version >= '3.11'" }, + { name = "jinja2", marker = "python_full_version >= '3.11'" }, + { name = "packaging", marker = "python_full_version >= '3.11'" }, + { name = "pygments", marker = "python_full_version >= '3.11'" }, + { name = "requests", marker = "python_full_version >= '3.11'" }, + { name = "roman-numerals-py", marker = "python_full_version >= '3.11'" }, + { name = "snowballstemmer", marker = "python_full_version >= '3.11'" }, + { name = "sphinxcontrib-applehelp", marker = "python_full_version >= '3.11'" }, + { name = "sphinxcontrib-devhelp", marker = "python_full_version >= '3.11'" }, + { name = "sphinxcontrib-htmlhelp", marker = "python_full_version >= '3.11'" }, + { name = "sphinxcontrib-jsmath", marker = "python_full_version >= '3.11'" }, + { name = "sphinxcontrib-qthelp", marker = "python_full_version >= '3.11'" }, + { name = "sphinxcontrib-serializinghtml", marker = "python_full_version >= '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/ad/4360e50ed56cb483667b8e6dadf2d3fda62359593faabbe749a27c4eaca6/sphinx-8.2.3.tar.gz", hash = "sha256:398ad29dee7f63a75888314e9424d40f52ce5a6a87ae88e7071e80af296ec348", size = 8321876, upload-time = "2025-03-02T22:31:59.658Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/31/53/136e9eca6e0b9dc0e1962e2c908fbea2e5ac000c2a2fbd9a35797958c48b/sphinx-8.2.3-py3-none-any.whl", hash = "sha256:4405915165f13521d875a8c29c8970800a0141c14cc5416a38feca4ea5d9b9c3", size = 3589741, upload-time = "2025-03-02T22:31:56.836Z" }, +] + +[[package]] +name = "sphinx-autobuild" +version = "2024.10.3" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11'", +] +dependencies = [ + { name = "colorama", marker = "python_full_version < '3.11'" }, + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "starlette", marker = "python_full_version < '3.11'" }, + { name = "uvicorn", marker = "python_full_version < '3.11'" }, + { name = "watchfiles", marker = "python_full_version < '3.11'" }, + { name = "websockets", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a5/2c/155e1de2c1ba96a72e5dba152c509a8b41e047ee5c2def9e9f0d812f8be7/sphinx_autobuild-2024.10.3.tar.gz", hash = "sha256:248150f8f333e825107b6d4b86113ab28fa51750e5f9ae63b59dc339be951fb1", size = 14023, upload-time = "2024-10-02T23:15:30.172Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/c0/eba125db38c84d3c74717008fd3cb5000b68cd7e2cbafd1349c6a38c3d3b/sphinx_autobuild-2024.10.3-py3-none-any.whl", hash = "sha256:158e16c36f9d633e613c9aaf81c19b0fc458ca78b112533b20dafcda430d60fa", size = 11908, upload-time = "2024-10-02T23:15:28.739Z" }, +] + +[[package]] +name = "sphinx-autobuild" +version = "2025.8.25" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.11'", +] +dependencies = [ + { name = "colorama", marker = "python_full_version >= '3.11'" }, + { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "starlette", marker = "python_full_version >= '3.11'" }, + { name = "uvicorn", marker = "python_full_version >= '3.11'" }, + { name = "watchfiles", marker = "python_full_version >= '3.11'" }, + { name = "websockets", marker = "python_full_version >= '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e0/3c/a59a3a453d4133777f7ed2e83c80b7dc817d43c74b74298ca0af869662ad/sphinx_autobuild-2025.8.25.tar.gz", hash = "sha256:9cf5aab32853c8c31af572e4fecdc09c997e2b8be5a07daf2a389e270e85b213", size = 15200, upload-time = "2025-08-25T18:44:55.436Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/20/56411b52f917696995f5ad27d2ea7e9492c84a043c5b49a3a3173573cd93/sphinx_autobuild-2025.8.25-py3-none-any.whl", hash = "sha256:b750ac7d5a18603e4665294323fd20f6dcc0a984117026d1986704fa68f0379a", size = 12535, upload-time = "2025-08-25T18:44:54.164Z" }, +] + +[[package]] +name = "sphinx-autodoc-typehints" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11'", +] +dependencies = [ + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/26/f0/43c6a5ff3e7b08a8c3b32f81b859f1b518ccc31e45f22e2b41ced38be7b9/sphinx_autodoc_typehints-3.0.1.tar.gz", hash = "sha256:b9b40dd15dee54f6f810c924f863f9cf1c54f9f3265c495140ea01be7f44fa55", size = 36282, upload-time = "2025-01-16T18:25:30.958Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/dc/dc46c5c7c566b7ec5e8f860f9c89533bf03c0e6aadc96fb9b337867e4460/sphinx_autodoc_typehints-3.0.1-py3-none-any.whl", hash = "sha256:4b64b676a14b5b79cefb6628a6dc8070e320d4963e8ff640a2f3e9390ae9045a", size = 20245, upload-time = "2025-01-16T18:25:27.394Z" }, +] + +[[package]] +name = "sphinx-autodoc-typehints" +version = "3.5.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.11'", +] +dependencies = [ + { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/34/4f/4fd5583678bb7dc8afa69e9b309e6a99ee8d79ad3a4728f4e52fd7cb37c7/sphinx_autodoc_typehints-3.5.2.tar.gz", hash = "sha256:5fcd4a3eb7aa89424c1e2e32bedca66edc38367569c9169a80f4b3e934171fdb", size = 37839, upload-time = "2025-10-16T00:50:15.743Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/f2/9657c98a66973b7c35bfd48ba65d1922860de9598fbb535cd96e3f58a908/sphinx_autodoc_typehints-3.5.2-py3-none-any.whl", hash = "sha256:0accd043619f53c86705958e323b419e41667917045ac9215d7be1b493648d8c", size = 21184, upload-time = "2025-10-16T00:50:13.973Z" }, +] + +[[package]] +name = "sphinx-basic-ng" +version = "1.0.0b2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/0b/a866924ded68efec7a1759587a4e478aec7559d8165fac8b2ad1c0e774d6/sphinx_basic_ng-1.0.0b2.tar.gz", hash = "sha256:9ec55a47c90c8c002b5960c57492ec3021f5193cb26cebc2dc4ea226848651c9", size = 20736, upload-time = "2023-07-08T18:40:54.166Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/dd/018ce05c532a22007ac58d4f45232514cd9d6dd0ee1dc374e309db830983/sphinx_basic_ng-1.0.0b2-py3-none-any.whl", hash = "sha256:eb09aedbabfb650607e9b4b68c9d240b90b1e1be221d6ad71d61c52e29f7932b", size = 22496, upload-time = "2023-07-08T18:40:52.659Z" }, +] + +[[package]] +name = "sphinx-copybutton" +version = "0.5.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/2b/a964715e7f5295f77509e59309959f4125122d648f86b4fe7d70ca1d882c/sphinx-copybutton-0.5.2.tar.gz", hash = "sha256:4cf17c82fb9646d1bc9ca92ac280813a3b605d8c421225fd9913154103ee1fbd", size = 23039, upload-time = "2023-04-14T08:10:22.998Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/48/1ea60e74949eecb12cdd6ac43987f9fd331156388dcc2319b45e2ebb81bf/sphinx_copybutton-0.5.2-py3-none-any.whl", hash = "sha256:fb543fd386d917746c9a2c50360c7905b605726b9355cd26e9974857afeae06e", size = 13343, upload-time = "2023-04-14T08:10:20.844Z" }, +] + +[[package]] +name = "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-jsmath" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787, upload-time = "2019-01-21T16:10:16.347Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071, upload-time = "2019-01-21T16:10:14.333Z" }, +] + +[[package]] +name = "sphinxcontrib-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 = "starlette" +version = "0.50.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ba/b8/73a0e6a6e079a9d9cfa64113d771e421640b6f679a52eeb9b32f72d871a1/starlette-0.50.0.tar.gz", hash = "sha256:a2a17b22203254bcbc2e1f926d2d55f3f9497f769416b3190768befe598fa3ca", size = 2646985, upload-time = "2025-11-01T15:25:27.516Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/52/1064f510b141bd54025f9b55105e26d1fa970b9be67ad766380a3c9b74b0/starlette-0.50.0-py3-none-any.whl", hash = "sha256:9e5391843ec9b6e472eed1365a78c8098cfceb7a74bfd4d6b1c0c0095efb3bca", size = 74033, upload-time = "2025-11-01T15:25:25.461Z" }, +] + +[[package]] +name = "tomli" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/52/ed/3f73f72945444548f33eba9a87fc7a6e969915e7b1acc8260b30e1f76a2f/tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549", size = 17392, upload-time = "2025-10-08T22:01:47.119Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/2e/299f62b401438d5fe1624119c723f5d877acc86a4c2492da405626665f12/tomli-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45", size = 153236, upload-time = "2025-10-08T22:01:00.137Z" }, + { url = "https://files.pythonhosted.org/packages/86/7f/d8fffe6a7aefdb61bced88fcb5e280cfd71e08939da5894161bd71bea022/tomli-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba", size = 148084, upload-time = "2025-10-08T22:01:01.63Z" }, + { url = "https://files.pythonhosted.org/packages/47/5c/24935fb6a2ee63e86d80e4d3b58b222dafaf438c416752c8b58537c8b89a/tomli-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d1381caf13ab9f300e30dd8feadb3de072aeb86f1d34a8569453ff32a7dea4bf", size = 234832, upload-time = "2025-10-08T22:01:02.543Z" }, + { url = "https://files.pythonhosted.org/packages/89/da/75dfd804fc11e6612846758a23f13271b76d577e299592b4371a4ca4cd09/tomli-2.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a0e285d2649b78c0d9027570d4da3425bdb49830a6156121360b3f8511ea3441", size = 242052, upload-time = "2025-10-08T22:01:03.836Z" }, + { url = "https://files.pythonhosted.org/packages/70/8c/f48ac899f7b3ca7eb13af73bacbc93aec37f9c954df3c08ad96991c8c373/tomli-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a154a9ae14bfcf5d8917a59b51ffd5a3ac1fd149b71b47a3a104ca4edcfa845", size = 239555, upload-time = "2025-10-08T22:01:04.834Z" }, + { url = "https://files.pythonhosted.org/packages/ba/28/72f8afd73f1d0e7829bfc093f4cb98ce0a40ffc0cc997009ee1ed94ba705/tomli-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:74bf8464ff93e413514fefd2be591c3b0b23231a77f901db1eb30d6f712fc42c", size = 245128, upload-time = "2025-10-08T22:01:05.84Z" }, + { url = "https://files.pythonhosted.org/packages/b6/eb/a7679c8ac85208706d27436e8d421dfa39d4c914dcf5fa8083a9305f58d9/tomli-2.3.0-cp311-cp311-win32.whl", hash = "sha256:00b5f5d95bbfc7d12f91ad8c593a1659b6387b43f054104cda404be6bda62456", size = 96445, upload-time = "2025-10-08T22:01:06.896Z" }, + { url = "https://files.pythonhosted.org/packages/0a/fe/3d3420c4cb1ad9cb462fb52967080575f15898da97e21cb6f1361d505383/tomli-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:4dc4ce8483a5d429ab602f111a93a6ab1ed425eae3122032db7e9acf449451be", size = 107165, upload-time = "2025-10-08T22:01:08.107Z" }, + { url = "https://files.pythonhosted.org/packages/ff/b7/40f36368fcabc518bb11c8f06379a0fd631985046c038aca08c6d6a43c6e/tomli-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d7d86942e56ded512a594786a5ba0a5e521d02529b3826e7761a05138341a2ac", size = 154891, upload-time = "2025-10-08T22:01:09.082Z" }, + { url = "https://files.pythonhosted.org/packages/f9/3f/d9dd692199e3b3aab2e4e4dd948abd0f790d9ded8cd10cbaae276a898434/tomli-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:73ee0b47d4dad1c5e996e3cd33b8a76a50167ae5f96a2607cbe8cc773506ab22", size = 148796, upload-time = "2025-10-08T22:01:10.266Z" }, + { url = "https://files.pythonhosted.org/packages/60/83/59bff4996c2cf9f9387a0f5a3394629c7efa5ef16142076a23a90f1955fa/tomli-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:792262b94d5d0a466afb5bc63c7daa9d75520110971ee269152083270998316f", size = 242121, upload-time = "2025-10-08T22:01:11.332Z" }, + { url = "https://files.pythonhosted.org/packages/45/e5/7c5119ff39de8693d6baab6c0b6dcb556d192c165596e9fc231ea1052041/tomli-2.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f195fe57ecceac95a66a75ac24d9d5fbc98ef0962e09b2eddec5d39375aae52", size = 250070, upload-time = "2025-10-08T22:01:12.498Z" }, + { url = "https://files.pythonhosted.org/packages/45/12/ad5126d3a278f27e6701abde51d342aa78d06e27ce2bb596a01f7709a5a2/tomli-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e31d432427dcbf4d86958c184b9bfd1e96b5b71f8eb17e6d02531f434fd335b8", size = 245859, upload-time = "2025-10-08T22:01:13.551Z" }, + { url = "https://files.pythonhosted.org/packages/fb/a1/4d6865da6a71c603cfe6ad0e6556c73c76548557a8d658f9e3b142df245f/tomli-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b0882799624980785240ab732537fcfc372601015c00f7fc367c55308c186f6", size = 250296, upload-time = "2025-10-08T22:01:14.614Z" }, + { url = "https://files.pythonhosted.org/packages/a0/b7/a7a7042715d55c9ba6e8b196d65d2cb662578b4d8cd17d882d45322b0d78/tomli-2.3.0-cp312-cp312-win32.whl", hash = "sha256:ff72b71b5d10d22ecb084d345fc26f42b5143c5533db5e2eaba7d2d335358876", size = 97124, upload-time = "2025-10-08T22:01:15.629Z" }, + { url = "https://files.pythonhosted.org/packages/06/1e/f22f100db15a68b520664eb3328fb0ae4e90530887928558112c8d1f4515/tomli-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:1cb4ed918939151a03f33d4242ccd0aa5f11b3547d0cf30f7c74a408a5b99878", size = 107698, upload-time = "2025-10-08T22:01:16.51Z" }, + { url = "https://files.pythonhosted.org/packages/89/48/06ee6eabe4fdd9ecd48bf488f4ac783844fd777f547b8d1b61c11939974e/tomli-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5192f562738228945d7b13d4930baffda67b69425a7f0da96d360b0a3888136b", size = 154819, upload-time = "2025-10-08T22:01:17.964Z" }, + { url = "https://files.pythonhosted.org/packages/f1/01/88793757d54d8937015c75dcdfb673c65471945f6be98e6a0410fba167ed/tomli-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:be71c93a63d738597996be9528f4abe628d1adf5e6eb11607bc8fe1a510b5dae", size = 148766, upload-time = "2025-10-08T22:01:18.959Z" }, + { url = "https://files.pythonhosted.org/packages/42/17/5e2c956f0144b812e7e107f94f1cc54af734eb17b5191c0bbfb72de5e93e/tomli-2.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4665508bcbac83a31ff8ab08f424b665200c0e1e645d2bd9ab3d3e557b6185b", size = 240771, upload-time = "2025-10-08T22:01:20.106Z" }, + { url = "https://files.pythonhosted.org/packages/d5/f4/0fbd014909748706c01d16824eadb0307115f9562a15cbb012cd9b3512c5/tomli-2.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4021923f97266babc6ccab9f5068642a0095faa0a51a246a6a02fccbb3514eaf", size = 248586, upload-time = "2025-10-08T22:01:21.164Z" }, + { url = "https://files.pythonhosted.org/packages/30/77/fed85e114bde5e81ecf9bc5da0cc69f2914b38f4708c80ae67d0c10180c5/tomli-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4ea38c40145a357d513bffad0ed869f13c1773716cf71ccaa83b0fa0cc4e42f", size = 244792, upload-time = "2025-10-08T22:01:22.417Z" }, + { url = "https://files.pythonhosted.org/packages/55/92/afed3d497f7c186dc71e6ee6d4fcb0acfa5f7d0a1a2878f8beae379ae0cc/tomli-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad805ea85eda330dbad64c7ea7a4556259665bdf9d2672f5dccc740eb9d3ca05", size = 248909, upload-time = "2025-10-08T22:01:23.859Z" }, + { url = "https://files.pythonhosted.org/packages/f8/84/ef50c51b5a9472e7265ce1ffc7f24cd4023d289e109f669bdb1553f6a7c2/tomli-2.3.0-cp313-cp313-win32.whl", hash = "sha256:97d5eec30149fd3294270e889b4234023f2c69747e555a27bd708828353ab606", size = 96946, upload-time = "2025-10-08T22:01:24.893Z" }, + { url = "https://files.pythonhosted.org/packages/b2/b7/718cd1da0884f281f95ccfa3a6cc572d30053cba64603f79d431d3c9b61b/tomli-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0c95ca56fbe89e065c6ead5b593ee64b84a26fca063b5d71a1122bf26e533999", size = 107705, upload-time = "2025-10-08T22:01:26.153Z" }, + { url = "https://files.pythonhosted.org/packages/19/94/aeafa14a52e16163008060506fcb6aa1949d13548d13752171a755c65611/tomli-2.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cebc6fe843e0733ee827a282aca4999b596241195f43b4cc371d64fc6639da9e", size = 154244, upload-time = "2025-10-08T22:01:27.06Z" }, + { url = "https://files.pythonhosted.org/packages/db/e4/1e58409aa78eefa47ccd19779fc6f36787edbe7d4cd330eeeedb33a4515b/tomli-2.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4c2ef0244c75aba9355561272009d934953817c49f47d768070c3c94355c2aa3", size = 148637, upload-time = "2025-10-08T22:01:28.059Z" }, + { url = "https://files.pythonhosted.org/packages/26/b6/d1eccb62f665e44359226811064596dd6a366ea1f985839c566cd61525ae/tomli-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c22a8bf253bacc0cf11f35ad9808b6cb75ada2631c2d97c971122583b129afbc", size = 241925, upload-time = "2025-10-08T22:01:29.066Z" }, + { url = "https://files.pythonhosted.org/packages/70/91/7cdab9a03e6d3d2bb11beae108da5bdc1c34bdeb06e21163482544ddcc90/tomli-2.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0eea8cc5c5e9f89c9b90c4896a8deefc74f518db5927d0e0e8d4a80953d774d0", size = 249045, upload-time = "2025-10-08T22:01:31.98Z" }, + { url = "https://files.pythonhosted.org/packages/15/1b/8c26874ed1f6e4f1fcfeb868db8a794cbe9f227299402db58cfcc858766c/tomli-2.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b74a0e59ec5d15127acdabd75ea17726ac4c5178ae51b85bfe39c4f8a278e879", size = 245835, upload-time = "2025-10-08T22:01:32.989Z" }, + { url = "https://files.pythonhosted.org/packages/fd/42/8e3c6a9a4b1a1360c1a2a39f0b972cef2cc9ebd56025168c4137192a9321/tomli-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b5870b50c9db823c595983571d1296a6ff3e1b88f734a4c8f6fc6188397de005", size = 253109, upload-time = "2025-10-08T22:01:34.052Z" }, + { url = "https://files.pythonhosted.org/packages/22/0c/b4da635000a71b5f80130937eeac12e686eefb376b8dee113b4a582bba42/tomli-2.3.0-cp314-cp314-win32.whl", hash = "sha256:feb0dacc61170ed7ab602d3d972a58f14ee3ee60494292d384649a3dc38ef463", size = 97930, upload-time = "2025-10-08T22:01:35.082Z" }, + { url = "https://files.pythonhosted.org/packages/b9/74/cb1abc870a418ae99cd5c9547d6bce30701a954e0e721821df483ef7223c/tomli-2.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:b273fcbd7fc64dc3600c098e39136522650c49bca95df2d11cf3b626422392c8", size = 107964, upload-time = "2025-10-08T22:01:36.057Z" }, + { url = "https://files.pythonhosted.org/packages/54/78/5c46fff6432a712af9f792944f4fcd7067d8823157949f4e40c56b8b3c83/tomli-2.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:940d56ee0410fa17ee1f12b817b37a4d4e4dc4d27340863cc67236c74f582e77", size = 163065, upload-time = "2025-10-08T22:01:37.27Z" }, + { url = "https://files.pythonhosted.org/packages/39/67/f85d9bd23182f45eca8939cd2bc7050e1f90c41f4a2ecbbd5963a1d1c486/tomli-2.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f85209946d1fe94416debbb88d00eb92ce9cd5266775424ff81bc959e001acaf", size = 159088, upload-time = "2025-10-08T22:01:38.235Z" }, + { url = "https://files.pythonhosted.org/packages/26/5a/4b546a0405b9cc0659b399f12b6adb750757baf04250b148d3c5059fc4eb/tomli-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a56212bdcce682e56b0aaf79e869ba5d15a6163f88d5451cbde388d48b13f530", size = 268193, upload-time = "2025-10-08T22:01:39.712Z" }, + { url = "https://files.pythonhosted.org/packages/42/4f/2c12a72ae22cf7b59a7fe75b3465b7aba40ea9145d026ba41cb382075b0e/tomli-2.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5f3ffd1e098dfc032d4d3af5c0ac64f6d286d98bc148698356847b80fa4de1b", size = 275488, upload-time = "2025-10-08T22:01:40.773Z" }, + { url = "https://files.pythonhosted.org/packages/92/04/a038d65dbe160c3aa5a624e93ad98111090f6804027d474ba9c37c8ae186/tomli-2.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5e01decd096b1530d97d5d85cb4dff4af2d8347bd35686654a004f8dea20fc67", size = 272669, upload-time = "2025-10-08T22:01:41.824Z" }, + { url = "https://files.pythonhosted.org/packages/be/2f/8b7c60a9d1612a7cbc39ffcca4f21a73bf368a80fc25bccf8253e2563267/tomli-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8a35dd0e643bb2610f156cca8db95d213a90015c11fee76c946aa62b7ae7e02f", size = 279709, upload-time = "2025-10-08T22:01:43.177Z" }, + { url = "https://files.pythonhosted.org/packages/7e/46/cc36c679f09f27ded940281c38607716c86cf8ba4a518d524e349c8b4874/tomli-2.3.0-cp314-cp314t-win32.whl", hash = "sha256:a1f7f282fe248311650081faafa5f4732bdbfef5d45fe3f2e702fbc6f2d496e0", size = 107563, upload-time = "2025-10-08T22:01:44.233Z" }, + { url = "https://files.pythonhosted.org/packages/84/ff/426ca8683cf7b753614480484f6437f568fd2fda2edbdf57a2d3d8b27a0b/tomli-2.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:70a251f8d4ba2d9ac2542eecf008b3c8a9fc5c3f9f02c56a9d7952612be2fdba", size = 119756, upload-time = "2025-10-08T22:01:45.234Z" }, + { url = "https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", size = 14408, upload-time = "2025-10-08T22:01:46.04Z" }, +] + +[[package]] +name = "traitlets" +version = "5.14.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621, upload-time = "2024-04-19T11:11:49.746Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "urllib3" +version = "2.6.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1e/24/a2a2ed9addd907787d7aa0355ba36a6cadf1768b934c652ea78acbd59dcd/urllib3-2.6.2.tar.gz", hash = "sha256:016f9c98bb7e98085cb2b4b17b87d2c702975664e4f060c6532e64d1c1a5e797", size = 432930, upload-time = "2025-12-11T15:56:40.252Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/b9/4095b668ea3678bf6a0af005527f39de12fb026516fb3df17495a733b7f8/urllib3-2.6.2-py3-none-any.whl", hash = "sha256:ec21cddfe7724fc7cb4ba4bea7aa8e2ef36f607a4bab81aa6ce42a13dc3f03dd", size = 131182, upload-time = "2025-12-11T15:56:38.584Z" }, +] + +[[package]] +name = "uvicorn" +version = "0.40.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "h11" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c3/d1/8f3c683c9561a4e6689dd3b1d345c815f10f86acd044ee1fb9a4dcd0b8c5/uvicorn-0.40.0.tar.gz", hash = "sha256:839676675e87e73694518b5574fd0f24c9d97b46bea16df7b8c05ea1a51071ea", size = 81761, upload-time = "2025-12-21T14:16:22.45Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3d/d8/2083a1daa7439a66f3a48589a57d576aa117726762618f6bb09fe3798796/uvicorn-0.40.0-py3-none-any.whl", hash = "sha256:c6c8f55bc8bf13eb6fa9ff87ad62308bbbc33d0b67f84293151efe87e0d5f2ee", size = 68502, upload-time = "2025-12-21T14:16:21.041Z" }, +] + +[[package]] +name = "virtualenv" +version = "20.35.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "distlib" }, + { name = "filelock" }, + { name = "platformdirs" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/20/28/e6f1a6f655d620846bd9df527390ecc26b3805a0c5989048c210e22c5ca9/virtualenv-20.35.4.tar.gz", hash = "sha256:643d3914d73d3eeb0c552cbb12d7e82adf0e504dbf86a3182f8771a153a1971c", size = 6028799, upload-time = "2025-10-29T06:57:40.511Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/0c/c05523fa3181fdf0c9c52a6ba91a23fbf3246cc095f26f6516f9c60e6771/virtualenv-20.35.4-py3-none-any.whl", hash = "sha256:c21c9cede36c9753eeade68ba7d523529f228a403463376cf821eaae2b650f1b", size = 6005095, upload-time = "2025-10-29T06:57:37.598Z" }, +] + +[[package]] +name = "watchfiles" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c2/c9/8869df9b2a2d6c59d79220a4db37679e74f807c559ffe5265e08b227a210/watchfiles-1.1.1.tar.gz", hash = "sha256:a173cb5c16c4f40ab19cecf48a534c409f7ea983ab8fed0741304a1c0a31b3f2", size = 94440, upload-time = "2025-10-14T15:06:21.08Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/1a/206e8cf2dd86fddf939165a57b4df61607a1e0add2785f170a3f616b7d9f/watchfiles-1.1.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:eef58232d32daf2ac67f42dea51a2c80f0d03379075d44a587051e63cc2e368c", size = 407318, upload-time = "2025-10-14T15:04:18.753Z" }, + { url = "https://files.pythonhosted.org/packages/b3/0f/abaf5262b9c496b5dad4ed3c0e799cbecb1f8ea512ecb6ddd46646a9fca3/watchfiles-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03fa0f5237118a0c5e496185cafa92878568b652a2e9a9382a5151b1a0380a43", size = 394478, upload-time = "2025-10-14T15:04:20.297Z" }, + { url = "https://files.pythonhosted.org/packages/b1/04/9cc0ba88697b34b755371f5ace8d3a4d9a15719c07bdc7bd13d7d8c6a341/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ca65483439f9c791897f7db49202301deb6e15fe9f8fe2fed555bf986d10c31", size = 449894, upload-time = "2025-10-14T15:04:21.527Z" }, + { url = "https://files.pythonhosted.org/packages/d2/9c/eda4615863cd8621e89aed4df680d8c3ec3da6a4cf1da113c17decd87c7f/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f0ab1c1af0cb38e3f598244c17919fb1a84d1629cc08355b0074b6d7f53138ac", size = 459065, upload-time = "2025-10-14T15:04:22.795Z" }, + { url = "https://files.pythonhosted.org/packages/84/13/f28b3f340157d03cbc8197629bc109d1098764abe1e60874622a0be5c112/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bc570d6c01c206c46deb6e935a260be44f186a2f05179f52f7fcd2be086a94d", size = 488377, upload-time = "2025-10-14T15:04:24.138Z" }, + { url = "https://files.pythonhosted.org/packages/86/93/cfa597fa9389e122488f7ffdbd6db505b3b915ca7435ecd7542e855898c2/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e84087b432b6ac94778de547e08611266f1f8ffad28c0ee4c82e028b0fc5966d", size = 595837, upload-time = "2025-10-14T15:04:25.057Z" }, + { url = "https://files.pythonhosted.org/packages/57/1e/68c1ed5652b48d89fc24d6af905d88ee4f82fa8bc491e2666004e307ded1/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:620bae625f4cb18427b1bb1a2d9426dc0dd5a5ba74c7c2cdb9de405f7b129863", size = 473456, upload-time = "2025-10-14T15:04:26.497Z" }, + { url = "https://files.pythonhosted.org/packages/d5/dc/1a680b7458ffa3b14bb64878112aefc8f2e4f73c5af763cbf0bd43100658/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:544364b2b51a9b0c7000a4b4b02f90e9423d97fbbf7e06689236443ebcad81ab", size = 455614, upload-time = "2025-10-14T15:04:27.539Z" }, + { url = "https://files.pythonhosted.org/packages/61/a5/3d782a666512e01eaa6541a72ebac1d3aae191ff4a31274a66b8dd85760c/watchfiles-1.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bbe1ef33d45bc71cf21364df962af171f96ecaeca06bd9e3d0b583efb12aec82", size = 630690, upload-time = "2025-10-14T15:04:28.495Z" }, + { url = "https://files.pythonhosted.org/packages/9b/73/bb5f38590e34687b2a9c47a244aa4dd50c56a825969c92c9c5fc7387cea1/watchfiles-1.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1a0bb430adb19ef49389e1ad368450193a90038b5b752f4ac089ec6942c4dff4", size = 622459, upload-time = "2025-10-14T15:04:29.491Z" }, + { url = "https://files.pythonhosted.org/packages/f1/ac/c9bb0ec696e07a20bd58af5399aeadaef195fb2c73d26baf55180fe4a942/watchfiles-1.1.1-cp310-cp310-win32.whl", hash = "sha256:3f6d37644155fb5beca5378feb8c1708d5783145f2a0f1c4d5a061a210254844", size = 272663, upload-time = "2025-10-14T15:04:30.435Z" }, + { url = "https://files.pythonhosted.org/packages/11/a0/a60c5a7c2ec59fa062d9a9c61d02e3b6abd94d32aac2d8344c4bdd033326/watchfiles-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:a36d8efe0f290835fd0f33da35042a1bb5dc0e83cbc092dcf69bce442579e88e", size = 287453, upload-time = "2025-10-14T15:04:31.53Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f8/2c5f479fb531ce2f0564eda479faecf253d886b1ab3630a39b7bf7362d46/watchfiles-1.1.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:f57b396167a2565a4e8b5e56a5a1c537571733992b226f4f1197d79e94cf0ae5", size = 406529, upload-time = "2025-10-14T15:04:32.899Z" }, + { url = "https://files.pythonhosted.org/packages/fe/cd/f515660b1f32f65df671ddf6f85bfaca621aee177712874dc30a97397977/watchfiles-1.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:421e29339983e1bebc281fab40d812742268ad057db4aee8c4d2bce0af43b741", size = 394384, upload-time = "2025-10-14T15:04:33.761Z" }, + { url = "https://files.pythonhosted.org/packages/7b/c3/28b7dc99733eab43fca2d10f55c86e03bd6ab11ca31b802abac26b23d161/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e43d39a741e972bab5d8100b5cdacf69db64e34eb19b6e9af162bccf63c5cc6", size = 448789, upload-time = "2025-10-14T15:04:34.679Z" }, + { url = "https://files.pythonhosted.org/packages/4a/24/33e71113b320030011c8e4316ccca04194bf0cbbaeee207f00cbc7d6b9f5/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f537afb3276d12814082a2e9b242bdcf416c2e8fd9f799a737990a1dbe906e5b", size = 460521, upload-time = "2025-10-14T15:04:35.963Z" }, + { url = "https://files.pythonhosted.org/packages/f4/c3/3c9a55f255aa57b91579ae9e98c88704955fa9dac3e5614fb378291155df/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2cd9e04277e756a2e2d2543d65d1e2166d6fd4c9b183f8808634fda23f17b14", size = 488722, upload-time = "2025-10-14T15:04:37.091Z" }, + { url = "https://files.pythonhosted.org/packages/49/36/506447b73eb46c120169dc1717fe2eff07c234bb3232a7200b5f5bd816e9/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5f3f58818dc0b07f7d9aa7fe9eb1037aecb9700e63e1f6acfed13e9fef648f5d", size = 596088, upload-time = "2025-10-14T15:04:38.39Z" }, + { url = "https://files.pythonhosted.org/packages/82/ab/5f39e752a9838ec4d52e9b87c1e80f1ee3ccdbe92e183c15b6577ab9de16/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bb9f66367023ae783551042d31b1d7fd422e8289eedd91f26754a66f44d5cff", size = 472923, upload-time = "2025-10-14T15:04:39.666Z" }, + { url = "https://files.pythonhosted.org/packages/af/b9/a419292f05e302dea372fa7e6fda5178a92998411f8581b9830d28fb9edb/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aebfd0861a83e6c3d1110b78ad54704486555246e542be3e2bb94195eabb2606", size = 456080, upload-time = "2025-10-14T15:04:40.643Z" }, + { url = "https://files.pythonhosted.org/packages/b0/c3/d5932fd62bde1a30c36e10c409dc5d54506726f08cb3e1d8d0ba5e2bc8db/watchfiles-1.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5fac835b4ab3c6487b5dbad78c4b3724e26bcc468e886f8ba8cc4306f68f6701", size = 629432, upload-time = "2025-10-14T15:04:41.789Z" }, + { url = "https://files.pythonhosted.org/packages/f7/77/16bddd9779fafb795f1a94319dc965209c5641db5bf1edbbccace6d1b3c0/watchfiles-1.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:399600947b170270e80134ac854e21b3ccdefa11a9529a3decc1327088180f10", size = 623046, upload-time = "2025-10-14T15:04:42.718Z" }, + { url = "https://files.pythonhosted.org/packages/46/ef/f2ecb9a0f342b4bfad13a2787155c6ee7ce792140eac63a34676a2feeef2/watchfiles-1.1.1-cp311-cp311-win32.whl", hash = "sha256:de6da501c883f58ad50db3a32ad397b09ad29865b5f26f64c24d3e3281685849", size = 271473, upload-time = "2025-10-14T15:04:43.624Z" }, + { url = "https://files.pythonhosted.org/packages/94/bc/f42d71125f19731ea435c3948cad148d31a64fccde3867e5ba4edee901f9/watchfiles-1.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:35c53bd62a0b885bf653ebf6b700d1bf05debb78ad9292cf2a942b23513dc4c4", size = 287598, upload-time = "2025-10-14T15:04:44.516Z" }, + { url = "https://files.pythonhosted.org/packages/57/c9/a30f897351f95bbbfb6abcadafbaca711ce1162f4db95fc908c98a9165f3/watchfiles-1.1.1-cp311-cp311-win_arm64.whl", hash = "sha256:57ca5281a8b5e27593cb7d82c2ac927ad88a96ed406aa446f6344e4328208e9e", size = 277210, upload-time = "2025-10-14T15:04:45.883Z" }, + { url = "https://files.pythonhosted.org/packages/74/d5/f039e7e3c639d9b1d09b07ea412a6806d38123f0508e5f9b48a87b0a76cc/watchfiles-1.1.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:8c89f9f2f740a6b7dcc753140dd5e1ab9215966f7a3530d0c0705c83b401bd7d", size = 404745, upload-time = "2025-10-14T15:04:46.731Z" }, + { url = "https://files.pythonhosted.org/packages/a5/96/a881a13aa1349827490dab2d363c8039527060cfcc2c92cc6d13d1b1049e/watchfiles-1.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bd404be08018c37350f0d6e34676bd1e2889990117a2b90070b3007f172d0610", size = 391769, upload-time = "2025-10-14T15:04:48.003Z" }, + { url = "https://files.pythonhosted.org/packages/4b/5b/d3b460364aeb8da471c1989238ea0e56bec24b6042a68046adf3d9ddb01c/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8526e8f916bb5b9a0a777c8317c23ce65de259422bba5b31325a6fa6029d33af", size = 449374, upload-time = "2025-10-14T15:04:49.179Z" }, + { url = "https://files.pythonhosted.org/packages/b9/44/5769cb62d4ed055cb17417c0a109a92f007114a4e07f30812a73a4efdb11/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2edc3553362b1c38d9f06242416a5d8e9fe235c204a4072e988ce2e5bb1f69f6", size = 459485, upload-time = "2025-10-14T15:04:50.155Z" }, + { url = "https://files.pythonhosted.org/packages/19/0c/286b6301ded2eccd4ffd0041a1b726afda999926cf720aab63adb68a1e36/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30f7da3fb3f2844259cba4720c3fc7138eb0f7b659c38f3bfa65084c7fc7abce", size = 488813, upload-time = "2025-10-14T15:04:51.059Z" }, + { url = "https://files.pythonhosted.org/packages/c7/2b/8530ed41112dd4a22f4dcfdb5ccf6a1baad1ff6eed8dc5a5f09e7e8c41c7/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8979280bdafff686ba5e4d8f97840f929a87ed9cdf133cbbd42f7766774d2aa", size = 594816, upload-time = "2025-10-14T15:04:52.031Z" }, + { url = "https://files.pythonhosted.org/packages/ce/d2/f5f9fb49489f184f18470d4f99f4e862a4b3e9ac2865688eb2099e3d837a/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dcc5c24523771db3a294c77d94771abcfcb82a0e0ee8efd910c37c59ec1b31bb", size = 475186, upload-time = "2025-10-14T15:04:53.064Z" }, + { url = "https://files.pythonhosted.org/packages/cf/68/5707da262a119fb06fbe214d82dd1fe4a6f4af32d2d14de368d0349eb52a/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1db5d7ae38ff20153d542460752ff397fcf5c96090c1230803713cf3147a6803", size = 456812, upload-time = "2025-10-14T15:04:55.174Z" }, + { url = "https://files.pythonhosted.org/packages/66/ab/3cbb8756323e8f9b6f9acb9ef4ec26d42b2109bce830cc1f3468df20511d/watchfiles-1.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:28475ddbde92df1874b6c5c8aaeb24ad5be47a11f87cde5a28ef3835932e3e94", size = 630196, upload-time = "2025-10-14T15:04:56.22Z" }, + { url = "https://files.pythonhosted.org/packages/78/46/7152ec29b8335f80167928944a94955015a345440f524d2dfe63fc2f437b/watchfiles-1.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:36193ed342f5b9842edd3532729a2ad55c4160ffcfa3700e0d54be496b70dd43", size = 622657, upload-time = "2025-10-14T15:04:57.521Z" }, + { url = "https://files.pythonhosted.org/packages/0a/bf/95895e78dd75efe9a7f31733607f384b42eb5feb54bd2eb6ed57cc2e94f4/watchfiles-1.1.1-cp312-cp312-win32.whl", hash = "sha256:859e43a1951717cc8de7f4c77674a6d389b106361585951d9e69572823f311d9", size = 272042, upload-time = "2025-10-14T15:04:59.046Z" }, + { url = "https://files.pythonhosted.org/packages/87/0a/90eb755f568de2688cb220171c4191df932232c20946966c27a59c400850/watchfiles-1.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:91d4c9a823a8c987cce8fa2690923b069966dabb196dd8d137ea2cede885fde9", size = 288410, upload-time = "2025-10-14T15:05:00.081Z" }, + { url = "https://files.pythonhosted.org/packages/36/76/f322701530586922fbd6723c4f91ace21364924822a8772c549483abed13/watchfiles-1.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:a625815d4a2bdca61953dbba5a39d60164451ef34c88d751f6c368c3ea73d404", size = 278209, upload-time = "2025-10-14T15:05:01.168Z" }, + { url = "https://files.pythonhosted.org/packages/bb/f4/f750b29225fe77139f7ae5de89d4949f5a99f934c65a1f1c0b248f26f747/watchfiles-1.1.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:130e4876309e8686a5e37dba7d5e9bc77e6ed908266996ca26572437a5271e18", size = 404321, upload-time = "2025-10-14T15:05:02.063Z" }, + { url = "https://files.pythonhosted.org/packages/2b/f9/f07a295cde762644aa4c4bb0f88921d2d141af45e735b965fb2e87858328/watchfiles-1.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5f3bde70f157f84ece3765b42b4a52c6ac1a50334903c6eaf765362f6ccca88a", size = 391783, upload-time = "2025-10-14T15:05:03.052Z" }, + { url = "https://files.pythonhosted.org/packages/bc/11/fc2502457e0bea39a5c958d86d2cb69e407a4d00b85735ca724bfa6e0d1a/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14e0b1fe858430fc0251737ef3824c54027bedb8c37c38114488b8e131cf8219", size = 449279, upload-time = "2025-10-14T15:05:04.004Z" }, + { url = "https://files.pythonhosted.org/packages/e3/1f/d66bc15ea0b728df3ed96a539c777acfcad0eb78555ad9efcaa1274688f0/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f27db948078f3823a6bb3b465180db8ebecf26dd5dae6f6180bd87383b6b4428", size = 459405, upload-time = "2025-10-14T15:05:04.942Z" }, + { url = "https://files.pythonhosted.org/packages/be/90/9f4a65c0aec3ccf032703e6db02d89a157462fbb2cf20dd415128251cac0/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:059098c3a429f62fc98e8ec62b982230ef2c8df68c79e826e37b895bc359a9c0", size = 488976, upload-time = "2025-10-14T15:05:05.905Z" }, + { url = "https://files.pythonhosted.org/packages/37/57/ee347af605d867f712be7029bb94c8c071732a4b44792e3176fa3c612d39/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfb5862016acc9b869bb57284e6cb35fdf8e22fe59f7548858e2f971d045f150", size = 595506, upload-time = "2025-10-14T15:05:06.906Z" }, + { url = "https://files.pythonhosted.org/packages/a8/78/cc5ab0b86c122047f75e8fc471c67a04dee395daf847d3e59381996c8707/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:319b27255aacd9923b8a276bb14d21a5f7ff82564c744235fc5eae58d95422ae", size = 474936, upload-time = "2025-10-14T15:05:07.906Z" }, + { url = "https://files.pythonhosted.org/packages/62/da/def65b170a3815af7bd40a3e7010bf6ab53089ef1b75d05dd5385b87cf08/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c755367e51db90e75b19454b680903631d41f9e3607fbd941d296a020c2d752d", size = 456147, upload-time = "2025-10-14T15:05:09.138Z" }, + { url = "https://files.pythonhosted.org/packages/57/99/da6573ba71166e82d288d4df0839128004c67d2778d3b566c138695f5c0b/watchfiles-1.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c22c776292a23bfc7237a98f791b9ad3144b02116ff10d820829ce62dff46d0b", size = 630007, upload-time = "2025-10-14T15:05:10.117Z" }, + { url = "https://files.pythonhosted.org/packages/a8/51/7439c4dd39511368849eb1e53279cd3454b4a4dbace80bab88feeb83c6b5/watchfiles-1.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:3a476189be23c3686bc2f4321dd501cb329c0a0469e77b7b534ee10129ae6374", size = 622280, upload-time = "2025-10-14T15:05:11.146Z" }, + { url = "https://files.pythonhosted.org/packages/95/9c/8ed97d4bba5db6fdcdb2b298d3898f2dd5c20f6b73aee04eabe56c59677e/watchfiles-1.1.1-cp313-cp313-win32.whl", hash = "sha256:bf0a91bfb5574a2f7fc223cf95eeea79abfefa404bf1ea5e339c0c1560ae99a0", size = 272056, upload-time = "2025-10-14T15:05:12.156Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f3/c14e28429f744a260d8ceae18bf58c1d5fa56b50d006a7a9f80e1882cb0d/watchfiles-1.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:52e06553899e11e8074503c8e716d574adeeb7e68913115c4b3653c53f9bae42", size = 288162, upload-time = "2025-10-14T15:05:13.208Z" }, + { url = "https://files.pythonhosted.org/packages/dc/61/fe0e56c40d5cd29523e398d31153218718c5786b5e636d9ae8ae79453d27/watchfiles-1.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:ac3cc5759570cd02662b15fbcd9d917f7ecd47efe0d6b40474eafd246f91ea18", size = 277909, upload-time = "2025-10-14T15:05:14.49Z" }, + { url = "https://files.pythonhosted.org/packages/79/42/e0a7d749626f1e28c7108a99fb9bf524b501bbbeb9b261ceecde644d5a07/watchfiles-1.1.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:563b116874a9a7ce6f96f87cd0b94f7faf92d08d0021e837796f0a14318ef8da", size = 403389, upload-time = "2025-10-14T15:05:15.777Z" }, + { url = "https://files.pythonhosted.org/packages/15/49/08732f90ce0fbbc13913f9f215c689cfc9ced345fb1bcd8829a50007cc8d/watchfiles-1.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3ad9fe1dae4ab4212d8c91e80b832425e24f421703b5a42ef2e4a1e215aff051", size = 389964, upload-time = "2025-10-14T15:05:16.85Z" }, + { url = "https://files.pythonhosted.org/packages/27/0d/7c315d4bd5f2538910491a0393c56bf70d333d51bc5b34bee8e68e8cea19/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce70f96a46b894b36eba678f153f052967a0d06d5b5a19b336ab0dbbd029f73e", size = 448114, upload-time = "2025-10-14T15:05:17.876Z" }, + { url = "https://files.pythonhosted.org/packages/c3/24/9e096de47a4d11bc4df41e9d1e61776393eac4cb6eb11b3e23315b78b2cc/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cb467c999c2eff23a6417e58d75e5828716f42ed8289fe6b77a7e5a91036ca70", size = 460264, upload-time = "2025-10-14T15:05:18.962Z" }, + { url = "https://files.pythonhosted.org/packages/cc/0f/e8dea6375f1d3ba5fcb0b3583e2b493e77379834c74fd5a22d66d85d6540/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:836398932192dae4146c8f6f737d74baeac8b70ce14831a239bdb1ca882fc261", size = 487877, upload-time = "2025-10-14T15:05:20.094Z" }, + { url = "https://files.pythonhosted.org/packages/ac/5b/df24cfc6424a12deb41503b64d42fbea6b8cb357ec62ca84a5a3476f654a/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:743185e7372b7bc7c389e1badcc606931a827112fbbd37f14c537320fca08620", size = 595176, upload-time = "2025-10-14T15:05:21.134Z" }, + { url = "https://files.pythonhosted.org/packages/8f/b5/853b6757f7347de4e9b37e8cc3289283fb983cba1ab4d2d7144694871d9c/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:afaeff7696e0ad9f02cbb8f56365ff4686ab205fcf9c4c5b6fdfaaa16549dd04", size = 473577, upload-time = "2025-10-14T15:05:22.306Z" }, + { url = "https://files.pythonhosted.org/packages/e1/f7/0a4467be0a56e80447c8529c9fce5b38eab4f513cb3d9bf82e7392a5696b/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f7eb7da0eb23aa2ba036d4f616d46906013a68caf61b7fdbe42fc8b25132e77", size = 455425, upload-time = "2025-10-14T15:05:23.348Z" }, + { url = "https://files.pythonhosted.org/packages/8e/e0/82583485ea00137ddf69bc84a2db88bd92ab4a6e3c405e5fb878ead8d0e7/watchfiles-1.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:831a62658609f0e5c64178211c942ace999517f5770fe9436be4c2faeba0c0ef", size = 628826, upload-time = "2025-10-14T15:05:24.398Z" }, + { url = "https://files.pythonhosted.org/packages/28/9a/a785356fccf9fae84c0cc90570f11702ae9571036fb25932f1242c82191c/watchfiles-1.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:f9a2ae5c91cecc9edd47e041a930490c31c3afb1f5e6d71de3dc671bfaca02bf", size = 622208, upload-time = "2025-10-14T15:05:25.45Z" }, + { url = "https://files.pythonhosted.org/packages/c3/f4/0872229324ef69b2c3edec35e84bd57a1289e7d3fe74588048ed8947a323/watchfiles-1.1.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:d1715143123baeeaeadec0528bb7441103979a1d5f6fd0e1f915383fea7ea6d5", size = 404315, upload-time = "2025-10-14T15:05:26.501Z" }, + { url = "https://files.pythonhosted.org/packages/7b/22/16d5331eaed1cb107b873f6ae1b69e9ced582fcf0c59a50cd84f403b1c32/watchfiles-1.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:39574d6370c4579d7f5d0ad940ce5b20db0e4117444e39b6d8f99db5676c52fd", size = 390869, upload-time = "2025-10-14T15:05:27.649Z" }, + { url = "https://files.pythonhosted.org/packages/b2/7e/5643bfff5acb6539b18483128fdc0ef2cccc94a5b8fbda130c823e8ed636/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7365b92c2e69ee952902e8f70f3ba6360d0d596d9299d55d7d386df84b6941fb", size = 449919, upload-time = "2025-10-14T15:05:28.701Z" }, + { url = "https://files.pythonhosted.org/packages/51/2e/c410993ba5025a9f9357c376f48976ef0e1b1aefb73b97a5ae01a5972755/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bfff9740c69c0e4ed32416f013f3c45e2ae42ccedd1167ef2d805c000b6c71a5", size = 460845, upload-time = "2025-10-14T15:05:30.064Z" }, + { url = "https://files.pythonhosted.org/packages/8e/a4/2df3b404469122e8680f0fcd06079317e48db58a2da2950fb45020947734/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b27cf2eb1dda37b2089e3907d8ea92922b673c0c427886d4edc6b94d8dfe5db3", size = 489027, upload-time = "2025-10-14T15:05:31.064Z" }, + { url = "https://files.pythonhosted.org/packages/ea/84/4587ba5b1f267167ee715b7f66e6382cca6938e0a4b870adad93e44747e6/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:526e86aced14a65a5b0ec50827c745597c782ff46b571dbfe46192ab9e0b3c33", size = 595615, upload-time = "2025-10-14T15:05:32.074Z" }, + { url = "https://files.pythonhosted.org/packages/6a/0f/c6988c91d06e93cd0bb3d4a808bcf32375ca1904609835c3031799e3ecae/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04e78dd0b6352db95507fd8cb46f39d185cf8c74e4cf1e4fbad1d3df96faf510", size = 474836, upload-time = "2025-10-14T15:05:33.209Z" }, + { url = "https://files.pythonhosted.org/packages/b4/36/ded8aebea91919485b7bbabbd14f5f359326cb5ec218cd67074d1e426d74/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c85794a4cfa094714fb9c08d4a218375b2b95b8ed1666e8677c349906246c05", size = 455099, upload-time = "2025-10-14T15:05:34.189Z" }, + { url = "https://files.pythonhosted.org/packages/98/e0/8c9bdba88af756a2fce230dd365fab2baf927ba42cd47521ee7498fd5211/watchfiles-1.1.1-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:74d5012b7630714b66be7b7b7a78855ef7ad58e8650c73afc4c076a1f480a8d6", size = 630626, upload-time = "2025-10-14T15:05:35.216Z" }, + { url = "https://files.pythonhosted.org/packages/2a/84/a95db05354bf2d19e438520d92a8ca475e578c647f78f53197f5a2f17aaf/watchfiles-1.1.1-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:8fbe85cb3201c7d380d3d0b90e63d520f15d6afe217165d7f98c9c649654db81", size = 622519, upload-time = "2025-10-14T15:05:36.259Z" }, + { url = "https://files.pythonhosted.org/packages/1d/ce/d8acdc8de545de995c339be67711e474c77d643555a9bb74a9334252bd55/watchfiles-1.1.1-cp314-cp314-win32.whl", hash = "sha256:3fa0b59c92278b5a7800d3ee7733da9d096d4aabcfabb9a928918bd276ef9b9b", size = 272078, upload-time = "2025-10-14T15:05:37.63Z" }, + { url = "https://files.pythonhosted.org/packages/c4/c9/a74487f72d0451524be827e8edec251da0cc1fcf111646a511ae752e1a3d/watchfiles-1.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:c2047d0b6cea13b3316bdbafbfa0c4228ae593d995030fda39089d36e64fc03a", size = 287664, upload-time = "2025-10-14T15:05:38.95Z" }, + { url = "https://files.pythonhosted.org/packages/df/b8/8ac000702cdd496cdce998c6f4ee0ca1f15977bba51bdf07d872ebdfc34c/watchfiles-1.1.1-cp314-cp314-win_arm64.whl", hash = "sha256:842178b126593addc05acf6fce960d28bc5fae7afbaa2c6c1b3a7b9460e5be02", size = 277154, upload-time = "2025-10-14T15:05:39.954Z" }, + { url = "https://files.pythonhosted.org/packages/47/a8/e3af2184707c29f0f14b1963c0aace6529f9d1b8582d5b99f31bbf42f59e/watchfiles-1.1.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:88863fbbc1a7312972f1c511f202eb30866370ebb8493aef2812b9ff28156a21", size = 403820, upload-time = "2025-10-14T15:05:40.932Z" }, + { url = "https://files.pythonhosted.org/packages/c0/ec/e47e307c2f4bd75f9f9e8afbe3876679b18e1bcec449beca132a1c5ffb2d/watchfiles-1.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:55c7475190662e202c08c6c0f4d9e345a29367438cf8e8037f3155e10a88d5a5", size = 390510, upload-time = "2025-10-14T15:05:41.945Z" }, + { url = "https://files.pythonhosted.org/packages/d5/a0/ad235642118090f66e7b2f18fd5c42082418404a79205cdfca50b6309c13/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f53fa183d53a1d7a8852277c92b967ae99c2d4dcee2bfacff8868e6e30b15f7", size = 448408, upload-time = "2025-10-14T15:05:43.385Z" }, + { url = "https://files.pythonhosted.org/packages/df/85/97fa10fd5ff3332ae17e7e40e20784e419e28521549780869f1413742e9d/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6aae418a8b323732fa89721d86f39ec8f092fc2af67f4217a2b07fd3e93c6101", size = 458968, upload-time = "2025-10-14T15:05:44.404Z" }, + { url = "https://files.pythonhosted.org/packages/47/c2/9059c2e8966ea5ce678166617a7f75ecba6164375f3b288e50a40dc6d489/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f096076119da54a6080e8920cbdaac3dbee667eb91dcc5e5b78840b87415bd44", size = 488096, upload-time = "2025-10-14T15:05:45.398Z" }, + { url = "https://files.pythonhosted.org/packages/94/44/d90a9ec8ac309bc26db808a13e7bfc0e4e78b6fc051078a554e132e80160/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00485f441d183717038ed2e887a7c868154f216877653121068107b227a2f64c", size = 596040, upload-time = "2025-10-14T15:05:46.502Z" }, + { url = "https://files.pythonhosted.org/packages/95/68/4e3479b20ca305cfc561db3ed207a8a1c745ee32bf24f2026a129d0ddb6e/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a55f3e9e493158d7bfdb60a1165035f1cf7d320914e7b7ea83fe22c6023b58fc", size = 473847, upload-time = "2025-10-14T15:05:47.484Z" }, + { url = "https://files.pythonhosted.org/packages/4f/55/2af26693fd15165c4ff7857e38330e1b61ab8c37d15dc79118cdba115b7a/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c91ed27800188c2ae96d16e3149f199d62f86c7af5f5f4d2c61a3ed8cd3666c", size = 455072, upload-time = "2025-10-14T15:05:48.928Z" }, + { url = "https://files.pythonhosted.org/packages/66/1d/d0d200b10c9311ec25d2273f8aad8c3ef7cc7ea11808022501811208a750/watchfiles-1.1.1-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:311ff15a0bae3714ffb603e6ba6dbfba4065ab60865d15a6ec544133bdb21099", size = 629104, upload-time = "2025-10-14T15:05:49.908Z" }, + { url = "https://files.pythonhosted.org/packages/e3/bd/fa9bb053192491b3867ba07d2343d9f2252e00811567d30ae8d0f78136fe/watchfiles-1.1.1-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:a916a2932da8f8ab582f242c065f5c81bed3462849ca79ee357dd9551b0e9b01", size = 622112, upload-time = "2025-10-14T15:05:50.941Z" }, + { url = "https://files.pythonhosted.org/packages/ba/4c/a888c91e2e326872fa4705095d64acd8aa2fb9c1f7b9bd0588f33850516c/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:17ef139237dfced9da49fb7f2232c86ca9421f666d78c264c7ffca6601d154c3", size = 409611, upload-time = "2025-10-14T15:06:05.809Z" }, + { url = "https://files.pythonhosted.org/packages/1e/c7/5420d1943c8e3ce1a21c0a9330bcf7edafb6aa65d26b21dbb3267c9e8112/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:672b8adf25b1a0d35c96b5888b7b18699d27d4194bac8beeae75be4b7a3fc9b2", size = 396889, upload-time = "2025-10-14T15:06:07.035Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e5/0072cef3804ce8d3aaddbfe7788aadff6b3d3f98a286fdbee9fd74ca59a7/watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77a13aea58bc2b90173bc69f2a90de8e282648939a00a602e1dc4ee23e26b66d", size = 451616, upload-time = "2025-10-14T15:06:08.072Z" }, + { url = "https://files.pythonhosted.org/packages/83/4e/b87b71cbdfad81ad7e83358b3e447fedd281b880a03d64a760fe0a11fc2e/watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b495de0bb386df6a12b18335a0285dda90260f51bdb505503c02bcd1ce27a8b", size = 458413, upload-time = "2025-10-14T15:06:09.209Z" }, + { url = "https://files.pythonhosted.org/packages/d3/8e/e500f8b0b77be4ff753ac94dc06b33d8f0d839377fee1b78e8c8d8f031bf/watchfiles-1.1.1-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:db476ab59b6765134de1d4fe96a1a9c96ddf091683599be0f26147ea1b2e4b88", size = 408250, upload-time = "2025-10-14T15:06:10.264Z" }, + { url = "https://files.pythonhosted.org/packages/bd/95/615e72cd27b85b61eec764a5ca51bd94d40b5adea5ff47567d9ebc4d275a/watchfiles-1.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:89eef07eee5e9d1fda06e38822ad167a044153457e6fd997f8a858ab7564a336", size = 396117, upload-time = "2025-10-14T15:06:11.28Z" }, + { url = "https://files.pythonhosted.org/packages/c9/81/e7fe958ce8a7fb5c73cc9fb07f5aeaf755e6aa72498c57d760af760c91f8/watchfiles-1.1.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce19e06cbda693e9e7686358af9cd6f5d61312ab8b00488bc36f5aabbaf77e24", size = 450493, upload-time = "2025-10-14T15:06:12.321Z" }, + { url = "https://files.pythonhosted.org/packages/6e/d4/ed38dd3b1767193de971e694aa544356e63353c33a85d948166b5ff58b9e/watchfiles-1.1.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e6f39af2eab0118338902798b5aa6664f46ff66bc0280de76fca67a7f262a49", size = 457546, upload-time = "2025-10-14T15:06:13.372Z" }, +] + +[[package]] +name = "wcwidth" +version = "0.2.14" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/30/6b0809f4510673dc723187aeaf24c7f5459922d01e2f794277a3dfb90345/wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605", size = 102293, upload-time = "2025-09-22T16:29:53.023Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/af/b5/123f13c975e9f27ab9c0770f514345bd406d0e8d3b7a0723af9d43f710af/wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1", size = 37286, upload-time = "2025-09-22T16:29:51.641Z" }, +] + +[[package]] +name = "websockets" +version = "15.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/da/6462a9f510c0c49837bbc9345aca92d767a56c1fb2939e1579df1e1cdcf7/websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", size = 175423, upload-time = "2025-03-05T20:01:35.363Z" }, + { url = "https://files.pythonhosted.org/packages/1c/9f/9d11c1a4eb046a9e106483b9ff69bce7ac880443f00e5ce64261b47b07e7/websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205", size = 173080, upload-time = "2025-03-05T20:01:37.304Z" }, + { url = "https://files.pythonhosted.org/packages/d5/4f/b462242432d93ea45f297b6179c7333dd0402b855a912a04e7fc61c0d71f/websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a", size = 173329, upload-time = "2025-03-05T20:01:39.668Z" }, + { url = "https://files.pythonhosted.org/packages/6e/0c/6afa1f4644d7ed50284ac59cc70ef8abd44ccf7d45850d989ea7310538d0/websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e", size = 182312, upload-time = "2025-03-05T20:01:41.815Z" }, + { url = "https://files.pythonhosted.org/packages/dd/d4/ffc8bd1350b229ca7a4db2a3e1c482cf87cea1baccd0ef3e72bc720caeec/websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf", size = 181319, upload-time = "2025-03-05T20:01:43.967Z" }, + { url = "https://files.pythonhosted.org/packages/97/3a/5323a6bb94917af13bbb34009fac01e55c51dfde354f63692bf2533ffbc2/websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb", size = 181631, upload-time = "2025-03-05T20:01:46.104Z" }, + { url = "https://files.pythonhosted.org/packages/a6/cc/1aeb0f7cee59ef065724041bb7ed667b6ab1eeffe5141696cccec2687b66/websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d", size = 182016, upload-time = "2025-03-05T20:01:47.603Z" }, + { url = "https://files.pythonhosted.org/packages/79/f9/c86f8f7af208e4161a7f7e02774e9d0a81c632ae76db2ff22549e1718a51/websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9", size = 181426, upload-time = "2025-03-05T20:01:48.949Z" }, + { url = "https://files.pythonhosted.org/packages/c7/b9/828b0bc6753db905b91df6ae477c0b14a141090df64fb17f8a9d7e3516cf/websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c", size = 181360, upload-time = "2025-03-05T20:01:50.938Z" }, + { url = "https://files.pythonhosted.org/packages/89/fb/250f5533ec468ba6327055b7d98b9df056fb1ce623b8b6aaafb30b55d02e/websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256", size = 176388, upload-time = "2025-03-05T20:01:52.213Z" }, + { url = "https://files.pythonhosted.org/packages/1c/46/aca7082012768bb98e5608f01658ff3ac8437e563eca41cf068bd5849a5e/websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41", size = 176830, upload-time = "2025-03-05T20:01:53.922Z" }, + { url = "https://files.pythonhosted.org/packages/9f/32/18fcd5919c293a398db67443acd33fde142f283853076049824fc58e6f75/websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431", size = 175423, upload-time = "2025-03-05T20:01:56.276Z" }, + { url = "https://files.pythonhosted.org/packages/76/70/ba1ad96b07869275ef42e2ce21f07a5b0148936688c2baf7e4a1f60d5058/websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57", size = 173082, upload-time = "2025-03-05T20:01:57.563Z" }, + { url = "https://files.pythonhosted.org/packages/86/f2/10b55821dd40eb696ce4704a87d57774696f9451108cff0d2824c97e0f97/websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905", size = 173330, upload-time = "2025-03-05T20:01:59.063Z" }, + { url = "https://files.pythonhosted.org/packages/a5/90/1c37ae8b8a113d3daf1065222b6af61cc44102da95388ac0018fcb7d93d9/websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562", size = 182878, upload-time = "2025-03-05T20:02:00.305Z" }, + { url = "https://files.pythonhosted.org/packages/8e/8d/96e8e288b2a41dffafb78e8904ea7367ee4f891dafc2ab8d87e2124cb3d3/websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792", size = 181883, upload-time = "2025-03-05T20:02:03.148Z" }, + { url = "https://files.pythonhosted.org/packages/93/1f/5d6dbf551766308f6f50f8baf8e9860be6182911e8106da7a7f73785f4c4/websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413", size = 182252, upload-time = "2025-03-05T20:02:05.29Z" }, + { url = "https://files.pythonhosted.org/packages/d4/78/2d4fed9123e6620cbf1706c0de8a1632e1a28e7774d94346d7de1bba2ca3/websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8", size = 182521, upload-time = "2025-03-05T20:02:07.458Z" }, + { url = "https://files.pythonhosted.org/packages/e7/3b/66d4c1b444dd1a9823c4a81f50231b921bab54eee2f69e70319b4e21f1ca/websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3", size = 181958, upload-time = "2025-03-05T20:02:09.842Z" }, + { url = "https://files.pythonhosted.org/packages/08/ff/e9eed2ee5fed6f76fdd6032ca5cd38c57ca9661430bb3d5fb2872dc8703c/websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf", size = 181918, upload-time = "2025-03-05T20:02:11.968Z" }, + { url = "https://files.pythonhosted.org/packages/d8/75/994634a49b7e12532be6a42103597b71098fd25900f7437d6055ed39930a/websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85", size = 176388, upload-time = "2025-03-05T20:02:13.32Z" }, + { url = "https://files.pythonhosted.org/packages/98/93/e36c73f78400a65f5e236cd376713c34182e6663f6889cd45a4a04d8f203/websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065", size = 176828, upload-time = "2025-03-05T20:02:14.585Z" }, + { url = "https://files.pythonhosted.org/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437, upload-time = "2025-03-05T20:02:16.706Z" }, + { url = "https://files.pythonhosted.org/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096, upload-time = "2025-03-05T20:02:18.832Z" }, + { url = "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332, upload-time = "2025-03-05T20:02:20.187Z" }, + { url = "https://files.pythonhosted.org/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152, upload-time = "2025-03-05T20:02:22.286Z" }, + { url = "https://files.pythonhosted.org/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096, upload-time = "2025-03-05T20:02:24.368Z" }, + { url = "https://files.pythonhosted.org/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523, upload-time = "2025-03-05T20:02:25.669Z" }, + { url = "https://files.pythonhosted.org/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790, upload-time = "2025-03-05T20:02:26.99Z" }, + { url = "https://files.pythonhosted.org/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165, upload-time = "2025-03-05T20:02:30.291Z" }, + { url = "https://files.pythonhosted.org/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160, upload-time = "2025-03-05T20:02:31.634Z" }, + { url = "https://files.pythonhosted.org/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395, upload-time = "2025-03-05T20:02:33.017Z" }, + { url = "https://files.pythonhosted.org/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841, upload-time = "2025-03-05T20:02:34.498Z" }, + { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload-time = "2025-03-05T20:02:36.695Z" }, + { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload-time = "2025-03-05T20:02:37.985Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload-time = "2025-03-05T20:02:39.298Z" }, + { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload-time = "2025-03-05T20:02:40.595Z" }, + { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload-time = "2025-03-05T20:02:41.926Z" }, + { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload-time = "2025-03-05T20:02:43.304Z" }, + { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload-time = "2025-03-05T20:02:48.812Z" }, + { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload-time = "2025-03-05T20:02:50.14Z" }, + { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" }, + { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" }, + { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/d40f779fa16f74d3468357197af8d6ad07e7c5a27ea1ca74ceb38986f77a/websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3", size = 173109, upload-time = "2025-03-05T20:03:17.769Z" }, + { url = "https://files.pythonhosted.org/packages/bc/cd/5b887b8585a593073fd92f7c23ecd3985cd2c3175025a91b0d69b0551372/websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1", size = 173343, upload-time = "2025-03-05T20:03:19.094Z" }, + { url = "https://files.pythonhosted.org/packages/fe/ae/d34f7556890341e900a95acf4886833646306269f899d58ad62f588bf410/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475", size = 174599, upload-time = "2025-03-05T20:03:21.1Z" }, + { url = "https://files.pythonhosted.org/packages/71/e6/5fd43993a87db364ec60fc1d608273a1a465c0caba69176dd160e197ce42/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9", size = 174207, upload-time = "2025-03-05T20:03:23.221Z" }, + { url = "https://files.pythonhosted.org/packages/2b/fb/c492d6daa5ec067c2988ac80c61359ace5c4c674c532985ac5a123436cec/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04", size = 174155, upload-time = "2025-03-05T20:03:25.321Z" }, + { url = "https://files.pythonhosted.org/packages/68/a1/dcb68430b1d00b698ae7a7e0194433bce4f07ded185f0ee5fb21e2a2e91e/websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122", size = 176884, upload-time = "2025-03-05T20:03:27.934Z" }, + { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, +] diff --git a/{{cookiecutter.repo_name}}/.github/workflows/test.yml b/{{cookiecutter.repo_name}}/.github/workflows/test.yml deleted file mode 100644 index cf0c501..0000000 --- a/{{cookiecutter.repo_name}}/.github/workflows/test.yml +++ /dev/null @@ -1,61 +0,0 @@ -# This workflow will install Python dependencies, run tests and lint with a single version of Python -# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions - -name: Test - -on: push - -jobs: - test: - - runs-on: ubuntu-latest - - strategy: - fail-fast: false - matrix: - python-version: [3.7, 3.8, 3.9] - - steps: - - - uses: actions/checkout@v2 - - - name: Cache Setup - uses: actions/cache@v2 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} - restore-keys: | - ${{ runner.os }}-pip- - - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install . - - - name: Lint with flake8 - run: | - pip install flake8 - # stop the build if there are Python syntax errors or undefined names - flake8 . --count --show-source --statistics - - - name: Lint with isort - run: | - pip install isort - isort -c . - - - name: Test with pytest - run: | - pip install pytest pytest-cov pytest-asyncio pytest-mock asynctest pytest-sugar - pip install coverage[toml] - pytest - - # - name: Upload coverage to Codecov - # if: matrix.python-version == '3.8' - # uses: codecov/codecov-action@v1 - # with: - # file: ./coverage.xml diff --git a/{{cookiecutter.repo_name}}/.gitignore b/{{cookiecutter.repo_name}}/.gitignore deleted file mode 100644 index ab804af..0000000 --- a/{{cookiecutter.repo_name}}/.gitignore +++ /dev/null @@ -1,115 +0,0 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -*.DS_Store - -# C extensions -*.so -*.o -*.a - -# Distribution / packaging -.Python -env/ -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -*.egg-info/ -.installed.cfg -*.egg - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.coverage* -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -.hypothesis/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ -docs/sphinx/_build/ - -# PyBuilder -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# pyenv -.python-version - -# celery beat schedule file -celerybeat-schedule - -# SageMath parsed files -*.sage.py - -# dotenv -.env - -# virtualenv -.venv -venv/ -ENV/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ - -.vscode - -.pytest_cache - -# Vim temporary files -*~ -*.swp -*.swo diff --git a/{{cookiecutter.repo_name}}/.pylintrc b/{{cookiecutter.repo_name}}/.pylintrc deleted file mode 100644 index 1a2c0f7..0000000 --- a/{{cookiecutter.repo_name}}/.pylintrc +++ /dev/null @@ -1,425 +0,0 @@ -[MASTER] - -# 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-whitelist= - -# Add files or directories to the blacklist. They should be base names, not -# paths. -ignore=CVS - -# Add files or directories matching the regex patterns to the blacklist. The -# regex matches against base names, not paths. -ignore-patterns= - -# Python code to execute, usually for sys.path manipulation such as -# pygtk.require(). -#init-hook= - -# Use multiple processes to speed up Pylint. -jobs=1 - -# List of plugins (as comma separated values of python modules names) to load, -# usually to register additional checkers. -load-plugins= - -# Pickle collected data for later comparisons. -persistent=yes - -# Specify a configuration file. -#rcfile= - -# Allow loading of arbitrary C extensions. Extensions are imported into the -# active Python interpreter and may run arbitrary code. -unsafe-load-any-extension=no - - -[MESSAGES CONTROL] - -# Only show warnings with the listed confidence levels. Leave empty to show -# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED -confidence= - -# 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 reenable 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=C,R,W0703,W0221,W0511,W0212,W0621,import-star-module-level,old-octal-literal,oct-method,print-statement,unpacking-in-except,parameter-unpacking,backtick,old-raise-syntax,old-ne-operator,long-suffix,dict-view-method,dict-iter-method,metaclass-assignment,next-method-called,raising-string,indexing-exception,raw_input-builtin,long-builtin,file-builtin,execfile-builtin,coerce-builtin,cmp-builtin,buffer-builtin,basestring-builtin,apply-builtin,filter-builtin-not-iterating,using-cmp-argument,useless-suppression,range-builtin-not-iterating,suppressed-message,cmp-method,reload-builtin,zip-builtin-not-iterating,intern-builtin,unichr-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,input-builtin,round-builtin,hex-method,nonzero-method,map-builtin-not-iterating - -# 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= - - -[REPORTS] - -# Python expression which should return a note less than 10 (10 is the highest -# note). You have access to the variables errors warning, statement which -# respectively contain the number of errors / warnings messages and the total -# number of statements analyzed. This is used by the global evaluation report -# (RP0004). -evaluation=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, eg -# mypackage.mymodule.MyReporterClass. -output-format=text - -# Tells whether to display a full report or only the messages -reports=no - -# Activate the evaluation score. -score=yes - - -[REFACTORING] - -# Maximum number of nested blocks for function / method body -max-nested-blocks=5 - - -[LOGGING] - -# Logging modules to check that the string format arguments are in logging -# function parameter format -logging-modules=logging - - -[SPELLING] - -# Spelling dictionary name. Available dictionaries: none. To make it working -# install python-enchant package. -spelling-dict= - -# List of comma separated words that should not be checked. -spelling-ignore-words= - -# A path to a file that contains private dictionary; one word per line. -spelling-private-dict-file= - -# Tells whether to store unknown words to indicated private dictionary in -# --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 - - -[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 missing members accessed in mixin class should be ignored. A -# mixin class is detected if its name ends with "mixin" (case insensitive). -ignore-mixin-members=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 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 - -# 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= - -# 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 - - -[VARIABLES] - -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid to define new builtins when possible. -additional-builtins= - -# Tells whether unused global variables should be treated as a violation. -allow-global-unused-variables=yes - -# 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. expectedly -# not 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,future.builtins - - -[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=99 - -# Maximum number of lines in a module -max-module-lines=1000 - -# List of optional constructs for which whitespace checking is disabled. `dict- -# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. -# `trailing-comma` allows a space between comma and closing bracket: (a, ). -# `empty-line` allows space-only lines. -no-space-check=trailing-comma,dict-separator - -# 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 - - -[SIMILARITIES] - -# Ignore comments when computing similarities. -ignore-comments=yes - -# Ignore docstrings when computing similarities. -ignore-docstrings=yes - -# Ignore imports when computing similarities. -ignore-imports=no - -# Minimum lines number of a similarity. -min-similarity-lines=4 - - -[BASIC] - -# Naming hint for argument names -argument-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Regular expression matching correct argument names -argument-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Naming hint for attribute names -attr-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Regular expression matching correct attribute names -attr-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Bad variable names which should always be refused, separated by a comma -bad-names=foo,bar,baz,toto,tutu,tata - -# Naming hint for class attribute names -class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ - -# Regular expression matching correct class attribute names -class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ - -# Naming hint for class names -class-name-hint=[A-Z_][a-zA-Z0-9]+$ - -# Regular expression matching correct class names -class-rgx=[A-Z_][a-zA-Z0-9]+$ - -# Naming hint for constant names -const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ - -# Regular expression matching correct constant names -const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ - -# Minimum line length for functions/classes that require docstrings, shorter -# ones are exempt. -docstring-min-length=-1 - -# Naming hint for function names -function-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Regular expression matching correct function names -function-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Good variable names which should always be accepted, separated by a comma -good-names=i,j,k,ex,Run,_ - -# Include a hint for the correct naming format with invalid-name -include-naming-hint=no - -# Naming hint for inline iteration names -inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ - -# Regular expression matching correct inline iteration names -inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ - -# Naming hint for method names -method-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Regular expression matching correct method names -method-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Naming hint for module names -module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ - -# Regular expression matching correct module names -module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ - -# 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. -property-classes=abc.abstractproperty - -# Naming hint for variable names -variable-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Regular expression matching correct variable names -variable-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - - -[IMPORTS] - -# Allow wildcard imports from modules that define __all__. -allow-wildcard-with-all=no - -# 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 - -# Deprecated modules which should not be used, separated by a comma -deprecated-modules=optparse,tkinter.tix - -# Create a graph of external dependencies in the given file (report RP0402 must -# not be disabled) -ext-import-graph= - -# Create a graph of every (i.e. internal and external) dependencies in the -# given file (report RP0402 must not be disabled) -import-graph= - -# Create a graph of internal dependencies in 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 - - -[CLASSES] - -# List of method names used to declare (i.e. assign) instance attributes. -defining-attr-methods=__init__,__new__,setUp - -# 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=mcs - - -[DESIGN] - -# 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 a if statement -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 - - -[EXCEPTIONS] - -# Exceptions that will emit a warning when being caught. Defaults to -# "Exception" -overgeneral-exceptions=Exception diff --git a/{{cookiecutter.repo_name}}/.travis.yml b/{{cookiecutter.repo_name}}/.travis.yml deleted file mode 100644 index 29b2f81..0000000 --- a/{{cookiecutter.repo_name}}/.travis.yml +++ /dev/null @@ -1,38 +0,0 @@ -language: python - -cache: - pip: true - timeout: 1000 - -sudo: false - -python: -- '3.7' -- '3.8' - -os: -- linux - -matrix: - fast_finish: true - -notifications: - email: false - -# repo branches to test -branches: -- main - -install: -- pip install -U pip wheel --quiet -- pip install --upgrade setuptools --quiet -- pip install pytest -- pip install pytest-coverage -- pip install codecov -- pip install .[dev] - -script: -- pytest tests --cov {{cookiecutter.package_name}} --cov-report html - -after_success: -- codecov diff --git a/{{cookiecutter.repo_name}}/CHANGELOG.rst b/{{cookiecutter.repo_name}}/CHANGELOG.rst deleted file mode 100644 index a021852..0000000 --- a/{{cookiecutter.repo_name}}/CHANGELOG.rst +++ /dev/null @@ -1,27 +0,0 @@ -.. _{{cookiecutter.package_name}}-changelog: - -========== -Change Log -========== -{% if cookiecutter.use_releases %} -* First change goes here. -{% else %} -This document records the main changes to the {{cookiecutter.package_name}} code. - -.. {{cookiecutter.package_name}}-0.1.0: - -0.1.0 (unreleased) ------------------- - -Added -^^^^^ -* A thing we added. - -Changed -^^^^^^^ -* TBD - -Fixed -^^^^^ -* TBD -{% endif %} diff --git a/{{cookiecutter.repo_name}}/CODEOWNERS b/{{cookiecutter.repo_name}}/CODEOWNERS deleted file mode 100644 index 73ff14c..0000000 --- a/{{cookiecutter.repo_name}}/CODEOWNERS +++ /dev/null @@ -1,38 +0,0 @@ -# This is a comment. -# Each line is a file pattern followed by one or more owners. - -# These owners will be the default owners for everything in -# the repo. Unless a later match takes precedence, -# @global-owner1 and @global-owner2 will be requested for -# review when someone opens a pull request. -* @{{cookiecutter.github_organisation}} -* {{cookiecutter.email}} - -# Order is important; the last matching pattern takes the most -# precedence. When someone opens a pull request that only -# modifies JS files, only @js-owner and not the global -# owner(s) will be requested for a review. -*.js @js-owner - -# You can also use email addresses if you prefer. They'll be -# used to look up users just like we do for commit author -# emails. -*.go docs@example.com - -# In this example, @doctocat owns any files in the build/logs -# directory at the root of the repository and any of its -# subdirectories. -/build/logs/ @doctocat - -# The `docs/*` pattern will match files like -# `docs/getting-started.md` but not further nested files like -# `docs/build-app/troubleshooting.md`. -docs/* docs@example.com - -# In this example, @octocat owns any file in an apps directory -# anywhere in your repository. -apps/ @octocat - -# In this example, @doctocat owns any file in the `/docs` -# directory in the root of your repository. -/docs/ @doctocat diff --git a/{{cookiecutter.repo_name}}/LICENSE.md b/{{cookiecutter.repo_name}}/LICENSE.md deleted file mode 100644 index b583b6f..0000000 --- a/{{cookiecutter.repo_name}}/LICENSE.md +++ /dev/null @@ -1,29 +0,0 @@ -BSD 3-Clause License - -Copyright (c) 2017, SDSS -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/{{cookiecutter.repo_name}}/README.md b/{{cookiecutter.repo_name}}/README.md deleted file mode 100644 index 6b6de82..0000000 --- a/{{cookiecutter.repo_name}}/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# {{cookiecutter.package_name}} - -![Versions](https://img.shields.io/badge/python->3.7-blue) -[![Documentation Status](https://readthedocs.org/projects/{{cookiecutter.pip_name}}/badge/?version=latest)](https://{{cookiecutter.pip_name}}.readthedocs.io/en/latest/?badge=latest) -[![Travis (.org)](https://img.shields.io/travis/{{cookiecutter.github_organisation}}/{{cookiecutter.repo_name}})](https://travis-ci.org/{{cookiecutter.github_organisation}}/{{cookiecutter.repo_name}}) -[![codecov](https://codecov.io/gh/{{cookiecutter.github_organisation}}/{{cookiecutter.repo_name}}/branch/main/graph/badge.svg)](https://codecov.io/gh/{{cookiecutter.github_organisation}}/{{cookiecutter.repo_name}}) - -{{cookiecutter.short_description}} diff --git a/{{cookiecutter.repo_name}}/bin/{{cookiecutter.package_name}} b/{{cookiecutter.repo_name}}/bin/{{cookiecutter.package_name}} deleted file mode 100755 index 2b0b371..0000000 --- a/{{cookiecutter.repo_name}}/bin/{{cookiecutter.package_name}} +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -# -# @Author: JosΓ© SΓ‘nchez-Gallego -# @Date: Dec 1, 2017 -# @Filename: {{cookiecutter.package_name}} -# @License: BSD 3-Clause -# @Copyright: JosΓ© SΓ‘nchez-Gallego - -import argparse -import os -import sys - -from {{cookiecutter.package_name}}.main import math - - -if __name__ == '__main__': - - # An example of how to write a command line parser that works with the - # main.math function. For more details on how to use argparse, start with - # this tutorial: http://bit.ly/2SGDf7h - - parser = argparse.ArgumentParser( - prog=os.path.basename(sys.argv[0]), - description='Performs an arithmetic operation.') - - parser.add_argument('VALUE1', type=float, help='The first operand') - parser.add_argument('OPERATOR', type=str, help='The operator [+, -, *, /]') - parser.add_argument('VALUE2', type=float, help='The second operand') - - parser.add_argument('-v', '--verbose', action='store_true', default=False, - help='sets verbose mode') - - args = parser.parse_args() - - result = math(args.VALUE1, args.VALUE2, arith_operator=args.OPERATOR) - - if args.verbose: - print('{} {} {} = {}'.format(args.VALUE1, args.OPERATOR, args.VALUE2, result)) - else: - print(result) diff --git a/{{cookiecutter.repo_name}}/cextern/README.txt b/{{cookiecutter.repo_name}}/cextern/README.txt deleted file mode 100644 index 71a8590..0000000 --- a/{{cookiecutter.repo_name}}/cextern/README.txt +++ /dev/null @@ -1 +0,0 @@ -C code to be compiled on setup goes here. diff --git a/{{cookiecutter.repo_name}}/docs/sphinx/CHANGELOG.rst b/{{cookiecutter.repo_name}}/docs/sphinx/CHANGELOG.rst deleted file mode 100644 index fee2d8a..0000000 --- a/{{cookiecutter.repo_name}}/docs/sphinx/CHANGELOG.rst +++ /dev/null @@ -1,2 +0,0 @@ - -.. include:: ../../CHANGELOG.rst diff --git a/{{cookiecutter.repo_name}}/docs/sphinx/Makefile b/{{cookiecutter.repo_name}}/docs/sphinx/Makefile deleted file mode 100644 index 5145a85..0000000 --- a/{{cookiecutter.repo_name}}/docs/sphinx/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = python -msphinx -SPHINXPROJ = BMO -SOURCEDIR = . -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/{{cookiecutter.repo_name}}/docs/sphinx/_static/custom.css b/{{cookiecutter.repo_name}}/docs/sphinx/_static/custom.css deleted file mode 100644 index 9ea0f78..0000000 --- a/{{cookiecutter.repo_name}}/docs/sphinx/_static/custom.css +++ /dev/null @@ -1,43 +0,0 @@ -/* This is the custom CSS for alabaster. The theme does not allow for it to be set differently. */ - -.red { - color: red; -} - -.green { - color: green; -} - -.pink { - color: pink; -} - -.orange { - color: orange; -} - -.purple { - color: purple; -} - -a.reference > em { - font-style: normal !important; -} - -a.reference > code { - font-weight: inherit !important; - color: inherit; - background-color: inherit; -} - -ul, ol { - margin: 0px 0 0px 30px; -} - -a.reference { - border-bottom: 0px; -} - -td.field-body > ul > li > em { - font-style: normal !important; -} diff --git a/{{cookiecutter.repo_name}}/docs/sphinx/_static/custom_bootstrap.css b/{{cookiecutter.repo_name}}/docs/sphinx/_static/custom_bootstrap.css deleted file mode 100644 index c400728..0000000 --- a/{{cookiecutter.repo_name}}/docs/sphinx/_static/custom_bootstrap.css +++ /dev/null @@ -1,107 +0,0 @@ -body { color: #444444 !important; font-size: 14px} - -div.custom-warning { - background-color: #f7c589; - border-color: #f7c589; -} - -div.custom-warning { - background-color: #f7c589; - border-color: #f7c589; -} - -.red { - color: red; -} - -.green { - color: green; -} - -.pink { - color: pink; -} - -.orange { - color: orange; -} - -.purple { - color: purple; -} - -dl.attribute, dl.method { - display: block; - margin-left: 50px; -} - -footer a{ - - color: #4c72b0 !important; -} -a.reference { - color: #4c72b0 !important; -} - -blockquote p { - font-size: 14px !important; -} - -blockquote { - padding-top: 4px !important; - padding-bottom: 4px !important; - margin: 0 0 0px !important; -} - -code { - color: #49759c !important; - background-color: #ffffff !important; -} - -.alert-info { - background-color: #adb8cb !important; - border-color: #adb8cb !important; - color: #2c3e50 !important; -} - -code.descname, code.descclassname { - color: #c42850 !important; -} - -code.descclassname + code.descname { - margin-left: -4px; - padding-left: 0px; -} - -span.sig-paren ~ em { - font-weight: 600; - font-family: sans-serif; - font-size: 9.5pt; -} - -em.property { - font-weight: 600; - font-family: sans-serif; - font-size: 9.5pt; -} - -/* .function dt { - padding-top: 150px; - margin-top: -150px; - -webkit-background-clip: content-box; - background-clip: content-box; -} */ - -.rubric > .class-header-no-toc { - font-size: 240%; - font-weight: 400; - /* padding-bottom: 20px; */ - display: inline-block; -} - -h1 { font-size: 240%; } -h2 { font-size: 180%; } -h3 { font-size: 150%; } -h4 { font-size: 120%; } -h5 { font-size: 90%; } -h6 { font-size: 80%; } diff --git a/{{cookiecutter.repo_name}}/docs/sphinx/_static/favicon.ico b/{{cookiecutter.repo_name}}/docs/sphinx/_static/favicon.ico deleted file mode 100644 index 4ea0b435d71f92beaa86f0ffe832f1ef9e4ef46e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1150 zcmcJONlX(_7{?!r;Xptl31?$8tpzDdDbyC)N-0|dvJ~1WrTcVe3s80uP%v)6C{||GYPkkSM&9k_fgZ zi6fSf6ha6W!4O6c;@A;_?~>yWV8{Qt+1}nJ06>O^uf!P*<`X(fpW<}56K5X!qsKZnwe z#7;ZoMIwoY&(D5YAeQb?m9@}rw83SE7Y6Jeps7X>=H$Vd)7%}I^g;up56y+yG^Hiw zoQzCCNGUJ+-e-2ejJFdO=oXkaxFD>v!)DJ2JnpyzGyTILmB=71mH+Yn)HJJ=%N1fl zc5cL}(SzU90b#up0%{ZZYmMN?K5TTuM)xqx>1bFoH$k`E4Ln}@S1u=&6c#G8g*l?F zeyllfYk^>$nbj;~i}8Mk_%L|Hnkp&Amfc4XAm0xRAwR>Sx^B-H4Hm6je>$Hanl7MM1Bz^K-~ zQ52V*l1QXPC=~5ZHTz&4eXh0l!*Wv>tTgw)YHKe%=^bIef1`T{mgrWPG&=WPlwq@2 zRlyPFiOKTv3dt7aejcU05YpOU5!a6K$*j|&r5Tnzov_|H2#-1j;HJ&{jn)~)%BpHo zN>vr)#@&1DzM%(gMREC;ak>ct=r@RY0>}*R)3m|4f5+Rt{8(}rZim>%!WUVXvTkOyM zv$o4j?^Q!1hS-#l2nkx@LqznjhoA@v2`LHbp~kQ8&o-D5^bmB%XXkg$`JUf7_iRKf z@TsjOeD5UJDx!KK+6xdu%EBodhxMUg3r!eX%)({!CBlS!tkYEhD;mOtH*o18RAvK&t&5=8}CP1BetNz>|` zl>7d*-uA&$XFCSl&O1l1_BQ`s|1g(Zi$0H0%kK8~GxW&o!CS4G%@Nmaj(PA3bm?}- zIq(u^8M&ov(6=fO2#oXjhK7fWk|_4*C!F1y-LVMmN3Z}bub;zt2ABW?NB9NUk0+H* zv$U#ymm{}3q05!>Z((`AW2oN^+k{*Z)(AcW4`wxBUvqd*CPibH5PJd`^cmQT;2s!& z&*x}F{RpfGcz+9ipXO*Z%49_ugC8%&RalNtU$f3-+Oq8^&MDx1K5c9X2BcixSsEgxel0L>{wryL9AS|%tFt1TYy#v5$Fo=`K+HXLkRvR z6pR7evcd`nx;4-r2mF7=_hm-RP$Aic^GJpN&qv0HSd{3;YN9XKiQYF5J*y^qzDN|W bBf3!_(k~N*RuawR5#K=cZXasC0o48kpGIy? diff --git a/{{cookiecutter.repo_name}}/docs/sphinx/_static/sdss_logo.png b/{{cookiecutter.repo_name}}/docs/sphinx/_static/sdss_logo.png deleted file mode 100644 index bc770a558a1f5b86b060c8afdb17f8eb2d36ceba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24816 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%0DR(>~4i=fR(8qHOpCPu8>##%X+3x)o_jX1}f^P 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 z zK+|Pp#KTaIr4kiicY7AAC~!YrE{lD%FJA;dzQZY{&ZW5>ZhD`gp(3=CygM{n+FH4~ zxcs?&t_tq7zQ}v8V-I-Q^i#?f?Y6Zt{n(E&Y5bi-^6IuDbrk}Q8E{$Hq8O!o@>4ws zMQ9uLRj2GLhLA}@R9@y%D%87Em&umEoIe<_rjcOEzSq0TF*sD!^)#I#;*hC+_>xj< zpaRBXi|b3XYA77|B!g|x)HJYJg)&76VwMxPHUk;t&@3oNn}JeZm`WG4#W1!rPoa66 z2WL6oG#iJw>FSaK!kk@o>0hrqqY4)l2ejhrpG5AAomaagJJqwBBYq;H&&%e*4Sran zAD1iI47Xh0W`f^+LFxM>fVTOcrucdohSs-t_s6@{^#v!`_h{eDIO7}|JZ>p_3R=TP z+y_He3$3l2^M3T`5MnO*i|0)(`ClTKj!7Srcs)eJ93b;eCCCQc zzpLY;@WRVb{>l|Y`*`1e6Akp9Ip6eo9{)h9rf2&g10Pw+oNBA9t4D@#YiVeBB!=xN z6%9_NwA2+XcW)uX;>2Jv%}&(HDSLy=NL~5FvL=p%Sl|CZ>(|qr?sE6(>YGQ%<)i`t8CF3jxg=$fS}FxzPAOgds^L>7;{K$t2{?ScO3#=b)ysvQ|~{g=f#*UtN7I ztGc44f46H}adm<0f2N+5C5rmU1rA!VxubhA#}1B%WHV#` zyd(8Fv*NQFZST^8ub;rTO~;~g^UbYU>TZ<;M^RNNU%F76wWV=PLU%^(>M35Np-N|B zKuM#rKGOVc!la3$0`n){LV|*7>N>QUf`QN2qWQtd#diAVr`3@9TsG5$YE9CBdm_-> zY>i0zSCMtjAAaP=wphR+x2gxLD39>m-7CdJ^g7%F+TxlJpD(eyUbli{(Ox(@HffJT#>63ovmd)8h^R*8v)IN#8Z$25XHD*VUFw< z|Nn+ftzLsiZvQd%5OA1X4X#WCOhyg8f8_ULhp~Omb~Wl)oVei^j)833X$90$HO5vt z8agz)sr}jhutR>%zaGE>N#`8lN2q~1zm8ko$;m*1Oxmmn_xq(aLl&)K#5IT9d9SMNIQeX&?uA{(TcbhL&R+O) zhVUcYsGUSxfxbWK?s$MH>woc4rWy)lZ64Q6P0e3hfpjWU7GiQOBZ_yO%<%6w-B%Hgq!tv6ia!=IyfC`~+?+Nr1& zJ>D0Pj}Ygny}jY;USW64=rT^QqrpE1CnrH4=pCJ%2mzviZs%x-LKT#TGJoYe0|ri-Lo z0E5H{cR5+>gS-updzcWAz9ohkjYFySg-eh0w?X54+rmb}j0wNSq~ua_ZOb9${(a1D zZh_8kL<=nmvEhQ}@!8|$_HDO_(m`AtEXd8QBwn`Qos_oHzvE`aTIP7(4+V!0B>
  • {JARp#HdQy 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 M6>a4@MeDHt0r$>g(*OVf diff --git a/{{cookiecutter.repo_name}}/docs/sphinx/_static/sdssv_logo_small.png b/{{cookiecutter.repo_name}}/docs/sphinx/_static/sdssv_logo_small.png deleted file mode 100644 index ea25558a41da32c616220a56e1f55936834564f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7404 zcmZ{J1z40_^Y<>@oze{|yMS~oji9uEbk`EQuyjc&NJ=A}QqmxbG=g*^-3<}~Qc8S_ zkMH~Vf4=8Ed!2LUo|)gwoO5RGJ$r4Ky6QuGoI5xG003V}QBD&%OWk%X4CGh>bzVSD zKo`x2GJx_y+HK^+XDeMLYZVp1T_lYKzyy*2P;XU`9{}(U0R0yY0GI=5{!7~dIe+V* zAa!^F$Pqw}>SMOxY;^wJVj4`Zs;+fYndC6**x$DeAcZ z0Jx;L9SBHGrvd=bP@!77uDUA9q84yRkeMai+zRCB=yZz$hBeBdi#a@q&1mAvlbTjN%AOYf()(h2L=GlLWJ^ ztE-bJ80_KU0rGeNf+K9eydokZU>-g&A0IbTgWJUm=4$524Rc}n%gBH1$XU5qAfQgJ zP&kb7)~=a3+|5;jnfcbyf7|ak9i9H`2e^9rQ z{|R%2TK^B&t>iD*ug&-?MsehhimJdZq1IkTh#)%wrDii7{5^Y;pW zp=A+Px9On;hdV(2EnEJ=|Ecv411iX)vov!x`#%9Z;ML;e6BXbS*OrRxlUji9iJT#lin7_*bCb{{sFY_$N>n?f^$TaWb>8g7E(K^#|(@?c049 zm4!PxA*@_}#U>yQ{{MLY)YsLta)CRz-DVd=h>r)^z`VEPZ|I-me?tF8YQvze5We4# zf3W|FQbRzkkcs}wA#y#x0{oNrPkp_=?fqMTe~N!Y#lg2_@<-YHRg=HC$fAVcAdmS! z1rEW9ncDUQ04OV!v6EqDWzEMD z{!uBJG2(1&tzhH3+P}&90D{LRVR~1dg!K`rMtEcZa69LWOs1E6bN8&m#RVjk7y#e! zJN7F*nDu!7ZW7|N_ij?(XRmL{=tEy%1MRucW&mNcKVIB-cyqMa_2njyru0m(WwX)U zn|;Fu2Ha-KFcy5-yYdKGJE7s$Ed1m4Y6a&URf@a=%qs}HC(8K*$aGE=dE6;y%pD2M37f6&fF!Vu{p@pLxfd`T zr_~sJN@$1ymrG$?savk2;sM`37GOtHnX^sr@GKZvv@t^*C44L}rzMSFm^OWo%BGE7 zJv*%*c`!9tQ42h9Q41D1ji2kL0a+;SfLOc)Yw4sQWIYS&EoG%6GBbCmX=3R+$e$7Y z%u$;Q81$#qbUrwUuZ#R58PN5@YA_IXEZl=mTuyQ^8~+G$X$dy>PP5x>~cjlp?OjnvrvU6-rgC zU7c?l(^K!L4NlNWH$($2>!rChLc{W0w$VC0>8^nuA9LeO;S<#TpY#pH@mV|Ta!p}o z-pg~;Oyt1%M!XFv-NZ!I-1PNLM^DH5J9M$-s;|FI$STBhaLEvCfXF7Jd|rmBUe4aH zjR5Lu-4is741MPG2sjrD1syZAnDO}giZMUxC1XD@e`My$Px=U)9bU>Rj^_qoIF(-<(Cmg-+YhP~2xUU+HbFAm}a+ zG~3=^c6zOB0ZZxv?aN^sk2AhRB)R#ajt#zHBz_-G^6Qrh21HvuLB|NiN#2AAzn$I) z3S>%n35xq5{Fg&zU-)A-H%#wd?0o222w-Tx%;6n$X6N1@k;J@5%&jFD zp||@6`#}vyDQD!&GnYYwWc`GI_V)IcfKUDi0?J)Xn|dW_@`BJ4cHICLZ@rcDxiO3Y zOzNZ)v2F(fDt=Tb=Q%%CgHY02ln8S4$$7t_j)8v9A?p~sQ5ldwKP37@TRCQ*{W zghtZ|{0WBQWO?F^+xIOE-{Xxkgq77g6*I4wsumDyY;8cgGB7jTjnl0t?kF!hAj4~G zx>8w`zQ6nk)mDm`d-SC+XJC*g*DOe-9Es_RQ# zEJ0htmmA<7gh{8DXQD^E6LPUUZ8};e&5>^wO)IkV1v*yXijRk9njt#>X`)n*REaJ& z)-cc-GJjVj$IJG70e!uaMsYP-~_FQ6gRhZIstMVzWqH$h#;oJa(JVbF+e;)%ScT_%fJuFR_+dHr4&ZL-1Y!e z`-+3tcb&*Emm)`X^9)DROn-SU881$p)K%P3=j#N0hIf=I_scVBwO( zA|q{WOCnY5*hs@QJ)ce23w4v|sP6hnt4qTKO7KwDSYiH}(aZ(M>Zeh6saQ6U?zduR zuV>?SOpz>1>V+?ubvOolX_NJ-YJlIfF!s?YMY$<>{gtO*Nj!Wv6{f&}d{Ig;p3a#& zJ5+~;V!kae|19osnJM8@Tf^G3@`_3}yo4==yrDY%etUILy$$-)n++m2`l2ar5e7=N z>N|MWN3?J!pQ||ZCz5Qb34AfvsL(I;m-u1CdMu+j8_!r+-I!T-m_OH|$Eka2?Dq3>&TK4M2CypG9V|#tmj;ArYiRU< zOq$!vjhi;yPIlH!G%X$(_Y){@IYp#k0a3MXAW)i&4Fc|~qd`nKNgAXue{xcdBby7Dq0 zVXhuin_aPb2JM^)&JL-$Tgw#}4~z+T3t;0zB-MGUsi|4>rA&2%t?D^CX1IP^k|y!5 zYh?UEX6|>KMuI4QJe5;+Y*W5-YzDK;;3-mD3RV-NXt&Oqn{6*7=nfpayz^kzHK;mhUr?hVdY_s4MU^B%4>v-LjEYGR zQ>kjk1U|ECDW$GH?6tdqUo+jou9Diii?u}D+F%ikfp01V8}BGJX}RXI`>H<4MH(@q zu&&cO(Cf%Hq>vw)zd0zzk%spwAnp@i>pN|-ulu5Abn!`&XJ=F`;t=!gtM0H<)BHn4 zo-8Gjm9R{il@^(d_GSxGn=)2s8?F}`X))w1_@|WyN$ND>U3(;yEzrlJRoFFIQQg=~ zzI5q$TZ=6%U;6s)y{WDaPZ_XQVD^>*&0O=Syt^g1~EX7%IxGpI}Qq}XGx(8hK8V1F5PzFtGO+V;1s$uyu z%|M2od*Jj5kKbH5XNy7>1_r1pK!*F&#@JVP;{j(xLeP}tj(1n!mvc(e*L&_XT!tLN z)Kc72duPustHxC$S~fGIhtVyg>7=@V;Z=o1y^F&`N?g=zUi^?!oh~R7L(!wpU`od9 zM`zawLG@;@*Xfpw9>!_4QD8M3Y8mS47`E50M=`64)Dx2_Z(H3v_{KOMpqDowZ{kNF z8t(Z}myi~F@t7Ee1vYLIr!tg%6&F3pPpQl%G>aWY#pANk|LEm)nEhmV)k2exG^OuX zIo5);P0H${qh67ipyXl;y=UXk(wmai9R~PG^cf;D4ubaxb8*ts&iXUyYh$hyr^w8L z;4!&W%9AVY53Y~vQ?@f!t@F>>Lu_Q{ydG+6FHzgQmuQDs_I@jQ4vA8vbe@-jpiQQO z%8eR}-m+~yB!)HR5u+9z78hn3`mS|rY<&IN6-_Vk83%Wg=NxNho)H8Jp@aCoE;Fp( zxr(9@8uelu`=Gp{Ns>4VFqyixI9#4S#^MlpaM@lQzWT|M{nc|cZTnTU2P?)mg`%Iq zSg;SJMR%ivc$QjiCklaGCF}T-3e$2QTY*7pQLl8RtrJeDJblqSE*e5ItyA)y5Y7Cy zp97GMtt*;N(%8r^105Z`I+lf@Gf2|n>c@!%MsT3SQTM0aoKS_=%{SLS9ZgZ@M|hV< zBpLUU^EDh!LTRefiaiav!cz2xz50?^#eygoC#d=}T3>eY;^9v0V|`coOwr@iJn)VV z{BYgWG?*TxX7{t?6G^h7a3?gbsU+#j!`6|Bg-D=9SMLBPVTqIWi9@b%ghaEvb?qh!zXumb8d=zJR zybjd^dXOs?nIj&v#N+IK_n?mHkXpJSE3j;A+|Ux*omb%v3)y`1q`@q5ZU-}}Cenp% zR!ItZJKi*%N-Gkoi5So>Y&-`7;RA%Ubld*P*N6}~x##v+)6;LKBB{ry>bub%zM{9H z6FsjiHxkPVfzSv!uXI?r>R5bwU?O)Pi};Pf!bIirF6;eI@I87vV+93=D1~#uXPn=F zH%lA5t-42;rX(%we22>^E=)K^DKa2&)(-4O!=&@zdq;U{{PBQx;3nBzrwKK`Z8l(tax-HES*4iqiB1tQ0Okr6y4iA1c94aR)A-TZBkr;0k{wM`deuoM#aUU4_wU?uAcsA3mu$h&&{*!8pWBHF z(YN5FH<@5u7=A;oGI$dd5w~&J*-9M0>sbuLi4m_+p^t3@?bspXS@rSpX%X}LF@9`` zk7YagFp{b*JVL0t$;aPx4YcTCf|VvI8ORmBbM=W(@)GqhnCp33_&0ZMdFPpCapDq! ziw)H)`q8^VY@;u_%-kTh zs%7w#{M}1I?l0aVv*5;EA2(&D<)&;d#%Dz0oIGl9*b~ex#RQ9|l*n7q=_<1RQa(pA z^|e#=x+;z42j&ABhLS)=fq5jYAKkuU_z^ozFSZ;XR}x*!04`f+(}1CyXPhBBj%6D! zsru3@+TAD*xORaKsgkc{tY5kVN88R`E04~2zbzAc`Ua&Y?b7L}x9F`Ln3p+^@-*an zXt=u&AiJmrj{E}BeLe}pAmTGz5)yKpxrEu;`UkhPY`9j{*5d8WMD`^Va60Qx#V`dE zE7tcm|AZyG7pL-BX_hxMY(@xcQic%#%iF-8=9)vy115$i2#s<-d{^xbU#SD7PBGd4CKT?>|tvw)R3W$NrelXPXTVaSOY+eq9>hGZ#zj4|nQju%b6A0qW!J5x<=NEo9 zn>kEglM`vQDlaeZva@4XQwP5ZIoTcyeeoR4zA2v}iTkk`E+qu_bGJUt)$Xi^lm!`U zXbI(#pk%Pcp@244_vvHp4W_$KB+*$gg!O07$_9%71F@)SBTEeL=Zb?YpR2Fr&NXtFjL(SIO({n}szT)cZ1%FJh zcdUJ2uP^7;Pw?{I9C~yBGSronMq)}zQf0PY(8qJAA@;o$6xctdp~NM#(@j>GbjkN( zSy7j4V}y%jihGef-CsbN+?R+MS~u1FJYM|7$O4x(ytFXa_D0&1N(_%dI-Z~~WxOR% zLsi4PP4LrrS&jbrkJ6R;NtzR(;>-IOMBGz8iy2}b)|n8$4XC&3*U>k)vrRs)+yj}L z0@B!mN*+#)si}RQZ<`g7pyfDSPd2GCZt||ql-P#LyS`n$7o)SvZ9ciyGvI+&p*%W0 z8cDAskG6_2O^r~a2$X9yRveWlC4HDoE|-OhuR<-#VW0P{hB|v}p)zMH>f^^B9;f?P zp_HA33Q^v3UT8ZzJ5(Z?BO@-a)6ytDjD$#M*-9tD=0DmUVj`-ydZRY$?G)AS#^|7I zDsK*Efbkh1bH(*1A_jfioKf@=A5jw=KWWzsC|8!8l+PaIoCoAi9Y$BbrwQ|4Z2rI? z5b(v$BI{XdDK8M@9^6w~wYFxpd$E}{MqzAV(5Gk@9xf;q+Rv(Bo0s$0Vd;zDTBm6@ z0nZ^(bYjpm$3l&bmlk*08gkqlPOBqtxT^QggCFKY{OvDpxKM3L5P^sJ6oGGDaUi|o zzUMr<<%D^r_hzO@)gs$2Bs)2~y{|9PlVXT4(PySC*h204lFCvEa(-g+hFpe+hu;-6 zYZuHGM6J3byudzWrpR0o^?974$O2zMf#`$)w7;F`Xx8}Ef^ zjB&-gN;;*4ii(N?-3E_?=q>HV@edz9oGYLi6km=}We+{o)Ep)BclJS7a|lZlbc}Us z7^lcPix0b8i)Tar7T3k?ijQVI_ByhpP80Kp9;@CupYlq|%q-TUj3XFj_-LGCQD>>d z7eui`^UWWCD1O0#qhfnxG~Lxl4a>0dF-x{B6+V9cgxKni!<=N! zJvW?%0&Aw17+gA>dhScDK%U`9`wORx+6~wftd?xklN{vbQ+2M{&xZv*6gDNZZ1Nf4 z2is*#FT$@9O!FglmC6FQ%&n=Y#wRBij@b=^o@#4X_4hk$?vL^^8fh3Cw|$PLdr=K8 zUlp2~uG#FKFK_U@*b&Xs2=5$xzx8eFSZLs89na}1AU&Oy+8X}jAp`d_!te^r!D{U0 zAcrbl>h0&1mD__XQp!y0p6B0)&k57EcA_SCjdhkPgwp0$O^;w7Mq%)an?ztaLrPqn zOdA ig1Pn9UqhMjw-zk>B6gHf9_-sc?3CnH<;rDDgZ>{$$vP+i diff --git a/{{cookiecutter.repo_name}}/docs/sphinx/_templates/fulltoc.html b/{{cookiecutter.repo_name}}/docs/sphinx/_templates/fulltoc.html deleted file mode 100644 index 205faf6..0000000 --- a/{{cookiecutter.repo_name}}/docs/sphinx/_templates/fulltoc.html +++ /dev/null @@ -1,3 +0,0 @@ - -{{ toctree(collapse=False) }} - diff --git a/{{cookiecutter.repo_name}}/docs/sphinx/_templates/layout.html b/{{cookiecutter.repo_name}}/docs/sphinx/_templates/layout.html deleted file mode 100644 index d217236..0000000 --- a/{{cookiecutter.repo_name}}/docs/sphinx/_templates/layout.html +++ /dev/null @@ -1,3 +0,0 @@ -{# layout.html #} -{# Import the theme's layout. #} -{% extends "!layout.html" %} diff --git a/{{cookiecutter.repo_name}}/docs/sphinx/api.rst b/{{cookiecutter.repo_name}}/docs/sphinx/api.rst deleted file mode 100644 index 70f50b4..0000000 --- a/{{cookiecutter.repo_name}}/docs/sphinx/api.rst +++ /dev/null @@ -1,15 +0,0 @@ - -.. _api: - -{{cookiecutter.package_name}} Reference -========================= - -.. _api-main: - -Main ----- - -.. automodule:: {{cookiecutter.package_name}}.main - :members: - :undoc-members: - :show-inheritance: diff --git a/{{cookiecutter.repo_name}}/docs/sphinx/conf.py b/{{cookiecutter.repo_name}}/docs/sphinx/conf.py deleted file mode 100644 index 05150be..0000000 --- a/{{cookiecutter.repo_name}}/docs/sphinx/conf.py +++ /dev/null @@ -1,326 +0,0 @@ -# -*- coding: utf-8 -*- -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -# type: ignore - -import os - -from pkg_resources import parse_version - -try: - from {{cookiecutter.package_name}} import __version__ -except ModuleNotFoundError: - from sdsstools import get_package_version - __version__ = get_package_version(__file__, '{{cookiecutter.pip_name}}') or 'dev' - - -# Are we building in RTD? -on_rtd = os.environ.get('READTHEDOCS') == 'True' - -# Sphinx template selected in cookiecutter and whether to use releases -sphinx_template = '{{cookiecutter.sphinx_template}}' -use_releases = '{{cookiecutter.use_releases}}' - -if sphinx_template == 'sphinx-bootstrap': - import sphinx_bootstrap_theme - - -# Importing matplotlib here with agg to prevent tkinter error in readthedocs -# import matplotlib -# matplotlib.use('agg') - - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -# -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.napoleon', 'sphinx.ext.autosummary', - 'sphinx.ext.todo', 'sphinx.ext.viewcode', 'sphinx.ext.mathjax', - 'sphinx.ext.intersphinx'] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# -source_suffix = ['.rst', '.md'] -# source_suffix = '.rst' - -# source_parsers = { -# '.md': 'recommonmark.parser.CommonMarkParser', -# } - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = '{{cookiecutter.package_name}}' -copyright = '{0}, {1}'.format('{{cookiecutter.year}}', '{{cookiecutter.full_name}}') -author = '{{cookiecutter.full_name}}' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. - -# The short X.Y version. -version = parse_version(__version__).base_version -# The full version, including alpha/beta/rc tags. -release = __version__ - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = None - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This patterns also effect to html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -default_role = 'py:obj' - -# If true, '()' will be appended to :func: etc. cross-reference text. -# add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -# show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -# modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -# keep_warnings = False - -# If true, `todo` and `todoList` produce output, else they produce nothing. -todo_include_todos = False - -# Intersphinx mappings -intersphinx_mapping = {'python': ('https://docs.python.org/', None), - 'astropy': ('http://docs.astropy.org/en/latest', None), - 'numpy': ('http://docs.scipy.org/doc/numpy/', None)} - -autodoc_mock_imports = ['_tkinter'] -autodoc_member_order = 'groupwise' - -napoleon_use_rtype = False -napoleon_use_ivar = True - -rst_epilog = f""" -.. |numpy_array| replace:: Numpy array -.. |HDUList| replace:: :class:`~astropy.io.fits.HDUList` -.. |{{cookiecutter.package_name}}_version| replace:: {__version__} -""" - - -# -- Options for HTML output ---------------------------------------------- - -html_css_files = [] - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. - -if sphinx_template == 'sphinx-bootstrap': - - html_theme = 'bootstrap' - - html_sidebars = {} - - # Theme options are theme-specific and customize the look and feel of a theme - # further. For a list of options available for each theme, see the - # documentation. - html_theme_options = { - # Navigation bar title. (Default: ``project`` value) - 'navbar_title': "SDSS: {0}".format(project), - - # Tab name for entire site. (Default: "Site") - 'navbar_site_name': "Site", - - # A list of tuples containing pages or urls to link to. - # Valid tuples should be in the following forms: - # (name, page) # a link to a page - # (name, "/aa/bb", 1) # a link to an arbitrary relative url - # (name, "http://example.com", True) # arbitrary absolute url - # Note the "1" or "True" value above as the third argument to indicate - # an arbitrary url. - 'navbar_links': [ - ], - - # Render the next and previous page links in navbar. (Default: true) - 'navbar_sidebarrel': False, - - # Render the current pages TOC in the navbar. (Default: true) - 'navbar_pagenav': False, - - # Tab name for the current pages TOC. (Default: "Page") - 'navbar_pagenav_name': "Page", - - # Global TOC depth for "site" navbar tab. (Default: 1) - # Switching to -1 shows all levels. - 'globaltoc_depth': 2, - - # Include hidden TOCs in Site navbar? - # - # Note: If this is "false", you cannot have mixed ``:hidden:`` and - # non-hidden ``toctree`` directives in the same page, or else the build - # will break. - # - # Values: "true" (default) or "false" - 'globaltoc_includehidden': "true", - - # HTML navbar class (Default: "navbar") to attach to
    element. - # For black navbar, do "navbar navbar-inverse" - 'navbar_class': "navbar", - - # Fix navigation bar to top of page? - # Values: "true" (default) or "false" - 'navbar_fixed_top': "true", - - # Location of link to source. - # Options are "nav" (default), "footer" or anything else to exclude. - 'source_link_position': "", - - # Bootswatch (http://bootswatch.com/) theme. - # - # Options are nothing (default) or the name of a valid theme - # such as "amelia" or "cosmo". - 'bootswatch_theme': "paper", - - # Choose Bootstrap version. - # Values: "3" (default) or "2" (in quotes) - 'bootstrap_version': "3", - } - - # Add any paths that contain custom themes here, relative to this directory. - html_theme_path = sphinx_bootstrap_theme.get_html_theme_path() - - html_logo = '_static/sdssv_logo_small.png' - - html_css_files += ["custom_bootstrap.css"] - - html_sidebars = {'**': ['localtoc.html']} - -elif sphinx_template == 'alabaster': - - html_theme = 'alabaster' - - html_theme_options = { - 'logo': 'sdssv_logo.png', - 'github_user': 'sdss', - 'github_repo': project, - 'github_button': True, - 'github_type': 'star', - 'sidebar_collapse': True, - 'page_width': '80%' - } - - html_sidebars = { - '**': [ - 'about.html', - 'navigation.html', - 'relations.html', - 'searchbox.html', - ] - } - - html_css_files += ["custom.css"] - -html_favicon = './_static/favicon_sdssv.ico' - -# 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". - -# See https://github.com/rtfd/readthedocs.org/issues/1776 for why we do this -if on_rtd: - html_static_path = [] -else: - html_static_path = ['_static'] - - -# -- Options for HTMLHelp output ------------------------------------------ - -# Output file base name for HTML help builder. -htmlhelp_basename = '{0}pdoc'.format('{{cookiecutter.package_name}}') - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - (master_doc, '{0}.tex'.format(project), u'{0} Documentation'.format(project), - author, 'manual'), -] - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, '{{cookiecutter.package_name}}', u'{0} Documentation'.format(project), - [author], 1) -] - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - (master_doc, project, u'{0} Documentation'.format(project), - author, project, 'One line description of project.', - 'Miscellaneous'), -] - -if use_releases == 'yes': - - extensions += ['sdsstools.releases'] - - releases_github_path = '{{cookiecutter.github_organisation}}/{{cookiecutter.package_name}}' - releases_document_name = ['CHANGELOG'] - releases_unstable_prehistory = True diff --git a/{{cookiecutter.repo_name}}/docs/sphinx/index.rst b/{{cookiecutter.repo_name}}/docs/sphinx/index.rst deleted file mode 100644 index 97c9d12..0000000 --- a/{{cookiecutter.repo_name}}/docs/sphinx/index.rst +++ /dev/null @@ -1,35 +0,0 @@ - -{{cookiecutter.package_name}}'s documentation -============================================= - -This is the documentation for the SDSS Python product {{cookiecutter.package_name}}. The current version is |{{cookiecutter.package_name}}_version|. You can install the package by doing - -.. code-block:: console - - $ pip install {{cookiecutter.pip_name}} - - -Contents --------- - -.. toctree:: - :maxdepth: 2 - - What's new in {{cookiecutter.package_name}}? - Introduction to {{cookiecutter.package_name}} - - -Reference ---------- - -.. toctree:: - :maxdepth: 1 - - api - - -Indices and tables ------------------- - -* :ref:`genindex` -* :ref:`modindex` diff --git a/{{cookiecutter.repo_name}}/docs/sphinx/intro.rst b/{{cookiecutter.repo_name}}/docs/sphinx/intro.rst deleted file mode 100644 index 5ed0237..0000000 --- a/{{cookiecutter.repo_name}}/docs/sphinx/intro.rst +++ /dev/null @@ -1,7 +0,0 @@ - -.. _intro: - -Introduction to {{cookiecutter.package_name}} -=============================== - -We should write an introduction here. diff --git a/{{cookiecutter.repo_name}}/docs/sphinx/requirements.txt b/{{cookiecutter.repo_name}}/docs/sphinx/requirements.txt deleted file mode 100644 index c9ed3eb..0000000 --- a/{{cookiecutter.repo_name}}/docs/sphinx/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -sphinx_bootstrap_theme~=0.4.12 diff --git a/{{cookiecutter.repo_name}}/etc/config.ini b/{{cookiecutter.repo_name}}/etc/config.ini deleted file mode 100644 index 4bfa2a5..0000000 --- a/{{cookiecutter.repo_name}}/etc/config.ini +++ /dev/null @@ -1,8 +0,0 @@ -# -# This configuration file provides options to sdss4install specific to this product -# - -[sdss4install] -evilmake = True -no_python_package = True - diff --git a/{{cookiecutter.repo_name}}/etc/{{cookiecutter.package_name}}.module b/{{cookiecutter.repo_name}}/etc/{{cookiecutter.package_name}}.module deleted file mode 100644 index 6465e3a..0000000 --- a/{{cookiecutter.repo_name}}/etc/{{cookiecutter.package_name}}.module +++ /dev/null @@ -1,74 +0,0 @@ -#%Module1.0 -# The first line of this file tells Modules that this is a module file. -# DO NOT ALTER IT! -# -# ABOUT THIS FILE -# -# This file is designed to be processed by Python. Specifically, this file -# will be read into a string, and the .format() method will be applied to it. -# This file is not a valid module file on its own. -# -# METADATA AND DOCUMENTATION SECTION -# -# This function is part of the Modules help system. You can modify -# the second line if needed, but most products should -# leave this alone. -# -proc ModulesHelp {{"{{ }} {{"}} - global product version - puts stderr {{'This module adds $product/$version to your environment.'}} - -{{"}}"}} -# -# These variables are used below. The product variable should be set to -# the name of the product and never changed. The version variable will -# be set at install time, so it should be left alone. The conflict line -# prevents multiple versions from being loaded simultaneously. Do not -# change it. -# -set product {name} -set version {version} -conflict $product -# -# The line below is another part of the Modules help system. You can -# modify the part in quotes if you really need to, but most products should -# leave this alone. -# -module-whatis "Sets up $product/$version in your environment." -# -# DEPENDENCIES SECTION -# -# If your product requires other software to function, that should be declared -# here. There are two types of dependencies: mandatory and optional. -# A mandatory dependency is a module load command followed by a prereq -# command. An optional dependency is not followed by a prereq statement. -# - - - -# -# ENVIRONMENT SECTION -# -# The PRODUCT_ROOT and PRODUCT_DIR variables are used to set other -# environment variables, exported to the actual environment, by sdss4install -# -set PRODUCT_ROOT {root} -set PRODUCT_DIR $PRODUCT_ROOT/$product/$version -# -# This line creates an environment variable pointing to the install -# directory of your product. -# -setenv [string toupper $product]_DIR $PRODUCT_DIR -# -# The lines below set various other environment variables. They assume the -# template product layout. These will be set or commented as needed by the -# sdss4install script. -# -{needs_bin}prepend-path PATH $PRODUCT_DIR/bin -{needs_python}prepend-path PYTHONPATH $PRODUCT_DIR/lib/{pyversion}/site-packages -{needs_trunk_python}prepend-path PYTHONPATH $PRODUCT_DIR/python -{needs_ld_lib}prepend-path LD_LIBRARY_PATH $PRODUCT_DIR/lib -{needs_idl}prepend-path IDL_PATH +$PRODUCT_DIR/pro -# -# Add any non-standard Module code below this point. -# diff --git a/{{cookiecutter.repo_name}}/poetry/.flake8 b/{{cookiecutter.repo_name}}/poetry/.flake8 deleted file mode 100644 index d0adef6..0000000 --- a/{{cookiecutter.repo_name}}/poetry/.flake8 +++ /dev/null @@ -1,11 +0,0 @@ -[flake8] - -ignore = - H101 - N - W504 - -per-file-ignores = - */__init__.py:E,W - -max-line-length = 99 diff --git a/{{cookiecutter.repo_name}}/poetry/__main__.py b/{{cookiecutter.repo_name}}/poetry/__main__.py deleted file mode 100644 index 1777af1..0000000 --- a/{{cookiecutter.repo_name}}/poetry/__main__.py +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -# -# @Author: JosΓ© SΓ‘nchez-Gallego -# @Date: Dec 1, 2017 -# @Filename: cli.py -# @License: BSD 3-Clause -# @Copyright: JosΓ© SΓ‘nchez-Gallego - -import argparse -import os -import sys - -from {{cookiecutter.package_name}}.main import math - - -def main(): - - # An example of how to write a command line parser that works with the - # main.math function. For more details on how to use argparse, start with - # this tutorial: http://bit.ly/2SGDf7h - - parser = argparse.ArgumentParser( - prog=os.path.basename(sys.argv[0]), - description='Performs an arithmetic operation.') - - parser.add_argument('VALUE1', type=float, help='The first operand') - parser.add_argument('OPERATOR', type=str, help='The operator [+, -, *, /]') - parser.add_argument('VALUE2', type=float, help='The second operand') - - parser.add_argument('-v', '--verbose', action='store_true', default=False, - help='sets verbose mode') - - args = parser.parse_args() - - result = math(args.VALUE1, args.VALUE2, arith_operator=args.OPERATOR) - - if args.verbose: - print('{} {} {} = {}'.format(args.VALUE1, args.OPERATOR, args.VALUE2, result)) - else: - print(result) - - -if __name__ == '__main__': - - main() diff --git a/{{cookiecutter.repo_name}}/poetry/build.py b/{{cookiecutter.repo_name}}/poetry/build.py deleted file mode 100644 index 185a9ad..0000000 --- a/{{cookiecutter.repo_name}}/poetry/build.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# @Author: JosΓ© SΓ‘nchez-Gallego (gallegoj@uw.edu) -# @Date: 2019-12-17 -# @Filename: build.py -# @License: BSD 3-clause (http://www.opensource.org/licenses/BSD-3-Clause) - -# Extension build system using poetry, see https://github.com/python-poetry/poetry/issues/11. -# Add your Extension modules (https://docs.python.org/3.8/library/distutils.html) to the -# ext_modules list and they will be build and installed on poetry install. -# For production, you will need to use the create_setup.py script to manually -# generate a setup.py or the installation will fail because of the lack of -# setup.py. This is a bug in poetry that hopefully will be fixed soon. - - -ext_modules = [ -] - - -def build(setup_kwargs): - """To build the extensions with poetry.""" - - setup_kwargs.update({ - 'ext_modules': ext_modules - }) diff --git a/{{cookiecutter.repo_name}}/poetry/create_setup.py b/{{cookiecutter.repo_name}}/poetry/create_setup.py deleted file mode 100644 index 23cc0e6..0000000 --- a/{{cookiecutter.repo_name}}/poetry/create_setup.py +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# @Author: JosΓ© SΓ‘nchez-Gallego (gallegoj@uw.edu) -# @Date: 2019-12-18 -# @Filename: create_setup.py -# @License: BSD 3-clause (http://www.opensource.org/licenses/BSD-3-Clause) - -# This is a temporary solution for the fact that pip install . fails with -# poetry when there is no setup.py and an extension needs to be compiled. -# See https://github.com/python-poetry/poetry/issues/1516. Running this -# script creates a setup.py filled out with information generated by -# poetry when parsing the pyproject.toml. - -# type: ignore - -import os -import sys -from distutils.version import StrictVersion - -# If there is a global installation of poetry, prefer that. -lib = os.path.expanduser("~/.poetry/lib") -vendors = os.path.join(lib, "poetry", "_vendor") -current_vendors = os.path.join( - vendors, "py{}".format(".".join(str(v) for v in sys.version_info[:2])) -) - -sys.path.insert(0, lib) -sys.path.insert(0, current_vendors) - -try: - try: - from poetry.core.factory import Factory - from poetry.core.masonry.builders.sdist import SdistBuilder - except (ImportError, ModuleNotFoundError): - from poetry.masonry.builders.sdist import SdistBuilder - from poetry.factory import Factory - from poetry.__version__ import __version__ -except (ImportError, ModuleNotFoundError) as ee: - raise ImportError( - "install poetry by doing pip install poetry to use " f"this script: {ee}" - ) - - -# Generate a Poetry object that knows about the metadata in pyproject.toml -factory = Factory() -poetry = factory.create_poetry(os.path.dirname(__file__)) - -# Use the SdistBuilder to genrate a blob for setup.py -if StrictVersion(__version__) >= StrictVersion("1.1.0b1"): - sdist_builder = SdistBuilder(poetry, None) -else: - sdist_builder = SdistBuilder(poetry, None, None) - -setuppy_blob = sdist_builder.build_setup() - -with open("setup.py", "wb") as unit: - unit.write(setuppy_blob) - unit.write(b"\n# This setup.py was autogenerated using poetry.\n") diff --git a/{{cookiecutter.repo_name}}/poetry/pyproject.toml b/{{cookiecutter.repo_name}}/poetry/pyproject.toml deleted file mode 100644 index 460b225..0000000 --- a/{{cookiecutter.repo_name}}/poetry/pyproject.toml +++ /dev/null @@ -1,87 +0,0 @@ -[tool.poetry] -name = "{{cookiecutter.pip_name}}" -version = "{{cookiecutter.version}}" -description = "{{cookiecutter.short_description}}" -authors = ["{{cookiecutter.full_name}} <{{cookiecutter.email}}>"] -license = "BSD-3-Clause" -readme = "README.md" -homepage = "https://github.com/{{cookiecutter.github_organisation}}/{{cookiecutter.repo_name}}" -repository = "https://github.com/{{cookiecutter.github_organisation}}/{{cookiecutter.repo_name}}" -documentation = "https://{{cookiecutter.pip_name}}.readthedocs.org" -keywords = ["astronomy", "software"] -classifiers = [ - "Intended Audience :: Science/Research", - "Natural Language :: English", - "Operating System :: OS Independent", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Topic :: Documentation :: Sphinx", - "Topic :: Software Development :: Libraries :: Python Modules" -] -packages = [ - { include = "{{cookiecutter.package_name}}", from = "python" } -] -include = ["python/{{cookiecutter.package_name}}/etc/*"] - -[tool.poetry.build] -script = "build.py" -generate-setup-file = false - -[tool.poetry.scripts] -{{cookiecutter.package_name}} = "{{cookiecutter.package_name}}.__main__:main" - -[tool.poetry.dependencies] -python = "^3.7,<4.0" -sdss-tree = ">=2.15.2" -sdss-access = ">=0.2.3" -sdsstools = ">=0.4.0" - -[tool.poetry.dev-dependencies] -ipython = [ - {version = ">=8.0.0rc1", python = ">=3.8", allow-prereleases = true}, - {version = ">=7.0.0", python = ">=3.7,<3.8"} -] -matplotlib = ">=3.1.1" -flake8 = ">=3.7.9" -doc8 = ">=0.8.0" -pytest = ">=5.2.2" -pytest-asyncio = ">=0.10.0" -pytest-cov = ">=2.8.1" -pytest-mock = ">=1.13.0" -pytest-sugar = ">=0.9.2" -isort = ">=4.3.21" -codecov = ">=2.0.15" -coverage = {version = ">=5.0", extras = ["toml"]} -ipdb = ">=0.12.3" -rstcheck = "^3.3.1" -Sphinx = "^3.0.0" - -[tool.isort] -line_length = 79 -sections = ["FUTURE", "STDLIB", "THIRDPARTY", "SDSS", "FIRSTPARTY", "LOCALFOLDER"] -default_section = "THIRDPARTY" -known_first_party = "{{cookiecutter.package_name}}" -known_sdss = ["sdsstools"] -balanced_wrapping = true -include_trailing_comma = false -lines_after_imports = 2 -use_parentheses = true - -[tool.pytest.ini_options] -addopts = "--cov {{cookiecutter.package_name}} --cov-report xml --cov-report html --cov-report term" - -[tool.coverage.run] -branch = true -include = ["python/{{cookiecutter.package_name}}/*"] -omit = [ - "*/__init__.py", -] - -[tool.coverage.report] -exclude_lines = [ -] - -[build-system] -requires = ["poetry-core>=1.0.0", "setuptools>=49.6.0"] -build-backend = "poetry.core.masonry.api" diff --git a/{{cookiecutter.repo_name}}/python/{{cookiecutter.package_name|lower}}/__init__.py b/{{cookiecutter.repo_name}}/python/{{cookiecutter.package_name|lower}}/__init__.py deleted file mode 100644 index 9ce9877..0000000 --- a/{{cookiecutter.repo_name}}/python/{{cookiecutter.package_name|lower}}/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# encoding: utf-8 - -from sdsstools import get_config, get_logger, get_package_version - -# pip package name -NAME = '{{cookiecutter.pip_name}}' - -# Loads config. config name is the package name. -config = get_config('{{cookiecutter.package_name}}') - -# Inits the logging system as NAME. Only shell logging, and exception and warning catching. -# File logging can be started by calling log.start_file_logger(path). Filename can be different -# than NAME. -log = get_logger(NAME) - - -# package name should be pip package name -__version__ = get_package_version(path=__file__, package_name=NAME) diff --git a/{{cookiecutter.repo_name}}/python/{{cookiecutter.package_name|lower}}/etc/{{cookiecutter.package_name}}.yml b/{{cookiecutter.repo_name}}/python/{{cookiecutter.package_name|lower}}/etc/{{cookiecutter.package_name}}.yml deleted file mode 100644 index 6eb68dd..0000000 --- a/{{cookiecutter.repo_name}}/python/{{cookiecutter.package_name|lower}}/etc/{{cookiecutter.package_name}}.yml +++ /dev/null @@ -1,9 +0,0 @@ ---- - -option1: - suboption1: 1 - suboption2: "some text" - suboption3: - subsuboption1: [1, 2, 3] - -option2: 2.0 diff --git a/{{cookiecutter.repo_name}}/python/{{cookiecutter.package_name|lower}}/exceptions.py b/{{cookiecutter.repo_name}}/python/{{cookiecutter.package_name|lower}}/exceptions.py deleted file mode 100644 index 59ce263..0000000 --- a/{{cookiecutter.repo_name}}/python/{{cookiecutter.package_name|lower}}/exceptions.py +++ /dev/null @@ -1,74 +0,0 @@ -# !usr/bin/env python -# -*- coding: utf-8 -*- -# -# Licensed under a 3-clause BSD license. -# -# @Author: Brian Cherinka -# @Date: 2017-12-05 12:01:21 -# @Last modified by: Brian Cherinka -# @Last Modified time: 2017-12-05 12:19:32 - -from __future__ import print_function, division, absolute_import -{% set package_ucfirst = cookiecutter.package_name[0:1]|upper ~ cookiecutter.package_name[1:] %} - -class {{package_ucfirst}}Error(Exception): - """A custom core {{package_ucfirst}} exception""" - - def __init__(self, message=None): - - message = 'There has been an error' \ - if not message else message - - super({{package_ucfirst}}Error, self).__init__(message) - - -class {{package_ucfirst}}NotImplemented({{package_ucfirst}}Error): - """A custom exception for not yet implemented features.""" - - def __init__(self, message=None): - - message = 'This feature is not implemented yet.' \ - if not message else message - - super({{package_ucfirst}}NotImplemented, self).__init__(message) - - -class {{package_ucfirst}}APIError({{package_ucfirst}}Error): - """A custom exception for API errors""" - - def __init__(self, message=None): - if not message: - message = 'Error with Http Response from {{package_ucfirst}} API' - else: - message = 'Http response error from {{package_ucfirst}} API. {0}'.format(message) - - super({{package_ucfirst}}APIError, self).__init__(message) - - -class {{package_ucfirst}}ApiAuthError({{package_ucfirst}}APIError): - """A custom exception for API authentication errors""" - pass - - -class {{package_ucfirst}}MissingDependency({{package_ucfirst}}Error): - """A custom exception for missing dependencies.""" - pass - - -class {{package_ucfirst}}Warning(Warning): - """Base warning for {{package_ucfirst}}.""" - - -class {{package_ucfirst}}UserWarning(UserWarning, {{package_ucfirst}}Warning): - """The primary warning class.""" - pass - - -class {{package_ucfirst}}SkippedTestWarning({{package_ucfirst}}UserWarning): - """A warning for when a test is skipped.""" - pass - - -class {{package_ucfirst}}DeprecationWarning({{package_ucfirst}}UserWarning): - """A warning for deprecated features.""" - pass diff --git a/{{cookiecutter.repo_name}}/python/{{cookiecutter.package_name|lower}}/main.py b/{{cookiecutter.repo_name}}/python/{{cookiecutter.package_name|lower}}/main.py deleted file mode 100644 index 6625384..0000000 --- a/{{cookiecutter.repo_name}}/python/{{cookiecutter.package_name|lower}}/main.py +++ /dev/null @@ -1,82 +0,0 @@ -# encoding: utf-8 -# -# @Author: JosΓ© SΓ‘nchez-Gallego -# @Date: Oct 12, 2017 -# @Filename: main.py -# @License: BSD 3-Clause -# @Copyright: JosΓ© SΓ‘nchez-Gallego - -import operator - - -__all__ = ('math', 'MyClass') - - -def math(arg1, arg2, arith_operator='+'): - """Performs an arithmetic operation. - - This function accepts to numbers and performs an arithmetic operation - with them. The arithmetic operation can be passed as a string. By default, - the addition operator is assumed. - - Parameters: - arg1,arg2 (float): - The numbers that we will sub/subtract/multiply/divide. - arith_operator ({'+', '-', '*', '/'}): - A string indicating the arithmetic operation to perform. - - Returns: - result (float): - The result of the arithmetic operation. - - Example: - >>> math(2, 2, arith_operator='*') - >>> 4 - - """ - - str_to_operator = {'+': operator.add, - '-': operator.sub, - '*': operator.mul, - '/': operator.truediv} - - return str_to_operator[arith_operator](arg1, arg2) - - -class MyClass(object): - """A description of the class. - - The top docstring in a class describes the class in general, and the - parameters to be passed to the class ``__init__``. - - Parameters: - arg1 (float): - The first argument. - arg2 (int): - The second argument. - kwarg1 (str): - A keyword argument. - - Attributes: - name (str): A description of what names gives acces to. - - """ - - def __init__(self, arg1, arg2, kwarg1='a'): - - self.name = arg1 - - def do_something(self): - """A description of what this method does.""" - - pass - - def do_something_else(self, param): - """A description of what this method does. - - If the class only has one or two arguments, you can describe them - inline. ``param`` is the parameter that we use to do something else. - - """ - - pass diff --git a/{{cookiecutter.repo_name}}/readthedocs.yml b/{{cookiecutter.repo_name}}/readthedocs.yml deleted file mode 100644 index 65ae459..0000000 --- a/{{cookiecutter.repo_name}}/readthedocs.yml +++ /dev/null @@ -1,11 +0,0 @@ -version: 2 - -build: - image: latest - -python: - version: 3.8 - install: - - requirements: docs/sphinx/requirements.txt - - method: pip - path: . diff --git a/{{cookiecutter.repo_name}}/setup_cfg/MANIFEST.in b/{{cookiecutter.repo_name}}/setup_cfg/MANIFEST.in deleted file mode 100644 index b1c147e..0000000 --- a/{{cookiecutter.repo_name}}/setup_cfg/MANIFEST.in +++ /dev/null @@ -1,2 +0,0 @@ -recursive-include python/{{cookiecutter.package_name}}/etc * -recursive-include cextern/**/* diff --git a/{{cookiecutter.repo_name}}/setup_cfg/setup.cfg b/{{cookiecutter.repo_name}}/setup_cfg/setup.cfg deleted file mode 100644 index bdac6ac..0000000 --- a/{{cookiecutter.repo_name}}/setup_cfg/setup.cfg +++ /dev/null @@ -1,109 +0,0 @@ -[metadata] -name = {{cookiecutter.pip_name}} -version = {{cookiecutter.version}} -author = {{cookiecutter.full_name}} -author_email = {{cookiecutter.email}} -description = {{cookiecutter.short_description}} -url = https://github.com/{{cookiecutter.github_organisation}}/{{cookiecutter.repo_name}} -project_urls = - Repository = https://github.com/{{cookiecutter.github_organisation}}/{{cookiecutter.repo_name}} - Documentation = https://{{cookiecutter.pip_name}}.readthedocs.org -long_description = file: README.md -long_description_content_type = text/markdown -keywords = astronomy, software -license = BSD 3-Clause License -license_file = LICENSE.md -classifiers = - Intended Audience :: Science/Research - Natural Language :: English - Operating System :: OS Independent - Programming Language :: Python - Programming Language :: Python :: 3.6 - Programming Language :: Python :: 3.7 - Programming Language :: Python :: 3.8 - Topic :: Documentation :: Sphinx - Topic :: Software Development :: Libraries :: Python Modules - -[options] -zip_safe = False -python_requires = >=3.6 -packages = find: -package_dir = - = python -install_requires = - sdss-tree>=2.15.2 - sdss-access>=0.2.3 - sdsstools>=0.4.0 -scripts = - bin/{{cookiecutter.package_name}} - -[options.packages.find] -where = - python - -[options.package_data] -{{cookiecutter.package_name}} = - etc/* - -[options.extras_require] -dev = - ipython>=7.9.0 - matplotlib>=3.1.1 - flake8>=3.7.9 - doc8>=0.8.0 - pytest>=5.2.2 - pytest-asyncio>=0.10.0 - pytest-cov>=2.8.1 - pytest-mock>=1.13.0 - pytest-sugar>=0.9.2 - isort>=4.3.21 - codecov>=2.0.15 - coverage[toml]>=5.0 - ipdb>=0.12.3 - invoke>=1.3.0 - twine>=3.1.1 - wheel>=0.33.6 - sphinx>=3.0.0 - -[isort] -line_length = 79 -sections = - FUTURE - STDLIB - THIRDPARTY - SDSS - FIRSTPARTY - LOCALFOLDER -default_section = THIRDPARTY -known_first_party = {{cookiecutter.package_name}} -known_sdss_party = - sdssdb - sdsstools -balanced_wrapping = true -include_trailing_comma = false -lines_after_imports = 2 -use_parentheses = true - -[flake8] -ignore = - H101 - E722 - W504 - W505 -per-file-ignores = - */__init__.py:E,W -max-line-length = 99 - -[tool:pytest] -addopts = --cov {{cookiecutter.package_name}} --cov-report html -W ignore - -[coverage:run] -branch = true -include = - python/{{cookiecutter.package_name}}/* -omit = - */utils/*.py - */__init__.py - -[coverage:report] -exclude_lines = diff --git a/{{cookiecutter.repo_name}}/setup_cfg/setup.py b/{{cookiecutter.repo_name}}/setup_cfg/setup.py deleted file mode 100644 index 578f6d6..0000000 --- a/{{cookiecutter.repo_name}}/setup_cfg/setup.py +++ /dev/null @@ -1,9 +0,0 @@ -# encoding: utf-8 -# -# setup.py -# - -from setuptools import setup - - -setup() diff --git a/{{cookiecutter.repo_name}}/tests/__init__.py b/{{cookiecutter.repo_name}}/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/{{cookiecutter.repo_name}}/tests/conftest.py b/{{cookiecutter.repo_name}}/tests/conftest.py deleted file mode 100644 index 8f69f1d..0000000 --- a/{{cookiecutter.repo_name}}/tests/conftest.py +++ /dev/null @@ -1,11 +0,0 @@ -# encoding: utf-8 -# -# conftest.py - -""" -Here you can add fixtures that will be used for all the tests in this -directory. You can also add conftest.py files in underlying subdirectories. -Those conftest.py will only be applies to the tests in that subdirectory and -underlying directories. See https://docs.pytest.org/en/2.7.3/plugins.html for -more information. -""" diff --git a/{{cookiecutter.repo_name}}/tests/test_main.py b/{{cookiecutter.repo_name}}/tests/test_main.py deleted file mode 100644 index f3a244e..0000000 --- a/{{cookiecutter.repo_name}}/tests/test_main.py +++ /dev/null @@ -1,17 +0,0 @@ -# encoding: utf-8 -# -# main.py - -from pytest import mark - -from {{cookiecutter.package_name}}.main import math - - -class TestMath(object): - """Tests for the ``math`` function in main.py.""" - - @mark.parametrize(('arg1', 'arg2', 'operator', 'result'), - [(1, 2, '+', 3), (2, 2, '-', 0), (3, 5, '*', 15), (10, 2, '/', 5)]) - def test_math(self, arg1, arg2, operator, result): - - assert math(arg1, arg2, arith_operator=operator) == result From 8c6493277b886911190c5156cba605276db5fd41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20S=C3=A1nchez-Gallego?= Date: Tue, 30 Dec 2025 01:14:14 -0800 Subject: [PATCH 2/9] Initial template --- copier.yaml | 96 +++++++ pyproject.toml | 1 + template/.github/workflows/lint.yml | 34 +++ template/.github/workflows/release.yml.jinja | 44 +++ template/.github/workflows/test.yml | 48 ++++ template/.gitignore | 109 +++++++ template/CHANGELOG.md.jinja | 3 + template/CODEOWNERS.jinja | 39 +++ template/LICENSE.md | 29 ++ template/README.md.jinja | 3 + template/docs/sphinx/_static/custom.css | 43 +++ template/docs/sphinx/_static/favicon.ico | Bin 0 -> 1150 bytes .../docs/sphinx/_static/favicon_sdssv.ico | Bin 0 -> 1150 bytes template/docs/sphinx/_static/sdss_logo.png | Bin 0 -> 24816 bytes template/docs/sphinx/_static/sdssv_logo.png | Bin 0 -> 42239 bytes .../docs/sphinx/_static/sdssv_logo_small.png | Bin 0 -> 7404 bytes template/docs/sphinx/changelog.md | 4 + template/docs/sphinx/conf.py.jinja | 143 ++++++++++ template/docs/sphinx/index.rst.jinja | 27 ++ template/docs/sphinx/requirements.txt | 7 + template/noxfile.py | 49 ++++ template/post_copy.py | 207 ++++++++++++++ template/pyproject.toml.jinja | 68 +++++ template/readthedocs.yml | 15 + .../src/{{package_name}}/__init__.py.jinja | 13 + template/tests/__init__.py | 0 template/tests/conftest.py | 0 template/{{_copier_conf.answers_file}}.jinja | 2 + uv.lock | 270 ++++++++++++++++++ 29 files changed, 1254 insertions(+) create mode 100644 copier.yaml create mode 100644 template/.github/workflows/lint.yml create mode 100644 template/.github/workflows/release.yml.jinja create mode 100644 template/.github/workflows/test.yml create mode 100644 template/.gitignore create mode 100644 template/CHANGELOG.md.jinja create mode 100644 template/CODEOWNERS.jinja create mode 100644 template/LICENSE.md create mode 100644 template/README.md.jinja create mode 100644 template/docs/sphinx/_static/custom.css create mode 100644 template/docs/sphinx/_static/favicon.ico create mode 100644 template/docs/sphinx/_static/favicon_sdssv.ico create mode 100644 template/docs/sphinx/_static/sdss_logo.png create mode 100644 template/docs/sphinx/_static/sdssv_logo.png create mode 100644 template/docs/sphinx/_static/sdssv_logo_small.png create mode 100644 template/docs/sphinx/changelog.md create mode 100644 template/docs/sphinx/conf.py.jinja create mode 100644 template/docs/sphinx/index.rst.jinja create mode 100644 template/docs/sphinx/requirements.txt create mode 100644 template/noxfile.py create mode 100644 template/post_copy.py create mode 100644 template/pyproject.toml.jinja create mode 100644 template/readthedocs.yml create mode 100644 template/src/{{package_name}}/__init__.py.jinja create mode 100644 template/tests/__init__.py create mode 100644 template/tests/conftest.py create mode 100644 template/{{_copier_conf.answers_file}}.jinja diff --git a/copier.yaml b/copier.yaml new file mode 100644 index 0000000..9a10ab8 --- /dev/null +++ b/copier.yaml @@ -0,0 +1,96 @@ +project_name: + type: str + qmark: πŸ“š + help: The name of the project. Used as repository name, in documentation, and other places. + validator: >- + {% if project_name == "" %} + Answer must not be an empty string. + {% endif %} + +package_name: + type: str + qmark: πŸ“¦ + help: The name of the Python package to create. This is the import name and the name of the package in PyPI. + validator: >- + {% if package_name == "" %} + Answer must not be an empty string. + {% endif %} + +project_description: + type: str + qmark: πŸ“ + help: A short description of the project. + validator: >- + {% if project_description == "" %} + Answer must not be an empty string. + {% endif %} + +author_name: + type: str + qmark: πŸ™‹ + help: The full name of the project maintainer. + validator: >- + {% if author_name == "" %} + Answer must not be an empty string. + {% endif %} + +author_email: + type: str + qmark: πŸ“§ + help: The email of the project maintainer. + validator: >- + {% if author_email == "" %} + Answer must not be an empty string. + {% endif %} + +license: + type: str + qmark: βš–οΈ + help: The license for the project. + default: BSD-3-Clause + choices: + - BSD-3-Clause + - GPL-3.0-or-later + - Apache-2.0 + - MIT + +github_organization: + type: str + qmark: πŸ™ + help: The GitHub organization or user where the repository will be hosted. + default: sdss + +github_username: + type: str + qmark: πŸ‘€ + help: The GitHub username of the project maintainer. + +push_to_github: + type: bool + qmark: πŸš€ + help: Whether to create a GitHub repository and push the initial commit (requires GitHub CLI). + default: false + +private_repository: + type: bool + qmark: πŸ”’ + help: Create a private GitHub repository? + default: false + when: '{{ push_to_github == true }}' + +sync_project: + type: bool + qmark: πŸ”„ + help: Whether to create a venv and sync the project after creation using uv. + default: true + +keep_answers: + type: bool + qmark: πŸ’Ύ + help: Keep Copier answers to questions for future re-use. + default: false + +_subdirectory: template + +_tasks: + - command: ['{{ _copier_python }}', 'post_copy.py'] diff --git a/pyproject.toml b/pyproject.toml index 73f5436..9e80132 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,6 +21,7 @@ dependencies = [ "sphinx-autobuild>=2021.3.14", "sphinx-copybutton>=0.4.0", "sphinx-autodoc-typehints>=1.23.2", + "copier>=9.11.0", ] [project.urls] diff --git a/template/.github/workflows/lint.yml b/template/.github/workflows/lint.yml new file mode 100644 index 0000000..6230e0d --- /dev/null +++ b/template/.github/workflows/lint.yml @@ -0,0 +1,34 @@ +name: Lint + +on: + push: + paths-ignore: + - 'docs/**' + pull_request: + paths-ignore: + - 'docs/**' + +jobs: + lint: + name: Lint + + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v6 + + - name: Install uv + uses: astral-sh/setup-uv@v7 + with: + enable-cache: true + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: '3.13' + + - name: Lint with ruff + run: | + uv tool install ruff + ruff check src/ tests/ + ruff format --check src/ tests/ diff --git a/template/.github/workflows/release.yml.jinja b/template/.github/workflows/release.yml.jinja new file mode 100644 index 0000000..352b9ea --- /dev/null +++ b/template/.github/workflows/release.yml.jinja @@ -0,0 +1,44 @@ +on: + push: + tags: + - '*' + +name: Create Release + +jobs: + release: + name: Build and publish + + runs-on: ubuntu-24.04 + + permissions: + contents: write + id-token: write + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Create release + uses: taiki-e/create-gh-release-action@v1 + with: + title: {{package_name}} $version + changelog: CHANGELOG.md + token: ${{ '{{ secrets.GITHUB_TOKEN }}' }} + + - name: Install uv + uses: astral-sh/setup-uv@v7 + with: + enable-cache: true + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: '3.13' + + - name: Build source and dist + run: | + uv build + + - name: Publish package distributions to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/template/.github/workflows/test.yml b/template/.github/workflows/test.yml new file mode 100644 index 0000000..24d11b5 --- /dev/null +++ b/template/.github/workflows/test.yml @@ -0,0 +1,48 @@ +name: Test + +on: + push: + paths-ignore: + - 'docs/**' + pull_request: + paths-ignore: + - 'docs/**' + +jobs: + test: + name: Test + + runs-on: ubuntu-24.04 + + strategy: + fail-fast: false + matrix: + python-version: ['3.11', '3.12', '3.13', '3.14'] + + steps: + - uses: actions/checkout@v6 + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.python-version }} + + - name: Install uv + uses: astral-sh/setup-uv@v7 + with: + enable-cache: true + + - name: Install dependencies + run: | + uv sync --no-dev --frozen + + - name: Test with pytest + run: | + uv pip install pytest pytest-mock pytest-asyncio pytest-cov + uv run pytest + + # - name: Upload coverage to Codecov + # uses: codecov/codecov-action@v5 + # with: + # token: ${{ secrets.CODECOV_TOKEN }} + # files: ./coverage.xml diff --git a/template/.gitignore b/template/.gitignore new file mode 100644 index 0000000..f81e90c --- /dev/null +++ b/template/.gitignore @@ -0,0 +1,109 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +.DS_Store + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ +docs/sphinx/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# dotenv +.env + +# virtualenv +.venv +venv/ +ENV/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + +# Vim temporary files +*~ +*.swp +*.swo diff --git a/template/CHANGELOG.md.jinja b/template/CHANGELOG.md.jinja new file mode 100644 index 0000000..ee6f88a --- /dev/null +++ b/template/CHANGELOG.md.jinja @@ -0,0 +1,3 @@ +# Change Log + +This document records the main changes to the `{{project_name}}` code. diff --git a/template/CODEOWNERS.jinja b/template/CODEOWNERS.jinja new file mode 100644 index 0000000..69ff242 --- /dev/null +++ b/template/CODEOWNERS.jinja @@ -0,0 +1,39 @@ +# This is a comment. +# Each line is a file pattern followed by one or more owners. + +# These owners will be the default owners for everything in +# the repo. Unless a later match takes precedence, +# @global-owner1 and @global-owner2 will be requested for +# review when someone opens a pull request. +* @{{github_organization}} +* @{{github_username}} +* {{email}} + +# Order is important; the last matching pattern takes the most +# precedence. When someone opens a pull request that only +# modifies JS files, only @js-owner and not the global +# owner(s) will be requested for a review. +*.js @js-owner + +# You can also use email addresses if you prefer. They'll be +# used to look up users just like we do for commit author +# emails. +*.go docs@example.com + +# In this example, @doctocat owns any files in the build/logs +# directory at the root of the repository and any of its +# subdirectories. +/build/logs/ @doctocat + +# The `docs/*` pattern will match files like +# `docs/getting-started.md` but not further nested files like +# `docs/build-app/troubleshooting.md`. +docs/* docs@example.com + +# In this example, @octocat owns any file in an apps directory +# anywhere in your repository. +apps/ @octocat + +# In this example, @doctocat owns any file in the `/docs` +# directory in the root of your repository. +/docs/ @doctocat diff --git a/template/LICENSE.md b/template/LICENSE.md new file mode 100644 index 0000000..b583b6f --- /dev/null +++ b/template/LICENSE.md @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2017, SDSS +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/template/README.md.jinja b/template/README.md.jinja new file mode 100644 index 0000000..3f65d4f --- /dev/null +++ b/template/README.md.jinja @@ -0,0 +1,3 @@ +# {{ project_name }} + +{{ project_description }} diff --git a/template/docs/sphinx/_static/custom.css b/template/docs/sphinx/_static/custom.css new file mode 100644 index 0000000..9ea0f78 --- /dev/null +++ b/template/docs/sphinx/_static/custom.css @@ -0,0 +1,43 @@ +/* This is the custom CSS for alabaster. The theme does not allow for it to be set differently. */ + +.red { + color: red; +} + +.green { + color: green; +} + +.pink { + color: pink; +} + +.orange { + color: orange; +} + +.purple { + color: purple; +} + +a.reference > em { + font-style: normal !important; +} + +a.reference > code { + font-weight: inherit !important; + color: inherit; + background-color: inherit; +} + +ul, ol { + margin: 0px 0 0px 30px; +} + +a.reference { + border-bottom: 0px; +} + +td.field-body > ul > li > em { + font-style: normal !important; +} diff --git a/template/docs/sphinx/_static/favicon.ico b/template/docs/sphinx/_static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..4ea0b435d71f92beaa86f0ffe832f1ef9e4ef46e GIT binary patch literal 1150 zcmcJONlX(_7{?!r;Xptl31?$8tpzDdDbyC)N-0|dvJ~1WrTcVe3s80uP%v)6C{||GYPkkSM&9k_fgZ zi6fSf6ha6W!4O6c;@A;_?~>yWV8{Qt+1}nJ06>O^uf!P*<`X(fpW<}56K5X!qsKZnwe z#7;ZoMIwoY&(D5YAeQb?m9@}rw83SE7Y6Jeps7X>=H$Vd)7%}I^g;up56y+yG^Hiw zoQzCCNGUJ+-e-2ejJFdO=oXkaxFD>v!)DJ2JnpyzGyTILmB=71mH+Yn)HJJ=%N1fl zc5cL}(SzU90b#up0%{ZZYmMN?K5TTuM)xqx>1bFoH$k`E4Ln}@S1u=&6c#G8g*l?F zeyllfYk^>$nbj;~i}8Mk_%L|Hnkp&Amfc4XAm0xRAwR>Sx^B-H4Hm6je>$Hanl7MM1Bz^K-~ zQ52V*l1QXPC=~5ZHTz&4eXh0l!*Wv>tTgw)YHKe%=^bIef1`T{mgrWPG&=WPlwq@2 zRlyPFiOKTv3dt7aejcU05YpOU5!a6K$*j|&r5Tnzov_|H2#-1j;HJ&{jn)~)%BpHo zN>vr)#@&1DzM%(gMREC;ak>ct=r@RY0>}*R)3m|4f5+Rt{8(}rZim>%!WUVXvTkOyM zv$o4j?^Q!1hS-#l2nkx@LqznjhoA@v2`LHbp~kQ8&o-D5^bmB%XXkg$`JUf7_iRKf z@TsjOeD5UJDx!KK+6xdu%EBodhxMUg3r!eX%)({!CBlS!tkYEhD;mOtH*o18RAvK&t&5=8}CP1BetNz>|` zl>7d*-uA&$XFCSl&O1l1_BQ`s|1g(Zi$0H0%kK8~GxW&o!CS4G%@Nmaj(PA3bm?}- zIq(u^8M&ov(6=fO2#oXjhK7fWk|_4*C!F1y-LVMmN3Z}bub;zt2ABW?NB9NUk0+H* zv$U#ymm{}3q05!>Z((`AW2oN^+k{*Z)(AcW4`wxBUvqd*CPibH5PJd`^cmQT;2s!& z&*x}F{RpfGcz+9ipXO*Z%49_ugC8%&RalNtU$f3-+Oq8^&MDx1K5c9X2BcixSsEgxel0L>{wryL9AS|%tFt1TYy#v5$Fo=`K+HXLkRvR z6pR7evcd`nx;4-r2mF7=_hm-RP$Aic^GJpN&qv0HSd{3;YN9XKiQYF5J*y^qzDN|W bBf3!_(k~N*RuawR5#K=cZXasC0o48kpGIy? literal 0 HcmV?d00001 diff --git a/template/docs/sphinx/_static/sdss_logo.png b/template/docs/sphinx/_static/sdss_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..bc770a558a1f5b86b060c8afdb17f8eb2d36ceba GIT binary patch literal 24816 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%0DR(>~4i=fR(8qHOpCPu8>##%X+3x)o_jX1}f^P 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 z zK+|Pp#KTaIr4kiicY7AAC~!YrE{lD%FJA;dzQZY{&ZW5>ZhD`gp(3=CygM{n+FH4~ zxcs?&t_tq7zQ}v8V-I-Q^i#?f?Y6Zt{n(E&Y5bi-^6IuDbrk}Q8E{$Hq8O!o@>4ws zMQ9uLRj2GLhLA}@R9@y%D%87Em&umEoIe<_rjcOEzSq0TF*sD!^)#I#;*hC+_>xj< zpaRBXi|b3XYA77|B!g|x)HJYJg)&76VwMxPHUk;t&@3oNn}JeZm`WG4#W1!rPoa66 z2WL6oG#iJw>FSaK!kk@o>0hrqqY4)l2ejhrpG5AAomaagJJqwBBYq;H&&%e*4Sran zAD1iI47Xh0W`f^+LFxM>fVTOcrucdohSs-t_s6@{^#v!`_h{eDIO7}|JZ>p_3R=TP z+y_He3$3l2^M3T`5MnO*i|0)(`ClTKj!7Srcs)eJ93b;eCCCQc zzpLY;@WRVb{>l|Y`*`1e6Akp9Ip6eo9{)h9rf2&g10Pw+oNBA9t4D@#YiVeBB!=xN z6%9_NwA2+XcW)uX;>2Jv%}&(HDSLy=NL~5FvL=p%Sl|CZ>(|qr?sE6(>YGQ%<)i`t8CF3jxg=$fS}FxzPAOgds^L>7;{K$t2{?ScO3#=b)ysvQ|~{g=f#*UtN7I ztGc44f46H}adm<0f2N+5C5rmU1rA!VxubhA#}1B%WHV#` zyd(8Fv*NQFZST^8ub;rTO~;~g^UbYU>TZ<;M^RNNU%F76wWV=PLU%^(>M35Np-N|B zKuM#rKGOVc!la3$0`n){LV|*7>N>QUf`QN2qWQtd#diAVr`3@9TsG5$YE9CBdm_-> zY>i0zSCMtjAAaP=wphR+x2gxLD39>m-7CdJ^g7%F+TxlJpD(eyUbli{(Ox(@HffJT#>63ovmd)8h^R*8v)IN#8Z$25XHD*VUFw< z|Nn+ftzLsiZvQd%5OA1X4X#WCOhyg8f8_ULhp~Omb~Wl)oVei^j)833X$90$HO5vt z8agz)sr}jhutR>%zaGE>N#`8lN2q~1zm8ko$;m*1Oxmmn_xq(aLl&)K#5IT9d9SMNIQeX&?uA{(TcbhL&R+O) zhVUcYsGUSxfxbWK?s$MH>woc4rWy)lZ64Q6P0e3hfpjWU7GiQOBZ_yO%<%6w-B%Hgq!tv6ia!=IyfC`~+?+Nr1& zJ>D0Pj}Ygny}jY;USW64=rT^QqrpE1CnrH4=pCJ%2mzviZs%x-LKT#TGJoYe0|ri-Lo z0E5H{cR5+>gS-updzcWAz9ohkjYFySg-eh0w?X54+rmb}j0wNSq~ua_ZOb9${(a1D zZh_8kL<=nmvEhQ}@!8|$_HDO_(m`AtEXd8QBwn`Qos_oHzvE`aTIP7(4+V!0B>
  • {JARp#HdQy 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 M6>a4@MeDHt0r$>g(*OVf literal 0 HcmV?d00001 diff --git a/template/docs/sphinx/_static/sdssv_logo_small.png b/template/docs/sphinx/_static/sdssv_logo_small.png new file mode 100644 index 0000000000000000000000000000000000000000..ea25558a41da32c616220a56e1f55936834564f3 GIT binary patch literal 7404 zcmZ{J1z40_^Y<>@oze{|yMS~oji9uEbk`EQuyjc&NJ=A}QqmxbG=g*^-3<}~Qc8S_ zkMH~Vf4=8Ed!2LUo|)gwoO5RGJ$r4Ky6QuGoI5xG003V}QBD&%OWk%X4CGh>bzVSD zKo`x2GJx_y+HK^+XDeMLYZVp1T_lYKzyy*2P;XU`9{}(U0R0yY0GI=5{!7~dIe+V* zAa!^F$Pqw}>SMOxY;^wJVj4`Zs;+fYndC6**x$DeAcZ z0Jx;L9SBHGrvd=bP@!77uDUA9q84yRkeMai+zRCB=yZz$hBeBdi#a@q&1mAvlbTjN%AOYf()(h2L=GlLWJ^ ztE-bJ80_KU0rGeNf+K9eydokZU>-g&A0IbTgWJUm=4$524Rc}n%gBH1$XU5qAfQgJ zP&kb7)~=a3+|5;jnfcbyf7|ak9i9H`2e^9rQ z{|R%2TK^B&t>iD*ug&-?MsehhimJdZq1IkTh#)%wrDii7{5^Y;pW zp=A+Px9On;hdV(2EnEJ=|Ecv411iX)vov!x`#%9Z;ML;e6BXbS*OrRxlUji9iJT#lin7_*bCb{{sFY_$N>n?f^$TaWb>8g7E(K^#|(@?c049 zm4!PxA*@_}#U>yQ{{MLY)YsLta)CRz-DVd=h>r)^z`VEPZ|I-me?tF8YQvze5We4# zf3W|FQbRzkkcs}wA#y#x0{oNrPkp_=?fqMTe~N!Y#lg2_@<-YHRg=HC$fAVcAdmS! z1rEW9ncDUQ04OV!v6EqDWzEMD z{!uBJG2(1&tzhH3+P}&90D{LRVR~1dg!K`rMtEcZa69LWOs1E6bN8&m#RVjk7y#e! zJN7F*nDu!7ZW7|N_ij?(XRmL{=tEy%1MRucW&mNcKVIB-cyqMa_2njyru0m(WwX)U zn|;Fu2Ha-KFcy5-yYdKGJE7s$Ed1m4Y6a&URf@a=%qs}HC(8K*$aGE=dE6;y%pD2M37f6&fF!Vu{p@pLxfd`T zr_~sJN@$1ymrG$?savk2;sM`37GOtHnX^sr@GKZvv@t^*C44L}rzMSFm^OWo%BGE7 zJv*%*c`!9tQ42h9Q41D1ji2kL0a+;SfLOc)Yw4sQWIYS&EoG%6GBbCmX=3R+$e$7Y z%u$;Q81$#qbUrwUuZ#R58PN5@YA_IXEZl=mTuyQ^8~+G$X$dy>PP5x>~cjlp?OjnvrvU6-rgC zU7c?l(^K!L4NlNWH$($2>!rChLc{W0w$VC0>8^nuA9LeO;S<#TpY#pH@mV|Ta!p}o z-pg~;Oyt1%M!XFv-NZ!I-1PNLM^DH5J9M$-s;|FI$STBhaLEvCfXF7Jd|rmBUe4aH zjR5Lu-4is741MPG2sjrD1syZAnDO}giZMUxC1XD@e`My$Px=U)9bU>Rj^_qoIF(-<(Cmg-+YhP~2xUU+HbFAm}a+ zG~3=^c6zOB0ZZxv?aN^sk2AhRB)R#ajt#zHBz_-G^6Qrh21HvuLB|NiN#2AAzn$I) z3S>%n35xq5{Fg&zU-)A-H%#wd?0o222w-Tx%;6n$X6N1@k;J@5%&jFD zp||@6`#}vyDQD!&GnYYwWc`GI_V)IcfKUDi0?J)Xn|dW_@`BJ4cHICLZ@rcDxiO3Y zOzNZ)v2F(fDt=Tb=Q%%CgHY02ln8S4$$7t_j)8v9A?p~sQ5ldwKP37@TRCQ*{W zghtZ|{0WBQWO?F^+xIOE-{Xxkgq77g6*I4wsumDyY;8cgGB7jTjnl0t?kF!hAj4~G zx>8w`zQ6nk)mDm`d-SC+XJC*g*DOe-9Es_RQ# zEJ0htmmA<7gh{8DXQD^E6LPUUZ8};e&5>^wO)IkV1v*yXijRk9njt#>X`)n*REaJ& z)-cc-GJjVj$IJG70e!uaMsYP-~_FQ6gRhZIstMVzWqH$h#;oJa(JVbF+e;)%ScT_%fJuFR_+dHr4&ZL-1Y!e z`-+3tcb&*Emm)`X^9)DROn-SU881$p)K%P3=j#N0hIf=I_scVBwO( zA|q{WOCnY5*hs@QJ)ce23w4v|sP6hnt4qTKO7KwDSYiH}(aZ(M>Zeh6saQ6U?zduR zuV>?SOpz>1>V+?ubvOolX_NJ-YJlIfF!s?YMY$<>{gtO*Nj!Wv6{f&}d{Ig;p3a#& zJ5+~;V!kae|19osnJM8@Tf^G3@`_3}yo4==yrDY%etUILy$$-)n++m2`l2ar5e7=N z>N|MWN3?J!pQ||ZCz5Qb34AfvsL(I;m-u1CdMu+j8_!r+-I!T-m_OH|$Eka2?Dq3>&TK4M2CypG9V|#tmj;ArYiRU< zOq$!vjhi;yPIlH!G%X$(_Y){@IYp#k0a3MXAW)i&4Fc|~qd`nKNgAXue{xcdBby7Dq0 zVXhuin_aPb2JM^)&JL-$Tgw#}4~z+T3t;0zB-MGUsi|4>rA&2%t?D^CX1IP^k|y!5 zYh?UEX6|>KMuI4QJe5;+Y*W5-YzDK;;3-mD3RV-NXt&Oqn{6*7=nfpayz^kzHK;mhUr?hVdY_s4MU^B%4>v-LjEYGR zQ>kjk1U|ECDW$GH?6tdqUo+jou9Diii?u}D+F%ikfp01V8}BGJX}RXI`>H<4MH(@q zu&&cO(Cf%Hq>vw)zd0zzk%spwAnp@i>pN|-ulu5Abn!`&XJ=F`;t=!gtM0H<)BHn4 zo-8Gjm9R{il@^(d_GSxGn=)2s8?F}`X))w1_@|WyN$ND>U3(;yEzrlJRoFFIQQg=~ zzI5q$TZ=6%U;6s)y{WDaPZ_XQVD^>*&0O=Syt^g1~EX7%IxGpI}Qq}XGx(8hK8V1F5PzFtGO+V;1s$uyu z%|M2od*Jj5kKbH5XNy7>1_r1pK!*F&#@JVP;{j(xLeP}tj(1n!mvc(e*L&_XT!tLN z)Kc72duPustHxC$S~fGIhtVyg>7=@V;Z=o1y^F&`N?g=zUi^?!oh~R7L(!wpU`od9 zM`zawLG@;@*Xfpw9>!_4QD8M3Y8mS47`E50M=`64)Dx2_Z(H3v_{KOMpqDowZ{kNF z8t(Z}myi~F@t7Ee1vYLIr!tg%6&F3pPpQl%G>aWY#pANk|LEm)nEhmV)k2exG^OuX zIo5);P0H${qh67ipyXl;y=UXk(wmai9R~PG^cf;D4ubaxb8*ts&iXUyYh$hyr^w8L z;4!&W%9AVY53Y~vQ?@f!t@F>>Lu_Q{ydG+6FHzgQmuQDs_I@jQ4vA8vbe@-jpiQQO z%8eR}-m+~yB!)HR5u+9z78hn3`mS|rY<&IN6-_Vk83%Wg=NxNho)H8Jp@aCoE;Fp( zxr(9@8uelu`=Gp{Ns>4VFqyixI9#4S#^MlpaM@lQzWT|M{nc|cZTnTU2P?)mg`%Iq zSg;SJMR%ivc$QjiCklaGCF}T-3e$2QTY*7pQLl8RtrJeDJblqSE*e5ItyA)y5Y7Cy zp97GMtt*;N(%8r^105Z`I+lf@Gf2|n>c@!%MsT3SQTM0aoKS_=%{SLS9ZgZ@M|hV< zBpLUU^EDh!LTRefiaiav!cz2xz50?^#eygoC#d=}T3>eY;^9v0V|`coOwr@iJn)VV z{BYgWG?*TxX7{t?6G^h7a3?gbsU+#j!`6|Bg-D=9SMLBPVTqIWi9@b%ghaEvb?qh!zXumb8d=zJR zybjd^dXOs?nIj&v#N+IK_n?mHkXpJSE3j;A+|Ux*omb%v3)y`1q`@q5ZU-}}Cenp% zR!ItZJKi*%N-Gkoi5So>Y&-`7;RA%Ubld*P*N6}~x##v+)6;LKBB{ry>bub%zM{9H z6FsjiHxkPVfzSv!uXI?r>R5bwU?O)Pi};Pf!bIirF6;eI@I87vV+93=D1~#uXPn=F zH%lA5t-42;rX(%we22>^E=)K^DKa2&)(-4O!=&@zdq;U{{PBQx;3nBzrwKK`Z8l(tax-HES*4iqiB1tQ0Okr6y4iA1c94aR)A-TZBkr;0k{wM`deuoM#aUU4_wU?uAcsA3mu$h&&{*!8pWBHF z(YN5FH<@5u7=A;oGI$dd5w~&J*-9M0>sbuLi4m_+p^t3@?bspXS@rSpX%X}LF@9`` zk7YagFp{b*JVL0t$;aPx4YcTCf|VvI8ORmBbM=W(@)GqhnCp33_&0ZMdFPpCapDq! ziw)H)`q8^VY@;u_%-kTh zs%7w#{M}1I?l0aVv*5;EA2(&D<)&;d#%Dz0oIGl9*b~ex#RQ9|l*n7q=_<1RQa(pA z^|e#=x+;z42j&ABhLS)=fq5jYAKkuU_z^ozFSZ;XR}x*!04`f+(}1CyXPhBBj%6D! zsru3@+TAD*xORaKsgkc{tY5kVN88R`E04~2zbzAc`Ua&Y?b7L}x9F`Ln3p+^@-*an zXt=u&AiJmrj{E}BeLe}pAmTGz5)yKpxrEu;`UkhPY`9j{*5d8WMD`^Va60Qx#V`dE zE7tcm|AZyG7pL-BX_hxMY(@xcQic%#%iF-8=9)vy115$i2#s<-d{^xbU#SD7PBGd4CKT?>|tvw)R3W$NrelXPXTVaSOY+eq9>hGZ#zj4|nQju%b6A0qW!J5x<=NEo9 zn>kEglM`vQDlaeZva@4XQwP5ZIoTcyeeoR4zA2v}iTkk`E+qu_bGJUt)$Xi^lm!`U zXbI(#pk%Pcp@244_vvHp4W_$KB+*$gg!O07$_9%71F@)SBTEeL=Zb?YpR2Fr&NXtFjL(SIO({n}szT)cZ1%FJh zcdUJ2uP^7;Pw?{I9C~yBGSronMq)}zQf0PY(8qJAA@;o$6xctdp~NM#(@j>GbjkN( zSy7j4V}y%jihGef-CsbN+?R+MS~u1FJYM|7$O4x(ytFXa_D0&1N(_%dI-Z~~WxOR% zLsi4PP4LrrS&jbrkJ6R;NtzR(;>-IOMBGz8iy2}b)|n8$4XC&3*U>k)vrRs)+yj}L z0@B!mN*+#)si}RQZ<`g7pyfDSPd2GCZt||ql-P#LyS`n$7o)SvZ9ciyGvI+&p*%W0 z8cDAskG6_2O^r~a2$X9yRveWlC4HDoE|-OhuR<-#VW0P{hB|v}p)zMH>f^^B9;f?P zp_HA33Q^v3UT8ZzJ5(Z?BO@-a)6ytDjD$#M*-9tD=0DmUVj`-ydZRY$?G)AS#^|7I zDsK*Efbkh1bH(*1A_jfioKf@=A5jw=KWWzsC|8!8l+PaIoCoAi9Y$BbrwQ|4Z2rI? z5b(v$BI{XdDK8M@9^6w~wYFxpd$E}{MqzAV(5Gk@9xf;q+Rv(Bo0s$0Vd;zDTBm6@ z0nZ^(bYjpm$3l&bmlk*08gkqlPOBqtxT^QggCFKY{OvDpxKM3L5P^sJ6oGGDaUi|o zzUMr<<%D^r_hzO@)gs$2Bs)2~y{|9PlVXT4(PySC*h204lFCvEa(-g+hFpe+hu;-6 zYZuHGM6J3byudzWrpR0o^?974$O2zMf#`$)w7;F`Xx8}Ef^ zjB&-gN;;*4ii(N?-3E_?=q>HV@edz9oGYLi6km=}We+{o)Ep)BclJS7a|lZlbc}Us z7^lcPix0b8i)Tar7T3k?ijQVI_ByhpP80Kp9;@CupYlq|%q-TUj3XFj_-LGCQD>>d z7eui`^UWWCD1O0#qhfnxG~Lxl4a>0dF-x{B6+V9cgxKni!<=N! zJvW?%0&Aw17+gA>dhScDK%U`9`wORx+6~wftd?xklN{vbQ+2M{&xZv*6gDNZZ1Nf4 z2is*#FT$@9O!FglmC6FQ%&n=Y#wRBij@b=^o@#4X_4hk$?vL^^8fh3Cw|$PLdr=K8 zUlp2~uG#FKFK_U@*b&Xs2=5$xzx8eFSZLs89na}1AU&Oy+8X}jAp`d_!te^r!D{U0 zAcrbl>h0&1mD__XQp!y0p6B0)&k57EcA_SCjdhkPgwp0$O^;w7Mq%)an?ztaLrPqn zOdA ig1Pn9UqhMjw-zk>B6gHf9_-sc?3CnH<;rDDgZ>{$$vP+i literal 0 HcmV?d00001 diff --git a/template/docs/sphinx/changelog.md b/template/docs/sphinx/changelog.md new file mode 100644 index 0000000..ea758b9 --- /dev/null +++ b/template/docs/sphinx/changelog.md @@ -0,0 +1,4 @@ +(template-changelog)= + +```{include} ../../CHANGELOG.md +``` diff --git a/template/docs/sphinx/conf.py.jinja b/template/docs/sphinx/conf.py.jinja new file mode 100644 index 0000000..bbd1629 --- /dev/null +++ b/template/docs/sphinx/conf.py.jinja @@ -0,0 +1,143 @@ +from {{ package_name }} import __version__ +import os + + +# Are we building in RTD? +on_rtd = os.environ.get("READTHEDOCS") == "True" + + +# matplotlib.use('agg') + + +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.napoleon", + "sphinx.ext.autosummary", + "sphinx_autodoc_typehints", + "sphinx.ext.todo", + "sphinx.ext.viewcode", + "sphinx.ext.mathjax", + "sphinx.ext.intersphinx", + "myst_parser", + "sphinx_copybutton", +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +pygments_style = "lovelace" +pygments_dark_style = "one-dark" + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = ".rst" + +source_parsers = { + # '.md': 'recommonmark.parser.CommonMarkParser', +} + +# The master toctree document. +master_doc = "index" + +# General information about the project. +project = "python_template" +copyright = "{0}, {1}".format("2018-", "SDSS Collaboration") +author = "SDSS Collaboration" + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. + +# The full version, including alpha/beta/rc tags. +release = __version__ + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = "en" + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = [ + "_build", + "Thumbs.db", + ".DS_Store", +] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +default_role = "obj" + +# If true, '()' will be appended to :func: etc. cross-reference text. +# add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +# show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = "sphinx" + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +# keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + +# Intersphinx mappings +intersphinx_mapping = {} + +autodoc_mock_imports = ["_tkinter"] +autodoc_member_order = "groupwise" +autodoc_default_options = {"members": None, "show-inheritance": None} +# autodoc_typehints = "description" + +simplify_optional_unions = True +typehints_use_signature_return = True + +# napoleon_use_rtype = False +# napoleon_use_ivar = True + +copybutton_prompt_text = r">>> |\$ " +copybutton_prompt_is_regexp = True + +rst_epilog = f""" +.. |{{package_name}}_version| replace:: {release} +.. default-role:: py:obj +""" + + +# -- 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 = "furo" +html_title = "{{ project_name }} documentation" +html_logo = "_static/sdssv_logo.png" +html_favicon = "./_static/favicon.ico" +html_theme_options = { + "source_repository": "https://github.com/{{ github_organization }}/{{ project_name }}/", + "source_branch": "main", + "source_directory": "docs/sphinx", +} + +# 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". + +# See https://github.com/rtfd/readthedocs.org/issues/1776 for why we do this +if on_rtd: + html_static_path = [] +else: + html_static_path = ["_static"] diff --git a/template/docs/sphinx/index.rst.jinja b/template/docs/sphinx/index.rst.jinja new file mode 100644 index 0000000..ccf6a0d --- /dev/null +++ b/template/docs/sphinx/index.rst.jinja @@ -0,0 +1,27 @@ + +{{ project_name }} +{{ '=' * project_name|length }} + +This is the documentation for the ``{{ package_name }}`` Python package. + +Contents +-------- + +.. toctree:: + :maxdepth: 2 + + Changelog + + +Links +----- + +* `Repository `__ +* `Issue tracking `__ + + +Indices and tables +------------------ + +* :ref:`genindex` +* :ref:`modindex` diff --git a/template/docs/sphinx/requirements.txt b/template/docs/sphinx/requirements.txt new file mode 100644 index 0000000..b621cbc --- /dev/null +++ b/template/docs/sphinx/requirements.txt @@ -0,0 +1,7 @@ +Sphinx>=8.0.0 +furo>=2025.12.19 +myst-parser>=2.0.0 +nox>=2025.11.12 +sphinx-autobuild>=2021.3.14 +sphinx-copybutton>=0.4.0 +sphinx-autodoc-typehints>=1.23.2 diff --git a/template/noxfile.py b/template/noxfile.py new file mode 100644 index 0000000..2c73640 --- /dev/null +++ b/template/noxfile.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# @Author: JosΓ© SΓ‘nchez-Gallego (gallegoj@uw.edu) +# @Date: 2021-06-20 +# @Filename: noxfile.py +# @License: BSD 3-clause (http://www.opensource.org/licenses/BSD-3-Clause) + +import contextlib +import os +import tempfile + +import nox + + +@contextlib.contextmanager +def cd(path): + CWD = os.getcwd() + + os.chdir(path) + + try: + yield + finally: + os.chdir(CWD) + + +@nox.session(name="docs-live", reuse_venv=True) +def docs_live(session): + if session.posargs: + docs_dir = session.posargs[0] + else: + docs_dir = "." + + with cd(os.path.join(os.path.dirname(__file__), "docs/sphinx")): + with tempfile.TemporaryDirectory() as destination: + session.run( + "sphinx-autobuild", + # for sphinx-autobuild + "--port=0", + "--open-browser", + # for sphinx + "-b=dirhtml", + "-a", + "--watch=../../src", + docs_dir, + destination, + external=True, + ) diff --git a/template/post_copy.py b/template/post_copy.py new file mode 100644 index 0000000..1ef747c --- /dev/null +++ b/template/post_copy.py @@ -0,0 +1,207 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# @Author: JosΓ© SΓ‘nchez-Gallego (gallegoj@uw.edu) +# @Date: 2025-12-29 +# @Filename: tasks.py +# @License: BSD 3-clause (http://www.opensource.org/licenses/BSD-3-Clause) + +from __future__ import annotations + +import pathlib +import subprocess + +from typing import Any + +import colorama +import yaml + + +colorama.init() + + +def get_binary_path(binary: str) -> pathlib.Path | None: + """Returns the path to a binary if it exists in PATH.""" + + result = subprocess.run( + ["which", binary], + capture_output=True, + text=True, + ) + + if result.returncode == 0: + return pathlib.Path(result.stdout.strip()) + + return None + + +def delete_copier_files(keep_answers: bool = False) -> None: + """Deletes the post_copy.py file.""" + + file_path = pathlib.Path(__file__).resolve() + if file_path.exists(): + file_path.unlink(missing_ok=True) + print(colorama.Fore.WHITE + " > Deleted post_copy.py file.") + + answers_path = pathlib.Path.cwd() / ".copier-answers.yml" + if not keep_answers and answers_path.exists(): + answers_path.unlink(missing_ok=True) + print(colorama.Fore.WHITE + " > Deleted .copier-answers.yml file.") + + +def run_command( + command: list[str] | str, + cwd: pathlib.Path | None = None, + success_message: str | None = None, + error_message: str | None = None, + shell: bool = False, + exit_on_error: bool = False, + keep_answers: bool = False, +) -> bool: + """Runs a command in a subprocess.""" + + if shell: + command = " ".join(command) if isinstance(command, list) else command + + cwd = cwd or pathlib.Path.cwd() + + result = subprocess.run( + command, + capture_output=True, + text=True, + cwd=cwd, + shell=shell, + ) + + if result.returncode != 0: + if error_message: + print(colorama.Fore.RED + f" ! {error_message}") + print(colorama.Fore.RED + result.stderr) + + if exit_on_error: + delete_copier_files(keep_answers=keep_answers) + exit(1) + + return False + else: + if success_message: + print(colorama.Fore.WHITE + f" > {success_message}") + return True + + +def post_copy(): + """Post copy tasks.""" + + # Get the answers + answer_file = pathlib.Path.cwd() / ".copier-answers.yml" + answers: dict[str, Any] = {} + if answer_file.exists(): + answers = yaml.safe_load(answer_file.read_text()) + print(colorama.Fore.WHITE + " > Parsed Copier answers file.") + else: + print(colorama.Fore.YELLOW + " ! No Copier answers file found.") + delete_copier_files() + return + + keep_answers = answers.get("keep_answers", False) + project_name = answers.get("project_name", "").strip() + + if not project_name: + print(colorama.Fore.RED + " ! No project name found in answers.") + delete_copier_files(keep_answers=keep_answers) + return + + if answers.get("sync_project", True): + uv_path = get_binary_path("uv") + if not uv_path: + print( + colorama.Fore.YELLOW + + " ! 'uv' binary not found in PATH. Skipping project sync." + ) + else: + cwd = pathlib.Path.cwd().resolve() + run_command( + [ + "UV_ACTIVE=0", + f"UV_PROJECT_ENVIRONMENT={cwd!s}/.venv", + f"VIRTUAL_ENV={cwd!s}/.venv", + "UV_PYTHON=''", + str(uv_path), + "sync", + "--all-groups", + "--all-extras", + ], + shell=True, + success_message="Project synced with 'uv'.", + error_message="Failed to sync project with 'uv'.", + ) + + git_path = get_binary_path("git") + if not git_path: + print(colorama.Fore.YELLOW + " ! 'git' binary not found in PATH.") + else: + result = run_command( + [str(git_path), "init"], + success_message="Initialized git repository.", + error_message="Failed to initialize git repository.", + ) + + github_organization = answers.get("github_organization", "").strip() + push_to_github = answers.get("push_to_github", False) + private = answers.get("private_repository", False) + + if result and push_to_github and github_organization: + github_repo_url = f"git@github.com:{github_organization}/{project_name}.git" + run_command( + [str(git_path), "remote", "add", "origin", github_repo_url], + success_message=f"Added GitHub remote '{github_repo_url}'.", + error_message="Failed to add GitHub remote.", + exit_on_error=True, + keep_answers=keep_answers, + ) + + run_command( + [str(git_path), "add", "."], + success_message="Staged all files for initial commit.", + error_message="Failed to stage files for initial commit.", + exit_on_error=True, + keep_answers=keep_answers, + ) + + run_command( + [str(git_path), "commit", "-m", "Initial commit"], + success_message="Created initial commit.", + error_message="Failed to create initial commit.", + exit_on_error=True, + keep_answers=keep_answers, + ) + + gh_path = get_binary_path("gh") + if gh_path: + if run_command( + [ + str(gh_path), + "repo", + "create", + f"{github_organization}/{project_name}", + "--private" if private else "--public", + ], + success_message="Created GitHub repository.", + error_message="Failed to create GitHub repository.", + ): + run_command( + [str(git_path), "push", "-u", "origin", "main"], + success_message="Pushed initial commit to GitHub.", + error_message="Failed to push initial commit to GitHub.", + ) + else: + print( + colorama.Fore.YELLOW + + " ! 'gh' binary not found. Not creating GitHub repository." + ) + + delete_copier_files(keep_answers=keep_answers) + + +if __name__ == "__main__": + post_copy() diff --git a/template/pyproject.toml.jinja b/template/pyproject.toml.jinja new file mode 100644 index 0000000..d0d20a0 --- /dev/null +++ b/template/pyproject.toml.jinja @@ -0,0 +1,68 @@ +[project] +name = "{{package_name}}" +version = "0.1.0a1" +description = "{{ project_description }}" +authors = [ + { name = "{{ author_name }}", email = "{{ author_email }}" }, +] +license = { text = "{{ license }}" } +readme = "README.md" +requires-python = ">=3.10,<4" + +dependencies = [ + "sdsstools>=1.9.2", +] + +[dependency-groups] +dev = [ + "ipython>=8.0.0", + "ipdb>=0.12.3", + "ruff>=0.14.10", +] +docs = [ + "furo>=2025.12.19", + "myst-parser>=2.0.0", + "nox>=2025.11.12", + "sphinx-autobuild>=2021.3.14", + "sphinx-copybutton>=0.4.0", + "sphinx-autodoc-typehints>=1.23.2", +] +test = [ + "pytest>=5.2.2", + "pytest-asyncio>=0.10.0", + "pytest-cov>=2.8.1", + "pytest-mock>=1.13.0", + "pytest-sugar>=0.9.2", + "coverage[toml]>=5.0" +] + +[project.urls] +Homepage = "https://github.com/{{github_organization}}/{{project_name}}" +Repository = "https://github.com/{{github_organization}}/{{project_name}}" + +[tool.uv] +package = true + +[tool.ruff] +line-length = 88 +target-version = 'py313' + +[tool.ruff.lint] +select = ["E", "F", "I"] +unfixable = ["F841"] + +[tool.ruff.lint.per-file-ignores] +"__init__.py" = ["F403", "E402", "F401"] + +[tool.ruff.lint.isort] +known-first-party = ["{{package_name}}"] +lines-after-imports = 2 +section-order = ["future", "standard-library", "typing", "third-party", "sdss", "first-party", "local-folder"] + +[tool.ruff.lint.isort.sections] +typing = ["typing"] +sdss = ["sdsstools"] + +[build-system] +requires = ["uv_build>=0.9.20,<0.10.0"] +build-backend = "uv_build" diff --git a/template/readthedocs.yml b/template/readthedocs.yml new file mode 100644 index 0000000..a2f370f --- /dev/null +++ b/template/readthedocs.yml @@ -0,0 +1,15 @@ +version: 2 + +build: + os: ubuntu-24.04 + tools: + python: '3.13' + +sphinx: + configuration: docs/sphinx/conf.py + +python: + install: + - requirements: docs/sphinx/requirements.txt + - method: pip + path: . diff --git a/template/src/{{package_name}}/__init__.py.jinja b/template/src/{{package_name}}/__init__.py.jinja new file mode 100644 index 0000000..0c0be36 --- /dev/null +++ b/template/src/{{package_name}}/__init__.py.jinja @@ -0,0 +1,13 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from __future__ import annotations + +from sdsstools import get_package_version + + +# pip package name +NAME = "{{ package_name }}" + +# package name should be pip package name +__version__ = get_package_version(path=__file__, package_name=NAME) diff --git a/template/tests/__init__.py b/template/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/template/tests/conftest.py b/template/tests/conftest.py new file mode 100644 index 0000000..e69de29 diff --git a/template/{{_copier_conf.answers_file}}.jinja b/template/{{_copier_conf.answers_file}}.jinja new file mode 100644 index 0000000..a96840d --- /dev/null +++ b/template/{{_copier_conf.answers_file}}.jinja @@ -0,0 +1,2 @@ +# Changes here will be overwritten by Copier +{{ _copier_answers|to_nice_yaml -}} diff --git a/uv.lock b/uv.lock index ecfd09f..a402552 100644 --- a/uv.lock +++ b/uv.lock @@ -27,6 +27,15 @@ 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.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + [[package]] name = "anyio" version = "4.12.0" @@ -221,6 +230,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6d/c1/e419ef3723a074172b68aaa89c9f3de486ed4c2399e2dbd8113a4fdcaf9e/colorlog-6.10.1-py3-none-any.whl", hash = "sha256:2d7e8348291948af66122cff006c9f8da6255d224e7cf8e37d8de2df3bad8c9c", size = 11743, upload-time = "2025-10-16T16:14:10.512Z" }, ] +[[package]] +name = "copier" +version = "9.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama" }, + { name = "dunamai" }, + { name = "funcy" }, + { name = "jinja2" }, + { name = "jinja2-ansible-filters" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "platformdirs" }, + { name = "plumbum" }, + { name = "pydantic" }, + { name = "pygments" }, + { name = "pyyaml" }, + { name = "questionary" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/61/226642b1efad2a39008ee5b913cd82a6f22a564b652e8f0645488a27a2e2/copier-9.11.0.tar.gz", hash = "sha256:e73d6989fa140b621a5c571984c46122704086a9caa84a6e07699a5234d297ab", size = 592030, upload-time = "2025-11-20T21:08:01.419Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/ee/657b24e9b2406f572db273e943237c39c86da7d06ac7bc0686cacea1f59d/copier-9.11.0-py3-none-any.whl", hash = "sha256:628adac090f7b333bb64bf5cab03456b99971a77e4d5b2b979e30b8451cbda9d", size = 56432, upload-time = "2025-11-20T21:07:59.618Z" }, +] + [[package]] name = "decorator" version = "5.2.1" @@ -261,6 +295,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408, upload-time = "2024-04-23T18:57:14.835Z" }, ] +[[package]] +name = "dunamai" +version = "1.25.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f1/2f/194d9a34c4d831c6563d2d990720850f0baef9ab60cb4ad8ae0eff6acd34/dunamai-1.25.0.tar.gz", hash = "sha256:a7f8360ea286d3dbaf0b6a1473f9253280ac93d619836ad4514facb70c0719d1", size = 46155, upload-time = "2025-07-04T19:25:56.082Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/41/04e2a649058b0713b00d6c9bd22da35618bb157289e05d068e51fddf8d7e/dunamai-1.25.0-py3-none-any.whl", hash = "sha256:7f9dc687dd3256e613b6cc978d9daabfd2bb5deb8adc541fc135ee423ffa98ab", size = 27022, upload-time = "2025-07-04T19:25:54.863Z" }, +] + [[package]] name = "exceptiongroup" version = "1.3.1" @@ -291,6 +337,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e3/7f/a1a97644e39e7316d850784c642093c99df1290a460df4ede27659056834/filelock-3.20.1-py3-none-any.whl", hash = "sha256:15d9e9a67306188a44baa72f569d2bfd803076269365fdea0934385da4dc361a", size = 16666, upload-time = "2025-12-15T23:54:26.874Z" }, ] +[[package]] +name = "funcy" +version = "2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/70/b8/c6081521ff70afdff55cd9512b2220bbf4fa88804dae51d1b57b4b58ef32/funcy-2.0.tar.gz", hash = "sha256:3963315d59d41c6f30c04bc910e10ab50a3ac4a225868bfa96feed133df075cb", size = 537931, upload-time = "2023-03-28T06:22:46.764Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d5/08/c2409cb01d5368dcfedcbaffa7d044cc8957d57a9d0855244a5eb4709d30/funcy-2.0-py2.py3-none-any.whl", hash = "sha256:53df23c8bb1651b12f095df764bfb057935d49537a56de211b098f4c79614bb0", size = 30891, upload-time = "2023-03-28T06:22:42.576Z" }, +] + [[package]] name = "furo" version = "2025.12.19" @@ -445,6 +500,19 @@ 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 = "jinja2-ansible-filters" +version = "1.3.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jinja2" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1a/27/fa186af4b246eb869ffca8ffa42d92b05abaec08c99329e74d88b2c46ec7/jinja2-ansible-filters-1.3.2.tar.gz", hash = "sha256:07c10cf44d7073f4f01102ca12d9a2dc31b41d47e4c61ed92ef6a6d2669b356b", size = 16945, upload-time = "2022-06-30T14:08:50.775Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/72/b9/313e8f2f2e9517ae050a692ae7b3e4b3f17cc5e6dfea0db51fe14e586580/jinja2_ansible_filters-1.3.2-py3-none-any.whl", hash = "sha256:e1082f5564917649c76fed239117820610516ec10f87735d0338688800a55b34", size = 18975, upload-time = "2022-06-30T14:08:49.571Z" }, +] + [[package]] name = "markdown-it-py" version = "3.0.0" @@ -630,6 +698,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668, upload-time = "2025-08-23T15:15:25.663Z" }, ] +[[package]] +name = "pathspec" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, +] + [[package]] name = "pexpect" version = "4.9.0" @@ -651,6 +728,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" }, ] +[[package]] +name = "plumbum" +version = "1.10.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pywin32", marker = "platform_python_implementation != 'PyPy' and sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/dc/c8/11a5f792704b70f071a3dbc329105a98e9cc8d25daaf09f733c44eb0ef8e/plumbum-1.10.0.tar.gz", hash = "sha256:f8cbf0ecec0b73ff4e349398b65112a9e3f9300e7dc019001217dcc148d5c97c", size = 320039, upload-time = "2025-10-31T05:02:48.697Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/ad/45312df6b63ba64ea35b8d8f5f0c577aac16e6b416eafe8e1cb34e03f9a7/plumbum-1.10.0-py3-none-any.whl", hash = "sha256:9583d737ac901c474d99d030e4d5eec4c4e6d2d7417b1cf49728cf3be34f6dc8", size = 127383, upload-time = "2025-10-31T05:02:47.002Z" }, +] + [[package]] name = "prompt-toolkit" version = "3.0.52" @@ -681,6 +770,139 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, ] +[[package]] +name = "pydantic" +version = "2.12.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591, upload-time = "2025-11-26T15:11:46.471Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload-time = "2025-11-26T15:11:44.605Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.41.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/90/32c9941e728d564b411d574d8ee0cf09b12ec978cb22b294995bae5549a5/pydantic_core-2.41.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146", size = 2107298, upload-time = "2025-11-04T13:39:04.116Z" }, + { url = "https://files.pythonhosted.org/packages/fb/a8/61c96a77fe28993d9a6fb0f4127e05430a267b235a124545d79fea46dd65/pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2", size = 1901475, upload-time = "2025-11-04T13:39:06.055Z" }, + { url = "https://files.pythonhosted.org/packages/5d/b6/338abf60225acc18cdc08b4faef592d0310923d19a87fba1faf05af5346e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5921a4d3ca3aee735d9fd163808f5e8dd6c6972101e4adbda9a4667908849b97", size = 1918815, upload-time = "2025-11-04T13:39:10.41Z" }, + { url = "https://files.pythonhosted.org/packages/d1/1c/2ed0433e682983d8e8cba9c8d8ef274d4791ec6a6f24c58935b90e780e0a/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25c479382d26a2a41b7ebea1043564a937db462816ea07afa8a44c0866d52f9", size = 2065567, upload-time = "2025-11-04T13:39:12.244Z" }, + { url = "https://files.pythonhosted.org/packages/b3/24/cf84974ee7d6eae06b9e63289b7b8f6549d416b5c199ca2d7ce13bbcf619/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f547144f2966e1e16ae626d8ce72b4cfa0caedc7fa28052001c94fb2fcaa1c52", size = 2230442, upload-time = "2025-11-04T13:39:13.962Z" }, + { url = "https://files.pythonhosted.org/packages/fd/21/4e287865504b3edc0136c89c9c09431be326168b1eb7841911cbc877a995/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f52298fbd394f9ed112d56f3d11aabd0d5bd27beb3084cc3d8ad069483b8941", size = 2350956, upload-time = "2025-11-04T13:39:15.889Z" }, + { url = "https://files.pythonhosted.org/packages/a8/76/7727ef2ffa4b62fcab916686a68a0426b9b790139720e1934e8ba797e238/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:100baa204bb412b74fe285fb0f3a385256dad1d1879f0a5cb1499ed2e83d132a", size = 2068253, upload-time = "2025-11-04T13:39:17.403Z" }, + { url = "https://files.pythonhosted.org/packages/d5/8c/a4abfc79604bcb4c748e18975c44f94f756f08fb04218d5cb87eb0d3a63e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:05a2c8852530ad2812cb7914dc61a1125dc4e06252ee98e5638a12da6cc6fb6c", size = 2177050, upload-time = "2025-11-04T13:39:19.351Z" }, + { url = "https://files.pythonhosted.org/packages/67/b1/de2e9a9a79b480f9cb0b6e8b6ba4c50b18d4e89852426364c66aa82bb7b3/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29452c56df2ed968d18d7e21f4ab0ac55e71dc59524872f6fc57dcf4a3249ed2", size = 2147178, upload-time = "2025-11-04T13:39:21Z" }, + { url = "https://files.pythonhosted.org/packages/16/c1/dfb33f837a47b20417500efaa0378adc6635b3c79e8369ff7a03c494b4ac/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:d5160812ea7a8a2ffbe233d8da666880cad0cbaf5d4de74ae15c313213d62556", size = 2341833, upload-time = "2025-11-04T13:39:22.606Z" }, + { url = "https://files.pythonhosted.org/packages/47/36/00f398642a0f4b815a9a558c4f1dca1b4020a7d49562807d7bc9ff279a6c/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df3959765b553b9440adfd3c795617c352154e497a4eaf3752555cfb5da8fc49", size = 2321156, upload-time = "2025-11-04T13:39:25.843Z" }, + { url = "https://files.pythonhosted.org/packages/7e/70/cad3acd89fde2010807354d978725ae111ddf6d0ea46d1ea1775b5c1bd0c/pydantic_core-2.41.5-cp310-cp310-win32.whl", hash = "sha256:1f8d33a7f4d5a7889e60dc39856d76d09333d8a6ed0f5f1190635cbec70ec4ba", size = 1989378, upload-time = "2025-11-04T13:39:27.92Z" }, + { url = "https://files.pythonhosted.org/packages/76/92/d338652464c6c367e5608e4488201702cd1cbb0f33f7b6a85a60fe5f3720/pydantic_core-2.41.5-cp310-cp310-win_amd64.whl", hash = "sha256:62de39db01b8d593e45871af2af9e497295db8d73b085f6bfd0b18c83c70a8f9", size = 2013622, upload-time = "2025-11-04T13:39:29.848Z" }, + { url = "https://files.pythonhosted.org/packages/e8/72/74a989dd9f2084b3d9530b0915fdda64ac48831c30dbf7c72a41a5232db8/pydantic_core-2.41.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a3a52f6156e73e7ccb0f8cced536adccb7042be67cb45f9562e12b319c119da6", size = 2105873, upload-time = "2025-11-04T13:39:31.373Z" }, + { url = "https://files.pythonhosted.org/packages/12/44/37e403fd9455708b3b942949e1d7febc02167662bf1a7da5b78ee1ea2842/pydantic_core-2.41.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7f3bf998340c6d4b0c9a2f02d6a400e51f123b59565d74dc60d252ce888c260b", size = 1899826, upload-time = "2025-11-04T13:39:32.897Z" }, + { url = "https://files.pythonhosted.org/packages/33/7f/1d5cab3ccf44c1935a359d51a8a2a9e1a654b744b5e7f80d41b88d501eec/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:378bec5c66998815d224c9ca994f1e14c0c21cb95d2f52b6021cc0b2a58f2a5a", size = 1917869, upload-time = "2025-11-04T13:39:34.469Z" }, + { url = "https://files.pythonhosted.org/packages/6e/6a/30d94a9674a7fe4f4744052ed6c5e083424510be1e93da5bc47569d11810/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7b576130c69225432866fe2f4a469a85a54ade141d96fd396dffcf607b558f8", size = 2063890, upload-time = "2025-11-04T13:39:36.053Z" }, + { url = "https://files.pythonhosted.org/packages/50/be/76e5d46203fcb2750e542f32e6c371ffa9b8ad17364cf94bb0818dbfb50c/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6cb58b9c66f7e4179a2d5e0f849c48eff5c1fca560994d6eb6543abf955a149e", size = 2229740, upload-time = "2025-11-04T13:39:37.753Z" }, + { url = "https://files.pythonhosted.org/packages/d3/ee/fed784df0144793489f87db310a6bbf8118d7b630ed07aa180d6067e653a/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88942d3a3dff3afc8288c21e565e476fc278902ae4d6d134f1eeda118cc830b1", size = 2350021, upload-time = "2025-11-04T13:39:40.94Z" }, + { url = "https://files.pythonhosted.org/packages/c8/be/8fed28dd0a180dca19e72c233cbf58efa36df055e5b9d90d64fd1740b828/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f31d95a179f8d64d90f6831d71fa93290893a33148d890ba15de25642c5d075b", size = 2066378, upload-time = "2025-11-04T13:39:42.523Z" }, + { url = "https://files.pythonhosted.org/packages/b0/3b/698cf8ae1d536a010e05121b4958b1257f0b5522085e335360e53a6b1c8b/pydantic_core-2.41.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1df3d34aced70add6f867a8cf413e299177e0c22660cc767218373d0779487b", size = 2175761, upload-time = "2025-11-04T13:39:44.553Z" }, + { url = "https://files.pythonhosted.org/packages/b8/ba/15d537423939553116dea94ce02f9c31be0fa9d0b806d427e0308ec17145/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4009935984bd36bd2c774e13f9a09563ce8de4abaa7226f5108262fa3e637284", size = 2146303, upload-time = "2025-11-04T13:39:46.238Z" }, + { url = "https://files.pythonhosted.org/packages/58/7f/0de669bf37d206723795f9c90c82966726a2ab06c336deba4735b55af431/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:34a64bc3441dc1213096a20fe27e8e128bd3ff89921706e83c0b1ac971276594", size = 2340355, upload-time = "2025-11-04T13:39:48.002Z" }, + { url = "https://files.pythonhosted.org/packages/e5/de/e7482c435b83d7e3c3ee5ee4451f6e8973cff0eb6007d2872ce6383f6398/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c9e19dd6e28fdcaa5a1de679aec4141f691023916427ef9bae8584f9c2fb3b0e", size = 2319875, upload-time = "2025-11-04T13:39:49.705Z" }, + { url = "https://files.pythonhosted.org/packages/fe/e6/8c9e81bb6dd7560e33b9053351c29f30c8194b72f2d6932888581f503482/pydantic_core-2.41.5-cp311-cp311-win32.whl", hash = "sha256:2c010c6ded393148374c0f6f0bf89d206bf3217f201faa0635dcd56bd1520f6b", size = 1987549, upload-time = "2025-11-04T13:39:51.842Z" }, + { url = "https://files.pythonhosted.org/packages/11/66/f14d1d978ea94d1bc21fc98fcf570f9542fe55bfcc40269d4e1a21c19bf7/pydantic_core-2.41.5-cp311-cp311-win_amd64.whl", hash = "sha256:76ee27c6e9c7f16f47db7a94157112a2f3a00e958bc626e2f4ee8bec5c328fbe", size = 2011305, upload-time = "2025-11-04T13:39:53.485Z" }, + { url = "https://files.pythonhosted.org/packages/56/d8/0e271434e8efd03186c5386671328154ee349ff0354d83c74f5caaf096ed/pydantic_core-2.41.5-cp311-cp311-win_arm64.whl", hash = "sha256:4bc36bbc0b7584de96561184ad7f012478987882ebf9f9c389b23f432ea3d90f", size = 1972902, upload-time = "2025-11-04T13:39:56.488Z" }, + { url = "https://files.pythonhosted.org/packages/5f/5d/5f6c63eebb5afee93bcaae4ce9a898f3373ca23df3ccaef086d0233a35a7/pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7", size = 2110990, upload-time = "2025-11-04T13:39:58.079Z" }, + { url = "https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0", size = 1896003, upload-time = "2025-11-04T13:39:59.956Z" }, + { url = "https://files.pythonhosted.org/packages/68/b8/a01b53cb0e59139fbc9e4fda3e9724ede8de279097179be4ff31f1abb65a/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69", size = 1919200, upload-time = "2025-11-04T13:40:02.241Z" }, + { url = "https://files.pythonhosted.org/packages/38/de/8c36b5198a29bdaade07b5985e80a233a5ac27137846f3bc2d3b40a47360/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75", size = 2052578, upload-time = "2025-11-04T13:40:04.401Z" }, + { url = "https://files.pythonhosted.org/packages/00/b5/0e8e4b5b081eac6cb3dbb7e60a65907549a1ce035a724368c330112adfdd/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05", size = 2208504, upload-time = "2025-11-04T13:40:06.072Z" }, + { url = "https://files.pythonhosted.org/packages/77/56/87a61aad59c7c5b9dc8caad5a41a5545cba3810c3e828708b3d7404f6cef/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc", size = 2335816, upload-time = "2025-11-04T13:40:07.835Z" }, + { url = "https://files.pythonhosted.org/packages/0d/76/941cc9f73529988688a665a5c0ecff1112b3d95ab48f81db5f7606f522d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c", size = 2075366, upload-time = "2025-11-04T13:40:09.804Z" }, + { url = "https://files.pythonhosted.org/packages/d3/43/ebef01f69baa07a482844faaa0a591bad1ef129253ffd0cdaa9d8a7f72d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5", size = 2171698, upload-time = "2025-11-04T13:40:12.004Z" }, + { url = "https://files.pythonhosted.org/packages/b1/87/41f3202e4193e3bacfc2c065fab7706ebe81af46a83d3e27605029c1f5a6/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c", size = 2132603, upload-time = "2025-11-04T13:40:13.868Z" }, + { url = "https://files.pythonhosted.org/packages/49/7d/4c00df99cb12070b6bccdef4a195255e6020a550d572768d92cc54dba91a/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294", size = 2329591, upload-time = "2025-11-04T13:40:15.672Z" }, + { url = "https://files.pythonhosted.org/packages/cc/6a/ebf4b1d65d458f3cda6a7335d141305dfa19bdc61140a884d165a8a1bbc7/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1", size = 2319068, upload-time = "2025-11-04T13:40:17.532Z" }, + { url = "https://files.pythonhosted.org/packages/49/3b/774f2b5cd4192d5ab75870ce4381fd89cf218af999515baf07e7206753f0/pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d", size = 1985908, upload-time = "2025-11-04T13:40:19.309Z" }, + { url = "https://files.pythonhosted.org/packages/86/45/00173a033c801cacf67c190fef088789394feaf88a98a7035b0e40d53dc9/pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815", size = 2020145, upload-time = "2025-11-04T13:40:21.548Z" }, + { url = "https://files.pythonhosted.org/packages/f9/22/91fbc821fa6d261b376a3f73809f907cec5ca6025642c463d3488aad22fb/pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3", size = 1976179, upload-time = "2025-11-04T13:40:23.393Z" }, + { url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403, upload-time = "2025-11-04T13:40:25.248Z" }, + { url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206, upload-time = "2025-11-04T13:40:27.099Z" }, + { url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307, upload-time = "2025-11-04T13:40:29.806Z" }, + { url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", size = 2063258, upload-time = "2025-11-04T13:40:33.544Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", size = 2214917, upload-time = "2025-11-04T13:40:35.479Z" }, + { url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", size = 2332186, upload-time = "2025-11-04T13:40:37.436Z" }, + { url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164, upload-time = "2025-11-04T13:40:40.289Z" }, + { url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146, upload-time = "2025-11-04T13:40:42.809Z" }, + { url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788, upload-time = "2025-11-04T13:40:44.752Z" }, + { url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload-time = "2025-11-04T13:40:46.66Z" }, + { url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852, upload-time = "2025-11-04T13:40:48.575Z" }, + { url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679, upload-time = "2025-11-04T13:40:50.619Z" }, + { url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766, upload-time = "2025-11-04T13:40:52.631Z" }, + { url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005, upload-time = "2025-11-04T13:40:54.734Z" }, + { url = "https://files.pythonhosted.org/packages/ea/28/46b7c5c9635ae96ea0fbb779e271a38129df2550f763937659ee6c5dbc65/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a", size = 2119622, upload-time = "2025-11-04T13:40:56.68Z" }, + { url = "https://files.pythonhosted.org/packages/74/1a/145646e5687e8d9a1e8d09acb278c8535ebe9e972e1f162ed338a622f193/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14", size = 1891725, upload-time = "2025-11-04T13:40:58.807Z" }, + { url = "https://files.pythonhosted.org/packages/23/04/e89c29e267b8060b40dca97bfc64a19b2a3cf99018167ea1677d96368273/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1", size = 1915040, upload-time = "2025-11-04T13:41:00.853Z" }, + { url = "https://files.pythonhosted.org/packages/84/a3/15a82ac7bd97992a82257f777b3583d3e84bdb06ba6858f745daa2ec8a85/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66", size = 2063691, upload-time = "2025-11-04T13:41:03.504Z" }, + { url = "https://files.pythonhosted.org/packages/74/9b/0046701313c6ef08c0c1cf0e028c67c770a4e1275ca73131563c5f2a310a/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869", size = 2213897, upload-time = "2025-11-04T13:41:05.804Z" }, + { url = "https://files.pythonhosted.org/packages/8a/cd/6bac76ecd1b27e75a95ca3a9a559c643b3afcd2dd62086d4b7a32a18b169/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2", size = 2333302, upload-time = "2025-11-04T13:41:07.809Z" }, + { url = "https://files.pythonhosted.org/packages/4c/d2/ef2074dc020dd6e109611a8be4449b98cd25e1b9b8a303c2f0fca2f2bcf7/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375", size = 2064877, upload-time = "2025-11-04T13:41:09.827Z" }, + { url = "https://files.pythonhosted.org/packages/18/66/e9db17a9a763d72f03de903883c057b2592c09509ccfe468187f2a2eef29/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553", size = 2180680, upload-time = "2025-11-04T13:41:12.379Z" }, + { url = "https://files.pythonhosted.org/packages/d3/9e/3ce66cebb929f3ced22be85d4c2399b8e85b622db77dad36b73c5387f8f8/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90", size = 2138960, upload-time = "2025-11-04T13:41:14.627Z" }, + { url = "https://files.pythonhosted.org/packages/a6/62/205a998f4327d2079326b01abee48e502ea739d174f0a89295c481a2272e/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07", size = 2339102, upload-time = "2025-11-04T13:41:16.868Z" }, + { url = "https://files.pythonhosted.org/packages/3c/0d/f05e79471e889d74d3d88f5bd20d0ed189ad94c2423d81ff8d0000aab4ff/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb", size = 2326039, upload-time = "2025-11-04T13:41:18.934Z" }, + { url = "https://files.pythonhosted.org/packages/ec/e1/e08a6208bb100da7e0c4b288eed624a703f4d129bde2da475721a80cab32/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23", size = 1995126, upload-time = "2025-11-04T13:41:21.418Z" }, + { url = "https://files.pythonhosted.org/packages/48/5d/56ba7b24e9557f99c9237e29f5c09913c81eeb2f3217e40e922353668092/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf", size = 2015489, upload-time = "2025-11-04T13:41:24.076Z" }, + { url = "https://files.pythonhosted.org/packages/4e/bb/f7a190991ec9e3e0ba22e4993d8755bbc4a32925c0b5b42775c03e8148f9/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0", size = 1977288, upload-time = "2025-11-04T13:41:26.33Z" }, + { url = "https://files.pythonhosted.org/packages/92/ed/77542d0c51538e32e15afe7899d79efce4b81eee631d99850edc2f5e9349/pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a", size = 2120255, upload-time = "2025-11-04T13:41:28.569Z" }, + { url = "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3", size = 1863760, upload-time = "2025-11-04T13:41:31.055Z" }, + { url = "https://files.pythonhosted.org/packages/5a/f0/e5e6b99d4191da102f2b0eb9687aaa7f5bea5d9964071a84effc3e40f997/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c", size = 1878092, upload-time = "2025-11-04T13:41:33.21Z" }, + { url = "https://files.pythonhosted.org/packages/71/48/36fb760642d568925953bcc8116455513d6e34c4beaa37544118c36aba6d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612", size = 2053385, upload-time = "2025-11-04T13:41:35.508Z" }, + { url = "https://files.pythonhosted.org/packages/20/25/92dc684dd8eb75a234bc1c764b4210cf2646479d54b47bf46061657292a8/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d", size = 2218832, upload-time = "2025-11-04T13:41:37.732Z" }, + { url = "https://files.pythonhosted.org/packages/e2/09/f53e0b05023d3e30357d82eb35835d0f6340ca344720a4599cd663dca599/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9", size = 2327585, upload-time = "2025-11-04T13:41:40Z" }, + { url = "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660", size = 2041078, upload-time = "2025-11-04T13:41:42.323Z" }, + { url = "https://files.pythonhosted.org/packages/cd/13/2e215f17f0ef326fc72afe94776edb77525142c693767fc347ed6288728d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9", size = 2173914, upload-time = "2025-11-04T13:41:45.221Z" }, + { url = "https://files.pythonhosted.org/packages/02/7a/f999a6dcbcd0e5660bc348a3991c8915ce6599f4f2c6ac22f01d7a10816c/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3", size = 2129560, upload-time = "2025-11-04T13:41:47.474Z" }, + { url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf", size = 2329244, upload-time = "2025-11-04T13:41:49.992Z" }, + { url = "https://files.pythonhosted.org/packages/d9/02/3c562f3a51afd4d88fff8dffb1771b30cfdfd79befd9883ee094f5b6c0d8/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470", size = 2331955, upload-time = "2025-11-04T13:41:54.079Z" }, + { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" }, + { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" }, + { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" }, + { url = "https://files.pythonhosted.org/packages/11/72/90fda5ee3b97e51c494938a4a44c3a35a9c96c19bba12372fb9c634d6f57/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034", size = 2115441, upload-time = "2025-11-04T13:42:39.557Z" }, + { url = "https://files.pythonhosted.org/packages/1f/53/8942f884fa33f50794f119012dc6a1a02ac43a56407adaac20463df8e98f/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c", size = 1930291, upload-time = "2025-11-04T13:42:42.169Z" }, + { url = "https://files.pythonhosted.org/packages/79/c8/ecb9ed9cd942bce09fc888ee960b52654fbdbede4ba6c2d6e0d3b1d8b49c/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2", size = 1948632, upload-time = "2025-11-04T13:42:44.564Z" }, + { url = "https://files.pythonhosted.org/packages/2e/1b/687711069de7efa6af934e74f601e2a4307365e8fdc404703afc453eab26/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad", size = 2138905, upload-time = "2025-11-04T13:42:47.156Z" }, + { url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495, upload-time = "2025-11-04T13:42:49.689Z" }, + { url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388, upload-time = "2025-11-04T13:42:52.215Z" }, + { url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879, upload-time = "2025-11-04T13:42:56.483Z" }, + { url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017, upload-time = "2025-11-04T13:42:59.471Z" }, + { url = "https://files.pythonhosted.org/packages/e6/b0/1a2aa41e3b5a4ba11420aba2d091b2d17959c8d1519ece3627c371951e73/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b5819cd790dbf0c5eb9f82c73c16b39a65dd6dd4d1439dcdea7816ec9adddab8", size = 2103351, upload-time = "2025-11-04T13:43:02.058Z" }, + { url = "https://files.pythonhosted.org/packages/a4/ee/31b1f0020baaf6d091c87900ae05c6aeae101fa4e188e1613c80e4f1ea31/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5a4e67afbc95fa5c34cf27d9089bca7fcab4e51e57278d710320a70b956d1b9a", size = 1925363, upload-time = "2025-11-04T13:43:05.159Z" }, + { url = "https://files.pythonhosted.org/packages/e1/89/ab8e86208467e467a80deaca4e434adac37b10a9d134cd2f99b28a01e483/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ece5c59f0ce7d001e017643d8d24da587ea1f74f6993467d85ae8a5ef9d4f42b", size = 2135615, upload-time = "2025-11-04T13:43:08.116Z" }, + { url = "https://files.pythonhosted.org/packages/99/0a/99a53d06dd0348b2008f2f30884b34719c323f16c3be4e6cc1203b74a91d/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16f80f7abe3351f8ea6858914ddc8c77e02578544a0ebc15b4c2e1a0e813b0b2", size = 2175369, upload-time = "2025-11-04T13:43:12.49Z" }, + { url = "https://files.pythonhosted.org/packages/6d/94/30ca3b73c6d485b9bb0bc66e611cff4a7138ff9736b7e66bcf0852151636/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:33cb885e759a705b426baada1fe68cbb0a2e68e34c5d0d0289a364cf01709093", size = 2144218, upload-time = "2025-11-04T13:43:15.431Z" }, + { url = "https://files.pythonhosted.org/packages/87/57/31b4f8e12680b739a91f472b5671294236b82586889ef764b5fbc6669238/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:c8d8b4eb992936023be7dee581270af5c6e0697a8559895f527f5b7105ecd36a", size = 2329951, upload-time = "2025-11-04T13:43:18.062Z" }, + { url = "https://files.pythonhosted.org/packages/7d/73/3c2c8edef77b8f7310e6fb012dbc4b8551386ed575b9eb6fb2506e28a7eb/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:242a206cd0318f95cd21bdacff3fcc3aab23e79bba5cac3db5a841c9ef9c6963", size = 2318428, upload-time = "2025-11-04T13:43:20.679Z" }, + { url = "https://files.pythonhosted.org/packages/2f/02/8559b1f26ee0d502c74f9cca5c0d2fd97e967e083e006bbbb4e97f3a043a/pydantic_core-2.41.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d3a978c4f57a597908b7e697229d996d77a6d3c94901e9edee593adada95ce1a", size = 2147009, upload-time = "2025-11-04T13:43:23.286Z" }, + { url = "https://files.pythonhosted.org/packages/5f/9b/1b3f0e9f9305839d7e84912f9e8bfbd191ed1b1ef48083609f0dabde978c/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b2379fa7ed44ddecb5bfe4e48577d752db9fc10be00a6b7446e9663ba143de26", size = 2101980, upload-time = "2025-11-04T13:43:25.97Z" }, + { url = "https://files.pythonhosted.org/packages/a4/ed/d71fefcb4263df0da6a85b5d8a7508360f2f2e9b3bf5814be9c8bccdccc1/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:266fb4cbf5e3cbd0b53669a6d1b039c45e3ce651fd5442eff4d07c2cc8d66808", size = 1923865, upload-time = "2025-11-04T13:43:28.763Z" }, + { url = "https://files.pythonhosted.org/packages/ce/3a/626b38db460d675f873e4444b4bb030453bbe7b4ba55df821d026a0493c4/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58133647260ea01e4d0500089a8c4f07bd7aa6ce109682b1426394988d8aaacc", size = 2134256, upload-time = "2025-11-04T13:43:31.71Z" }, + { url = "https://files.pythonhosted.org/packages/83/d9/8412d7f06f616bbc053d30cb4e5f76786af3221462ad5eee1f202021eb4e/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:287dad91cfb551c363dc62899a80e9e14da1f0e2b6ebde82c806612ca2a13ef1", size = 2174762, upload-time = "2025-11-04T13:43:34.744Z" }, + { url = "https://files.pythonhosted.org/packages/55/4c/162d906b8e3ba3a99354e20faa1b49a85206c47de97a639510a0e673f5da/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:03b77d184b9eb40240ae9fd676ca364ce1085f203e1b1256f8ab9984dca80a84", size = 2143141, upload-time = "2025-11-04T13:43:37.701Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f2/f11dd73284122713f5f89fc940f370d035fa8e1e078d446b3313955157fe/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:a668ce24de96165bb239160b3d854943128f4334822900534f2fe947930e5770", size = 2330317, upload-time = "2025-11-04T13:43:40.406Z" }, + { url = "https://files.pythonhosted.org/packages/88/9d/b06ca6acfe4abb296110fb1273a4d848a0bfb2ff65f3ee92127b3244e16b/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f14f8f046c14563f8eb3f45f499cc658ab8d10072961e07225e507adb700e93f", size = 2316992, upload-time = "2025-11-04T13:43:43.602Z" }, + { url = "https://files.pythonhosted.org/packages/36/c7/cfc8e811f061c841d7990b0201912c3556bfeb99cdcb7ed24adc8d6f8704/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51", size = 2145302, upload-time = "2025-11-04T13:43:46.64Z" }, +] + [[package]] name = "pygments" version = "2.19.2" @@ -695,6 +917,7 @@ name = "python-template" version = "3.0.0a1" source = { virtual = "." } dependencies = [ + { name = "copier" }, { name = "furo" }, { name = "ipdb" }, { name = "ipython", version = "8.37.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, @@ -713,6 +936,7 @@ dependencies = [ [package.metadata] requires-dist = [ + { name = "copier", specifier = ">=9.11.0" }, { name = "furo", specifier = ">=2025.12.19" }, { name = "ipdb", specifier = ">=0.12.3" }, { name = "ipython", specifier = ">=8.0.0" }, @@ -725,6 +949,28 @@ requires-dist = [ { name = "sphinx-copybutton", specifier = ">=0.4.0" }, ] +[[package]] +name = "pywin32" +version = "311" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/40/44efbb0dfbd33aca6a6483191dae0716070ed99e2ecb0c53683f400a0b4f/pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3", size = 8760432, upload-time = "2025-07-14T20:13:05.9Z" }, + { url = "https://files.pythonhosted.org/packages/5e/bf/360243b1e953bd254a82f12653974be395ba880e7ec23e3731d9f73921cc/pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b", size = 9590103, upload-time = "2025-07-14T20:13:07.698Z" }, + { url = "https://files.pythonhosted.org/packages/57/38/d290720e6f138086fb3d5ffe0b6caa019a791dd57866940c82e4eeaf2012/pywin32-311-cp310-cp310-win_arm64.whl", hash = "sha256:0502d1facf1fed4839a9a51ccbcc63d952cf318f78ffc00a7e78528ac27d7a2b", size = 8778557, upload-time = "2025-07-14T20:13:11.11Z" }, + { url = "https://files.pythonhosted.org/packages/7c/af/449a6a91e5d6db51420875c54f6aff7c97a86a3b13a0b4f1a5c13b988de3/pywin32-311-cp311-cp311-win32.whl", hash = "sha256:184eb5e436dea364dcd3d2316d577d625c0351bf237c4e9a5fabbcfa5a58b151", size = 8697031, upload-time = "2025-07-14T20:13:13.266Z" }, + { url = "https://files.pythonhosted.org/packages/51/8f/9bb81dd5bb77d22243d33c8397f09377056d5c687aa6d4042bea7fbf8364/pywin32-311-cp311-cp311-win_amd64.whl", hash = "sha256:3ce80b34b22b17ccbd937a6e78e7225d80c52f5ab9940fe0506a1a16f3dab503", size = 9508308, upload-time = "2025-07-14T20:13:15.147Z" }, + { url = "https://files.pythonhosted.org/packages/44/7b/9c2ab54f74a138c491aba1b1cd0795ba61f144c711daea84a88b63dc0f6c/pywin32-311-cp311-cp311-win_arm64.whl", hash = "sha256:a733f1388e1a842abb67ffa8e7aad0e70ac519e09b0f6a784e65a136ec7cefd2", size = 8703930, upload-time = "2025-07-14T20:13:16.945Z" }, + { url = "https://files.pythonhosted.org/packages/e7/ab/01ea1943d4eba0f850c3c61e78e8dd59757ff815ff3ccd0a84de5f541f42/pywin32-311-cp312-cp312-win32.whl", hash = "sha256:750ec6e621af2b948540032557b10a2d43b0cee2ae9758c54154d711cc852d31", size = 8706543, upload-time = "2025-07-14T20:13:20.765Z" }, + { url = "https://files.pythonhosted.org/packages/d1/a8/a0e8d07d4d051ec7502cd58b291ec98dcc0c3fff027caad0470b72cfcc2f/pywin32-311-cp312-cp312-win_amd64.whl", hash = "sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067", size = 9495040, upload-time = "2025-07-14T20:13:22.543Z" }, + { url = "https://files.pythonhosted.org/packages/ba/3a/2ae996277b4b50f17d61f0603efd8253cb2d79cc7ae159468007b586396d/pywin32-311-cp312-cp312-win_arm64.whl", hash = "sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852", size = 8710102, upload-time = "2025-07-14T20:13:24.682Z" }, + { url = "https://files.pythonhosted.org/packages/a5/be/3fd5de0979fcb3994bfee0d65ed8ca9506a8a1260651b86174f6a86f52b3/pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d", size = 8705700, upload-time = "2025-07-14T20:13:26.471Z" }, + { url = "https://files.pythonhosted.org/packages/e3/28/e0a1909523c6890208295a29e05c2adb2126364e289826c0a8bc7297bd5c/pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d", size = 9494700, upload-time = "2025-07-14T20:13:28.243Z" }, + { url = "https://files.pythonhosted.org/packages/04/bf/90339ac0f55726dce7d794e6d79a18a91265bdf3aa70b6b9ca52f35e022a/pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a", size = 8709318, upload-time = "2025-07-14T20:13:30.348Z" }, + { url = "https://files.pythonhosted.org/packages/c9/31/097f2e132c4f16d99a22bfb777e0fd88bd8e1c634304e102f313af69ace5/pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee", size = 8840714, upload-time = "2025-07-14T20:13:32.449Z" }, + { url = "https://files.pythonhosted.org/packages/90/4b/07c77d8ba0e01349358082713400435347df8426208171ce297da32c313d/pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87", size = 9656800, upload-time = "2025-07-14T20:13:34.312Z" }, + { url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" }, +] + [[package]] name = "pyyaml" version = "6.0.3" @@ -789,6 +1035,18 @@ wheels = [ { 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 = "questionary" +version = "2.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "prompt-toolkit" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f6/45/eafb0bba0f9988f6a2520f9ca2df2c82ddfa8d67c95d6625452e97b204a5/questionary-2.1.1.tar.gz", hash = "sha256:3d7e980292bb0107abaa79c68dd3eee3c561b83a0f89ae482860b181c8bd412d", size = 25845, upload-time = "2025-08-28T19:00:20.851Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/26/1062c7ec1b053db9e499b4d2d5bc231743201b74051c973dadeac80a8f43/questionary-2.1.1-py3-none-any.whl", hash = "sha256:a51af13f345f1cdea62347589fbb6df3b290306ab8930713bfae4d475a7d4a59", size = 36753, upload-time = "2025-08-28T19:00:19.56Z" }, +] + [[package]] name = "requests" version = "2.32.5" @@ -1175,6 +1433,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, ] +[[package]] +name = "typing-inspection" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, +] + [[package]] name = "urllib3" version = "2.6.2" From 17230cabd046d0915bc7efb4a09d5d8f19a00530 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20S=C3=A1nchez-Gallego?= Date: Tue, 30 Dec 2025 09:33:54 -0800 Subject: [PATCH 3/9] Add licenses --- LICENSE.md => LICENSE | 2 +- licenses/Apache-2.0 | 16 ++++++++++++++++ licenses/GPL-3.0-or-later | 10 ++++++++++ licenses/MIT | 10 ++++++++++ template/{LICENSE.md => LICENSE} | 2 +- 5 files changed, 38 insertions(+), 2 deletions(-) rename LICENSE.md => LICENSE (98%) create mode 100644 licenses/Apache-2.0 create mode 100644 licenses/GPL-3.0-or-later create mode 100644 licenses/MIT rename template/{LICENSE.md => LICENSE} (97%) diff --git a/LICENSE.md b/LICENSE similarity index 98% rename from LICENSE.md rename to LICENSE index b583b6f..48e6b95 100644 --- a/LICENSE.md +++ b/LICENSE @@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright (c) 2017, SDSS +Copyright (c) 2017-, SDSS All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/licenses/Apache-2.0 b/licenses/Apache-2.0 new file mode 100644 index 0000000..2502f52 --- /dev/null +++ b/licenses/Apache-2.0 @@ -0,0 +1,16 @@ +GNU General Public License v3.0 or later + +Copyright (c) {{ year }}-, SDSS +All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/licenses/GPL-3.0-or-later b/licenses/GPL-3.0-or-later new file mode 100644 index 0000000..71c6730 --- /dev/null +++ b/licenses/GPL-3.0-or-later @@ -0,0 +1,10 @@ +GNU General Public License v3.0 or later + +Copyright (c) {{ year }}-, SDSS +All rights reserved. + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with this program. If not, see . diff --git a/licenses/MIT b/licenses/MIT new file mode 100644 index 0000000..3338367 --- /dev/null +++ b/licenses/MIT @@ -0,0 +1,10 @@ +MIT License + +Copyright (c) {{ year }}-, SDSS +All rights reserved. + +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 (including the next paragraph) 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. diff --git a/template/LICENSE.md b/template/LICENSE similarity index 97% rename from template/LICENSE.md rename to template/LICENSE index b583b6f..ecbc6cd 100644 --- a/template/LICENSE.md +++ b/template/LICENSE @@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright (c) 2017, SDSS +Copyright (c) {{ year }}-, SDSS All rights reserved. Redistribution and use in source and binary forms, with or without From 0965c9f058294396a6a7618b58c9a7cda8e23712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20S=C3=A1nchez-Gallego?= Date: Tue, 30 Dec 2025 09:58:28 -0800 Subject: [PATCH 4/9] Support downloading licenses and other improvements --- pyproject.toml | 3 +- template/CODEOWNERS.jinja | 17 ++--- template/post_copy.py | 74 ++++++++++++++++++- template/pyproject.toml.jinja | 3 +- template/tests/test_{{package_name}}.py.jinja | 15 ++++ 5 files changed, 98 insertions(+), 14 deletions(-) create mode 100644 template/tests/test_{{package_name}}.py.jinja diff --git a/pyproject.toml b/pyproject.toml index 9e80132..1e56076 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,8 @@ authors = [ { name = "JosΓ© SΓ‘nchez-Gallego", email = "gallegoj@uw.edu" }, { name = "Brian Cherinka", email = "bcherinka@stsci.edu" } ] -license = { text = "BSD-3-Clause" } +license = "BSD-3-Clause" +license-files = ["LICENSE"] readme = "README.md" requires-python = ">=3.10,<4" diff --git a/template/CODEOWNERS.jinja b/template/CODEOWNERS.jinja index 69ff242..9a340d9 100644 --- a/template/CODEOWNERS.jinja +++ b/template/CODEOWNERS.jinja @@ -5,35 +5,34 @@ # the repo. Unless a later match takes precedence, # @global-owner1 and @global-owner2 will be requested for # review when someone opens a pull request. -* @{{github_organization}} -* @{{github_username}} -* {{email}} +* @{{github_username}} +* {{author_email}} # Order is important; the last matching pattern takes the most # precedence. When someone opens a pull request that only # modifies JS files, only @js-owner and not the global # owner(s) will be requested for a review. -*.js @js-owner +# *.js @js-owner # You can also use email addresses if you prefer. They'll be # used to look up users just like we do for commit author # emails. -*.go docs@example.com +# *.go docs@example.com # In this example, @doctocat owns any files in the build/logs # directory at the root of the repository and any of its # subdirectories. -/build/logs/ @doctocat +# /build/logs/ @doctocat # The `docs/*` pattern will match files like # `docs/getting-started.md` but not further nested files like # `docs/build-app/troubleshooting.md`. -docs/* docs@example.com +# docs/* docs@example.com # In this example, @octocat owns any file in an apps directory # anywhere in your repository. -apps/ @octocat +# apps/ @octocat # In this example, @doctocat owns any file in the `/docs` # directory in the root of your repository. -/docs/ @doctocat +# /docs/ @doctocat diff --git a/template/post_copy.py b/template/post_copy.py index 1ef747c..9d9d40b 100644 --- a/template/post_copy.py +++ b/template/post_copy.py @@ -8,8 +8,10 @@ from __future__ import annotations +import datetime import pathlib import subprocess +import urllib.request from typing import Any @@ -49,6 +51,47 @@ def delete_copier_files(keep_answers: bool = False) -> None: print(colorama.Fore.WHITE + " > Deleted .copier-answers.yml file.") +def get_license_text(license_file: str) -> str: + """Returns the text of a license file.""" + + url = f"https://raw.githubusercontent.com/sdss/python_template/refs/heads/python-template-v3/licenses/{license_file}" + + with urllib.request.urlopen(url) as response: + return response.read().decode("utf-8") + + +def update_license(license: str) -> bool: + """Updates the LICENSE file with the selected license.""" + + dst_file = pathlib.Path.cwd() / "LICENSE" + license_text: str = "" + + if license == "BSD-3-Clause": + # The template includes this license by default. + pass + else: + license_text = get_license_text(license) + with dst_file.open("w") as f: + f.write(license_text) + + # Update the copyright year + with dst_file.open("a+") as f: + f.seek(0) + text = f.read() + text = text.replace( + "{{ year }}", + str(datetime.datetime.now().year), + ) + f.seek(0) + f.truncate(0) + f.write(text) + f.truncate() + + print(colorama.Fore.WHITE + f" > Updated LICENSE file to {license}.") + + return True + + def run_command( command: list[str] | str, cwd: pathlib.Path | None = None, @@ -111,6 +154,11 @@ def post_copy(): delete_copier_files(keep_answers=keep_answers) return + # Update the LICENSE file + license = answers.get("license", "BSD-3-Clause").strip() + update_license(license) + + # Sync the project with 'uv' if requested if answers.get("sync_project", True): uv_path = get_binary_path("uv") if not uv_path: @@ -136,6 +184,7 @@ def post_copy(): error_message="Failed to sync project with 'uv'.", ) + # If git is available, initialize a repository. git_path = get_binary_path("git") if not git_path: print(colorama.Fore.YELLOW + " ! 'git' binary not found in PATH.") @@ -150,7 +199,10 @@ def post_copy(): push_to_github = answers.get("push_to_github", False) private = answers.get("private_repository", False) + # If we are pushing to GitHub, set the remote and push. We need to add and + # commit all files first but skip the copier files. if result and push_to_github and github_organization: + # Set the remote github_repo_url = f"git@github.com:{github_organization}/{project_name}.git" run_command( [str(git_path), "remote", "add", "origin", github_repo_url], @@ -160,6 +212,7 @@ def post_copy(): keep_answers=keep_answers, ) + # Stage all files run_command( [str(git_path), "add", "."], success_message="Staged all files for initial commit.", @@ -168,6 +221,20 @@ def post_copy(): keep_answers=keep_answers, ) + # Remove copier files from staging + files_to_unstage = ["post_copy.py"] + if not keep_answers: + files_to_unstage.append(".copier-answers.yml") + + run_command( + [str(git_path), "reset", "--"] + files_to_unstage, + success_message="Removed copier files from staging.", + error_message="Failed to remove copier files from staging.", + exit_on_error=True, + keep_answers=keep_answers, + ) + + # Commit run_command( [str(git_path), "commit", "-m", "Initial commit"], success_message="Created initial commit.", @@ -176,11 +243,12 @@ def post_copy(): keep_answers=keep_answers, ) - gh_path = get_binary_path("gh") - if gh_path: + # Create the GitHub repository using 'gh' CLI, if available. + gh_cli_path = get_binary_path("gh") + if gh_cli_path: if run_command( [ - str(gh_path), + str(gh_cli_path), "repo", "create", f"{github_organization}/{project_name}", diff --git a/template/pyproject.toml.jinja b/template/pyproject.toml.jinja index d0d20a0..8529f60 100644 --- a/template/pyproject.toml.jinja +++ b/template/pyproject.toml.jinja @@ -5,7 +5,8 @@ description = "{{ project_description }}" authors = [ { name = "{{ author_name }}", email = "{{ author_email }}" }, ] -license = { text = "{{ license }}" } +license = "{{ license }}" +license-files = ["LICENSE"] readme = "README.md" requires-python = ">=3.10,<4" diff --git a/template/tests/test_{{package_name}}.py.jinja b/template/tests/test_{{package_name}}.py.jinja new file mode 100644 index 0000000..baeff3a --- /dev/null +++ b/template/tests/test_{{package_name}}.py.jinja @@ -0,0 +1,15 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# @Filename: test_{{package_name}}.py +# @License: BSD 3-clause (http://www.opensource.org/licenses/BSD-3-Clause) + +from __future__ import annotations + + +def test_{{package_name}}(): + """Basic test for {{package_name}} package.""" + + import {{package_name}} + + assert {{package_name}}.__version__ is not None From 8d7cf56189937dcde13d408081213369006367c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20S=C3=A1nchez-Gallego?= Date: Tue, 30 Dec 2025 10:23:45 -0800 Subject: [PATCH 5/9] Add src/python_project to allow Sphinx to find the package --- src/python_template/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/python_template/__init__.py diff --git a/src/python_template/__init__.py b/src/python_template/__init__.py new file mode 100644 index 0000000..e69de29 From ec9d1311667fb697cbfdf19b0bc0f69fdba64084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20S=C3=A1nchez-Gallego?= Date: Tue, 30 Dec 2025 11:24:48 -0800 Subject: [PATCH 6/9] Do not ask to keep Copier answers --- copier.yaml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/copier.yaml b/copier.yaml index 9a10ab8..843da77 100644 --- a/copier.yaml +++ b/copier.yaml @@ -84,12 +84,6 @@ sync_project: help: Whether to create a venv and sync the project after creation using uv. default: true -keep_answers: - type: bool - qmark: πŸ’Ύ - help: Keep Copier answers to questions for future re-use. - default: false - _subdirectory: template _tasks: From fd83e2d9ff5a50320576244ce2346f2a0f885c2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20S=C3=A1nchez-Gallego?= Date: Tue, 30 Dec 2025 11:43:14 -0800 Subject: [PATCH 7/9] Add .vscode to .gitignore --- .gitignore | 2 ++ template/.gitignore | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index f81e90c..d4bcdda 100644 --- a/.gitignore +++ b/.gitignore @@ -107,3 +107,5 @@ ENV/ *~ *.swp *.swo + +.vscode/ diff --git a/template/.gitignore b/template/.gitignore index f81e90c..d4bcdda 100644 --- a/template/.gitignore +++ b/template/.gitignore @@ -107,3 +107,5 @@ ENV/ *~ *.swp *.swo + +.vscode/ From 725b730bcf8edb4c554edfd08f12334b0473ce07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20S=C3=A1nchez-Gallego?= Date: Tue, 30 Dec 2025 13:29:53 -0800 Subject: [PATCH 8/9] Use uv sync --frozen --group test --- template/.github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template/.github/workflows/test.yml b/template/.github/workflows/test.yml index 24d11b5..340b61e 100644 --- a/template/.github/workflows/test.yml +++ b/template/.github/workflows/test.yml @@ -38,7 +38,7 @@ jobs: - name: Test with pytest run: | - uv pip install pytest pytest-mock pytest-asyncio pytest-cov + uv sync --frozen --group test uv run pytest # - name: Upload coverage to Codecov From ca8e94b60e01d45f8fec8d08c207be75450887f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20S=C3=A1nchez-Gallego?= Date: Tue, 30 Dec 2025 15:15:02 -0800 Subject: [PATCH 9/9] 60% of documentation --- docs/sphinx/index.md | 376 ++++++++++++++++++++++++++++++++++ docs/sphinx/index.rst | 25 --- docs/sphinx/style.md | 11 + style/STYLE_v2.md | 2 +- template/pyproject.toml.jinja | 2 +- 5 files changed, 389 insertions(+), 27 deletions(-) create mode 100644 docs/sphinx/index.md delete mode 100644 docs/sphinx/index.rst create mode 100644 docs/sphinx/style.md diff --git a/docs/sphinx/index.md b/docs/sphinx/index.md new file mode 100644 index 0000000..e9268d4 --- /dev/null +++ b/docs/sphinx/index.md @@ -0,0 +1,376 @@ + +# SDSS Python Template + +```{toctree} +:hidden: +Changelog +Style guide