diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1ec14a6e..991c25ac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -89,6 +89,10 @@ jobs: timeout-minutes: 10 uses: ./.github/actions/pdm + - name: Setup Graphviz + timeout-minutes: 10 + uses: ts-graphviz/setup-graphviz@v2 + - name: Install dependencies timeout-minutes: 10 run: pdm install --dev --check --frozen-lockfile @@ -117,7 +121,7 @@ jobs: - name: Publish test reports timeout-minutes: 10 - if: always() + if: ${{ !cancelled() }} uses: pmeier/pytest-results-action@v0.7.1 with: path: tests/.tests.xml @@ -125,3 +129,33 @@ jobs: summary: true display-options: fEX fail-on-empty: false + + - name: Setup docs cache + timeout-minutes: 10 + if: ${{ !cancelled() }} + uses: actions/cache@v4 + with: + path: docs/build + key: docs-cache-${{ hashFiles('docs') }} + + - name: Build docs + timeout-minutes: 10 + if: ${{ !cancelled() }} + run: pdm run docs + + - name: Setup Github Pages + timeout-minutes: 10 + if: ${{ !cancelled() && github.event_name == 'push' && github.ref == 'refs/heads/main' }} + uses: actions/configure-pages@v5 + + - name: Upload docs to Github Pages + timeout-minutes: 10 + if: ${{ !cancelled() && github.event_name == 'push' && github.ref == 'refs/heads/main' }} + uses: actions/upload-pages-artifact@v3 + with: + path: './docs/build' + + - name: Deploy GitHub Pages + timeout-minutes: 10 + if: ${{ !cancelled() && github.event_name == 'push' && github.ref == 'refs/heads/main' }} + uses: actions/deploy-pages@v4 diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 00000000..5e88b163 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,80 @@ +import sys +from dataclasses import asdict +from pathlib import Path + +from sphinxawesome_theme import ThemeOptions +from sphinxawesome_theme.postprocess import Icons + +sys.path.insert(0, str(Path(__file__).parent / "src")) + +nitpicky = True +project = "python-erc7730" +copyright = "2024, Ledger" +author = "Ledger" +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.githubpages", + "sphinx.ext.viewcode", + "sphinx.ext.linkcode", + "sphinx.ext.autosummary", + "sphinx.ext.graphviz", + "sphinx.ext.intersphinx", + "sphinx.ext.todo", + "sphinx.ext.autosummary", + "sphinxcontrib.mermaid", + "sphinxcontrib.typer", + "sphinxcontrib.apidoc", + "sphinxcontrib.autodoc_pydantic", + "myst_parser", + "sphinx_github_style", + "sphinx_issues", + "sphinx_design", +] +myst_enable_extensions = [ + "fieldlist", + "linkify", + "substitution", +] +source_suffix = { + ".rst": "restructuredtext", + ".md": "markdown", +} +intersphinx_mapping = { + "python": ("https://docs.python.org/3", None), +} +templates_path = ["templates"] +issues_github_path = "LedgerHQ/python-erc7730" +linkcode_url = "LedgerHQ/python-erc7730" +apidoc_module_dir = "../src" +apidoc_output_dir = "build/reference" +apidoc_separate_modules = True +autosummary_generate = True +autodoc_pydantic_model_show_json = False +autodoc_pydantic_model_show_config_summary = False +autodoc_pydantic_model_validator_members = False +autodoc_pydantic_model_validator_summary = False +autodoc_pydantic_model_field_summary = False +autodoc_pydantic_model_hide_paramlist = True +autodoc_pydantic_model_hide_reused_validator = True +html_theme = "sphinxawesome_theme" +html_static_path = ["static"] +html_css_files = ["custom.css", "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css"] +html_favicon = "static/ledger-icon.png" +html_logo = "static/ledger-icon.png" +html_title = "python-erc7730" +html_show_sphinx = False +html_permalinks_icon = Icons.permalinks_icon +html_context = {"default_mode": "light"} +html_theme_options = asdict( + ThemeOptions( + show_prev_next=False, + show_scrolltop=True, + show_breadcrumbs=True, + breadcrumbs_separator=">", + ) +) +pygments_style = "friendly" +pygments_style_dark = "nord-darker" +todo_include_todos = True +mathjax3_config = {"displayAlign": "left"} +mermaid_version = "11.3.0" diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..9090d5de --- /dev/null +++ b/docs/index.md @@ -0,0 +1,18 @@ +python-erc7730 +============== + +**This library provides tooling for the ERC-7730 standard.** + +See for the standard specification and example descriptors. + +This library implements: + * Reading and writing ERC-7730 descriptor files into an object model + * Validation, available as a command line tool + * Conversion between Ledger specific legacy descriptors and ERC-7730 + + +```{toctree} +:maxdepth: 2 +pages/usage_cli.md +pages/usage_library.md +``` diff --git a/docs/pages/usage_cli.md b/docs/pages/usage_cli.md new file mode 100644 index 00000000..ac5a6be6 --- /dev/null +++ b/docs/pages/usage_cli.md @@ -0,0 +1,53 @@ +# Command line usage + +## Installation + +The `erc7730` tool is available as a [Python package on PyPI](https://pypi.org/project/erc7730). You can install it +using `pip`: + +```bash +pip install --user erc7730 +``` + +## Validation + +You can validate your setup by running the `erc7730` command: + +```{typer} erc7730.main.app +:preferred: svg +:theme: dark +:width: 100 +:prog: cal +``` + +## Commands + +### `erc7730 lint` + +The `lint` command runs validations on descriptors and outputs warnings and errors to the console: +```shell +$ erc7730 lint registry +checking registry/lido/calldata-stETH.json... + +checking registry/lido/calldata-wstETH.json... + +checking registry/makerdao/eip712-permit-DAI.json... +DEBUG: Optional Display field missing: Display field for path `nonce` is missing for message Permit. If intentionally excluded, please add +it to `exclude` list to avoid this warning. +WARNING: Missing Display field: Display field for path `owner` is missing for message Permit. If intentionally excluded, please add it to +`exclude` list to avoid this warning. +``` + +It can be called with single files or directories, in which case all descriptors will be checked. + +### `erc7730 convert` + +The `convert` command converts descriptors between the ERC-7730 format and the legacy formats used by Ledger, for +instance: +```shell +$ erc7730 convert eip712-to-erc7730 ledger-asset-dapps/ethereum/1inch/eip712.json erc7730-eip712-1inch.json +generated erc7730-eip712-1inch.0x119c71d3bbac22029622cbaec24854d3d32d2828.json ✅ +generated erc7730-eip712-1inch.0x111111125421ca6dc452d289314280a0f8842a65.json ✅ +``` + +Please run `erc7730 convert --help` for more information on the available options. diff --git a/docs/pages/usage_library.md b/docs/pages/usage_library.md new file mode 100644 index 00000000..680fccf0 --- /dev/null +++ b/docs/pages/usage_library.md @@ -0,0 +1,120 @@ +# Library usage + +## Installation + +The `erc7730` library is available as a [Python package on PyPI](https://pypi.org/project/erc7730). You can install it +using `pip`: + +```bash +pip install --user erc7730 +``` + +## Overview + +A typical usage of the `erc7730` library is to load descriptors and compile them to a wallet manufacturer-specific +format: + +```{mermaid} +--- +title: Node +--- +flowchart TD + input_json@{ shape: doc, label: "ERC-7730 descriptor file" } + input[input ERC-7730 descriptor] + resolved[resolved ERC-7730 descriptor] + vendor[wallet specific ERC-7730 descriptor] + input_json -- load/validate --> input + input -- resolve/validate --> resolved + resolved -- convert --> vendor +``` + +## Packages + +### `erc7730.model` + +The `erc7730.model` package implements an object model mapping for ERC-7730 descriptors using +[pydantic](https://docs.pydantic.dev), allowing to easily read/write/transform descriptors. + +#### input and resolved forms + +Descriptors can be manipulated in 2 forms: + - *"Input" form*: the descriptor document as defined in the ERC-7730 specification, after `include` tags have been + resolved. It is possible to save back the descriptor back to the original descriptor document. + - *"Resolved" form*: the descriptor after pre-processing: + - URLs have been fetched + - Contract addresses have been normalized to lowercase + - References have been inlined + - Constants have been inlined + - Field definitions have been inlined + - Selectors have been converted to 4 bytes form + This form is the most adapted to be used by tools and applications. + +```{eval-rst} +.. autosummary:: + :nosignatures: + + erc7730.model.input.descriptor.InputERC7730Descriptor + erc7730.model.resolved.descriptor.ResolvedERC7730Descriptor +``` + +#### input data model + +```{eval-rst} +.. autopydantic_model:: erc7730.model.input.descriptor.InputERC7730Descriptor + :noindex: + :model-show-config-summary: False + :model-show-field-summary: False + :model-erdantic-figure: True + :model-erdantic-figure-collapsed: False +``` + +#### resolved data model + +```{eval-rst} +.. autopydantic_model:: erc7730.model.resolved.descriptor.ResolvedERC7730Descriptor + :noindex: + :model-show-config-summary: False + :model-show-field-summary: False + :model-erdantic-figure: True + :model-erdantic-figure-collapsed: False +``` + +### `erc7730.lint` + +The `erc7730.lint` package implements the `erc7730 lint` command. The main interface is `ERC7730Linter`: + +```{eval-rst} +.. autoclass:: erc7730.lint.ERC7730Linter + :members: +``` + +The package contains several linter implementations: + +```{eval-rst} +.. autosummary:: + :nosignatures: + + erc7730.lint.lint_validate_abi.ValidateABILinter + erc7730.lint.lint_validate_display_fields.ValidateDisplayFieldsLinter + erc7730.lint.lint_transaction_type_classifier.ClassifyTransactionTypeLinter +``` + +### `erc7730.convert` + +The `erc7730.convert` package implements the `erc7730 convert` command. The main interface is `ERC7730Converter`: + +```{eval-rst} +.. autoclass:: erc7730.convert.ERC7730Converter + :members: +``` + +The package contains several converter implementations: + +```{eval-rst} +.. autosummary:: + :nosignatures: + + erc7730.convert.convert_erc7730_input_to_resolved.ERC7730InputToResolved + erc7730.convert.convert_eip712_to_erc7730.EIP712toERC7730Converter + erc7730.convert.convert_erc7730_to_eip712.ERC7730toEIP712Converter +``` diff --git a/docs/static/custom.css b/docs/static/custom.css new file mode 100644 index 00000000..bb87f391 --- /dev/null +++ b/docs/static/custom.css @@ -0,0 +1,31 @@ +@media (min-width: 1200px) { + .container { + max-width:1200px + } +} + +@media (min-width: 1400px) { + .container { + max-width:1400px + } +} + +@media (min-width: 1600px) { + .container { + max-width:1600px + } +} + +@media (min-width: 1800px) { + .container { + max-width:1800px + } +} + +#content ol, #content ul:not(.search) { + margin-top: 0.2rem; +} + +#content ol p, #content ol>li, #content ul:not(.search) p, #content ul:not(.search)>li { + margin-top: 0.2rem; +} diff --git a/docs/static/ledger-icon.png b/docs/static/ledger-icon.png new file mode 100644 index 00000000..ef35fc77 Binary files /dev/null and b/docs/static/ledger-icon.png differ diff --git a/docs/static/ledger-logo.png b/docs/static/ledger-logo.png new file mode 100644 index 00000000..88f66c3a Binary files /dev/null and b/docs/static/ledger-logo.png differ diff --git a/pdm.lock b/pdm.lock index f28880bd..9210c325 100644 --- a/pdm.lock +++ b/pdm.lock @@ -5,17 +5,28 @@ groups = ["default", "dev"] strategy = ["inherit_metadata"] lock_version = "4.5.0" -content_hash = "sha256:bc2fcca6db69d2fafbcfad69242ea2206ea9f9d677480b22d6cb3f2192d1c5f7" +content_hash = "sha256:f8506e44c931217a8f1f8bed448b421d208a01134803fada9c372d5f7186537a" [[metadata.targets]] requires_python = ">=3.12,<3.13" +[[package]] +name = "alabaster" +version = "1.0.0" +requires_python = ">=3.10" +summary = "A light, configurable Sphinx theme" +groups = ["dev"] +files = [ + {file = "alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b"}, + {file = "alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e"}, +] + [[package]] name = "annotated-types" version = "0.7.0" requires_python = ">=3.8" summary = "Reusable constraint types to use with typing.Annotated" -groups = ["default"] +groups = ["default", "dev"] dependencies = [ "typing-extensions>=4.0.0; python_version < \"3.9\"", ] @@ -38,6 +49,65 @@ files = [ {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, ] +[[package]] +name = "autodoc-pydantic" +version = "2.2.0" +requires_python = "<4.0.0,>=3.8.1" +summary = "Seamlessly integrate pydantic models in your Sphinx documentation." +groups = ["dev"] +dependencies = [ + "Sphinx>=4.0", + "importlib-metadata>1; python_version <= \"3.8\"", + "pydantic-settings<3.0.0,>=2.0", + "pydantic<3.0.0,>=2.0", +] +files = [ + {file = "autodoc_pydantic-2.2.0-py3-none-any.whl", hash = "sha256:8c6a36fbf6ed2700ea9c6d21ea76ad541b621fbdf16b5a80ee04673548af4d95"}, +] + +[[package]] +name = "autodoc-pydantic" +version = "2.2.0" +extras = ["erdantic"] +requires_python = "<4.0.0,>=3.8.1" +summary = "Seamlessly integrate pydantic models in your Sphinx documentation." +groups = ["dev"] +dependencies = [ + "autodoc-pydantic==2.2.0", + "erdantic<2.0", +] +files = [ + {file = "autodoc_pydantic-2.2.0-py3-none-any.whl", hash = "sha256:8c6a36fbf6ed2700ea9c6d21ea76ad541b621fbdf16b5a80ee04673548af4d95"}, +] + +[[package]] +name = "babel" +version = "2.16.0" +requires_python = ">=3.8" +summary = "Internationalization utilities" +groups = ["dev"] +dependencies = [ + "pytz>=2015.7; python_version < \"3.9\"", +] +files = [ + {file = "babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b"}, + {file = "babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316"}, +] + +[[package]] +name = "beautifulsoup4" +version = "4.12.3" +requires_python = ">=3.6.0" +summary = "Screen-scraping library" +groups = ["dev"] +dependencies = [ + "soupsieve>1.2", +] +files = [ + {file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"}, + {file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"}, +] + [[package]] name = "cattrs" version = "24.1.2" @@ -59,7 +129,7 @@ name = "certifi" version = "2024.8.30" requires_python = ">=3.6" summary = "Python package for providing Mozilla's CA Bundle." -groups = ["default"] +groups = ["default", "dev"] files = [ {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, @@ -81,7 +151,7 @@ name = "charset-normalizer" version = "3.3.2" requires_python = ">=3.7.0" summary = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -groups = ["default"] +groups = ["default", "dev"] files = [ {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, @@ -107,7 +177,7 @@ name = "click" version = "8.1.7" requires_python = ">=3.7" summary = "Composable command line interface toolkit" -groups = ["default"] +groups = ["default", "dev"] dependencies = [ "colorama; platform_system == \"Windows\"", "importlib-metadata; python_version < \"3.8\"", @@ -211,6 +281,17 @@ files = [ {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, ] +[[package]] +name = "docutils" +version = "0.21.2" +requires_python = ">=3.9" +summary = "Docutils -- Python Documentation Utilities" +groups = ["dev"] +files = [ + {file = "docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"}, + {file = "docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f"}, +] + [[package]] name = "eip712-clearsign" version = "2.1.0" @@ -225,6 +306,26 @@ files = [ {file = "eip712_clearsign-2.1.0.tar.gz", hash = "sha256:68b3636fe5dbc1363a67fb1d5816c6b3a4bc123273df1f2e2ff2b83c866ef034"}, ] +[[package]] +name = "erdantic" +version = "1.0.5" +requires_python = ">=3.8" +summary = "Entity relationship diagrams for Python data model classes like Pydantic." +groups = ["dev"] +dependencies = [ + "pydantic-core", + "pydantic>=2", + "pygraphviz", + "sortedcontainers-pydantic", + "typenames>=1.3", + "typer", + "typing-extensions>4; python_version < \"3.12\"", +] +files = [ + {file = "erdantic-1.0.5-py3-none-any.whl", hash = "sha256:f9ae0016d5e6116e14cf11b75c6a1ead467d7a13adbea9632df102199e22499a"}, + {file = "erdantic-1.0.5.tar.gz", hash = "sha256:e35cc1babb37b8dc62fc220ce61a167afaebd11e391c6bd53882918a3b01644b"}, +] + [[package]] name = "eth-hash" version = "0.7.0" @@ -347,12 +448,23 @@ name = "idna" version = "3.10" requires_python = ">=3.6" summary = "Internationalized Domain Names in Applications (IDNA)" -groups = ["default"] +groups = ["default", "dev"] files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] +[[package]] +name = "imagesize" +version = "1.4.1" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +summary = "Getting image size from png/jpeg/jpeg2000/gif file" +groups = ["dev"] +files = [ + {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"}, + {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, +] + [[package]] name = "iniconfig" version = "2.0.0" @@ -364,6 +476,20 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] +[[package]] +name = "jinja2" +version = "3.1.4" +requires_python = ">=3.7" +summary = "A very fast and expressive template engine." +groups = ["dev"] +dependencies = [ + "MarkupSafe>=2.0", +] +files = [ + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, +] + [[package]] name = "jsonschema" version = "4.23.0" @@ -409,6 +535,20 @@ files = [ {file = "lark-1.2.2.tar.gz", hash = "sha256:ca807d0162cd16cef15a8feecb862d7319e7a09bdb13aef927968e45040fed80"}, ] +[[package]] +name = "linkify-it-py" +version = "2.0.3" +requires_python = ">=3.7" +summary = "Links recognition library with FULL unicode support." +groups = ["dev"] +dependencies = [ + "uc-micro-py", +] +files = [ + {file = "linkify-it-py-2.0.3.tar.gz", hash = "sha256:68cda27e162e9215c17d786649d1da0021a451bdc436ef9e0fa0ba5234b9b048"}, + {file = "linkify_it_py-2.0.3-py3-none-any.whl", hash = "sha256:6bcbc417b0ac14323382aef5c5192c0075bf8a9d6b41820a2b66371eac6b6d79"}, +] + [[package]] name = "lsprotocol" version = "2023.0.1" @@ -429,7 +569,7 @@ name = "markdown-it-py" version = "3.0.0" requires_python = ">=3.8" summary = "Python port of markdown-it. Markdown parsing, done right!" -groups = ["default"] +groups = ["default", "dev"] dependencies = [ "mdurl~=0.1", ] @@ -438,17 +578,86 @@ files = [ {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, ] +[[package]] +name = "markupsafe" +version = "3.0.1" +requires_python = ">=3.9" +summary = "Safely add untrusted strings to HTML/XML markup." +groups = ["dev"] +files = [ + {file = "MarkupSafe-3.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8ae369e84466aa70f3154ee23c1451fda10a8ee1b63923ce76667e3077f2b0c4"}, + {file = "MarkupSafe-3.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40f1e10d51c92859765522cbd79c5c8989f40f0419614bcdc5015e7b6bf97fc5"}, + {file = "MarkupSafe-3.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a4cb365cb49b750bdb60b846b0c0bc49ed62e59a76635095a179d440540c346"}, + {file = "MarkupSafe-3.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee3941769bd2522fe39222206f6dd97ae83c442a94c90f2b7a25d847d40f4729"}, + {file = "MarkupSafe-3.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62fada2c942702ef8952754abfc1a9f7658a4d5460fabe95ac7ec2cbe0d02abc"}, + {file = "MarkupSafe-3.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4c2d64fdba74ad16138300815cfdc6ab2f4647e23ced81f59e940d7d4a1469d9"}, + {file = "MarkupSafe-3.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:fb532dd9900381d2e8f48172ddc5a59db4c445a11b9fab40b3b786da40d3b56b"}, + {file = "MarkupSafe-3.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0f84af7e813784feb4d5e4ff7db633aba6c8ca64a833f61d8e4eade234ef0c38"}, + {file = "MarkupSafe-3.0.1-cp312-cp312-win32.whl", hash = "sha256:cbf445eb5628981a80f54087f9acdbf84f9b7d862756110d172993b9a5ae81aa"}, + {file = "MarkupSafe-3.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:a10860e00ded1dd0a65b83e717af28845bb7bd16d8ace40fe5531491de76b79f"}, + {file = "markupsafe-3.0.1.tar.gz", hash = "sha256:3e683ee4f5d0fa2dde4db77ed8dd8a876686e3fc417655c2ece9a90576905344"}, +] + +[[package]] +name = "mdit-py-plugins" +version = "0.4.2" +requires_python = ">=3.8" +summary = "Collection of plugins for markdown-it-py" +groups = ["dev"] +dependencies = [ + "markdown-it-py<4.0.0,>=1.0.0", +] +files = [ + {file = "mdit_py_plugins-0.4.2-py3-none-any.whl", hash = "sha256:0c673c3f889399a33b95e88d2f0d111b4447bdfea7f237dab2d488f459835636"}, + {file = "mdit_py_plugins-0.4.2.tar.gz", hash = "sha256:5f2cd1fdb606ddf152d37ec30e46101a60512bc0e5fa1a7002c36647b09e26b5"}, +] + [[package]] name = "mdurl" version = "0.1.2" requires_python = ">=3.7" summary = "Markdown URL utilities" -groups = ["default"] +groups = ["default", "dev"] files = [ {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, ] +[[package]] +name = "myst-parser" +version = "4.0.0" +requires_python = ">=3.10" +summary = "An extended [CommonMark](https://spec.commonmark.org/) compliant parser," +groups = ["dev"] +dependencies = [ + "docutils<0.22,>=0.19", + "jinja2", + "markdown-it-py~=3.0", + "mdit-py-plugins>=0.4.1,~=0.4", + "pyyaml", + "sphinx<9,>=7", +] +files = [ + {file = "myst_parser-4.0.0-py3-none-any.whl", hash = "sha256:b9317997552424448c6096c2558872fdb6f81d3ecb3a40ce84a7518798f3f28d"}, + {file = "myst_parser-4.0.0.tar.gz", hash = "sha256:851c9dfb44e36e56d15d05e72f02b80da21a9e0d07cba96baf5e2d476bb91531"}, +] + +[[package]] +name = "myst-parser" +version = "4.0.0" +extras = ["linkify"] +requires_python = ">=3.10" +summary = "An extended [CommonMark](https://spec.commonmark.org/) compliant parser," +groups = ["dev"] +dependencies = [ + "linkify-it-py~=2.0", + "myst-parser==4.0.0", +] +files = [ + {file = "myst_parser-4.0.0-py3-none-any.whl", hash = "sha256:b9317997552424448c6096c2558872fdb6f81d3ecb3a40ce84a7518798f3f28d"}, + {file = "myst_parser-4.0.0.tar.gz", hash = "sha256:851c9dfb44e36e56d15d05e72f02b80da21a9e0d07cba96baf5e2d476bb91531"}, +] + [[package]] name = "networkx" version = "3.3" @@ -482,6 +691,17 @@ files = [ {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] +[[package]] +name = "pbr" +version = "6.1.0" +requires_python = ">=2.6" +summary = "Python Build Reasonableness" +groups = ["dev"] +files = [ + {file = "pbr-6.1.0-py2.py3-none-any.whl", hash = "sha256:a776ae228892d8013649c0aeccbb3d5f99ee15e005a4cbb7e61d55a067b28a2a"}, + {file = "pbr-6.1.0.tar.gz", hash = "sha256:788183e382e3d1d7707db08978239965e8b9e4e5ed42669bf4758186734d5f24"}, +] + [[package]] name = "platformdirs" version = "4.3.6" @@ -601,7 +821,7 @@ name = "pydantic" version = "2.9.2" requires_python = ">=3.8" summary = "Data validation using Python type hints" -groups = ["default"] +groups = ["default", "dev"] dependencies = [ "annotated-types>=0.6.0", "pydantic-core==2.23.4", @@ -618,7 +838,7 @@ name = "pydantic-core" version = "2.23.4" requires_python = ">=3.8" summary = "Core functionality for Pydantic validation and serialization" -groups = ["default"] +groups = ["default", "dev"] dependencies = [ "typing-extensions!=4.7.0,>=4.6.0", ] @@ -638,6 +858,21 @@ files = [ {file = "pydantic_core-2.23.4.tar.gz", hash = "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863"}, ] +[[package]] +name = "pydantic-settings" +version = "2.5.2" +requires_python = ">=3.8" +summary = "Settings management using Pydantic" +groups = ["dev"] +dependencies = [ + "pydantic>=2.7.0", + "python-dotenv>=0.21.0", +] +files = [ + {file = "pydantic_settings-2.5.2-py3-none-any.whl", hash = "sha256:2c912e55fd5794a59bf8c832b9de832dcfdf4778d79ff79b708744eed499a907"}, + {file = "pydantic_settings-2.5.2.tar.gz", hash = "sha256:f90b139682bee4d2065273d5185d71d37ea46cfe57e1b5ae184fc6a0b2484ca0"}, +] + [[package]] name = "pygls" version = "1.3.1" @@ -658,12 +893,22 @@ name = "pygments" version = "2.18.0" requires_python = ">=3.8" summary = "Pygments is a syntax highlighting package written in Python." -groups = ["default"] +groups = ["default", "dev"] files = [ {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, ] +[[package]] +name = "pygraphviz" +version = "1.14" +requires_python = ">=3.10" +summary = "Python interface to Graphviz" +groups = ["dev"] +files = [ + {file = "pygraphviz-1.14.tar.gz", hash = "sha256:c10df02377f4e39b00ae17c862f4ee7e5767317f1c6b2dfd04cea6acc7fc2bea"}, +] + [[package]] name = "pytest" version = "8.3.3" @@ -830,6 +1075,17 @@ files = [ {file = "pytest_xdist-3.6.1.tar.gz", hash = "sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d"}, ] +[[package]] +name = "python-dotenv" +version = "1.0.1" +requires_python = ">=3.8" +summary = "Read key-value pairs from a .env file and set them as environment variables" +groups = ["dev"] +files = [ + {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"}, + {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"}, +] + [[package]] name = "pyyaml" version = "6.0.2" @@ -869,7 +1125,7 @@ name = "requests" version = "2.32.3" requires_python = ">=3.8" summary = "Python HTTP for Humans." -groups = ["default"] +groups = ["default", "dev"] dependencies = [ "certifi>=2017.4.17", "charset-normalizer<4,>=2", @@ -886,7 +1142,7 @@ name = "rich" version = "13.9.2" requires_python = ">=3.8.0" summary = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" -groups = ["default"] +groups = ["default", "dev"] dependencies = [ "markdown-it-py>=2.2.0", "pygments<3.0.0,>=2.13.0", @@ -981,12 +1237,254 @@ name = "shellingham" version = "1.5.4" requires_python = ">=3.7" summary = "Tool to Detect Surrounding Shell" -groups = ["default"] +groups = ["default", "dev"] files = [ {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, ] +[[package]] +name = "snowballstemmer" +version = "2.2.0" +summary = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." +groups = ["dev"] +files = [ + {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, + {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, +] + +[[package]] +name = "sortedcontainers" +version = "2.4.0" +summary = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" +groups = ["dev"] +files = [ + {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"}, + {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, +] + +[[package]] +name = "sortedcontainers-pydantic" +version = "1.0.0" +requires_python = ">=3.8" +summary = "Pydantic support for the sortedcontainers package." +groups = ["dev"] +dependencies = [ + "pydantic-core", + "pydantic>=2", + "sortedcontainers", +] +files = [ + {file = "sortedcontainers_pydantic-1.0.0-py3-none-any.whl", hash = "sha256:07e92e9b85dbf9248e0a5b59e0311a095e6fb27e0dc461b1209ead5a550b60b2"}, + {file = "sortedcontainers_pydantic-1.0.0.tar.gz", hash = "sha256:eb0e4aeb5197d690165f0a7b1a55c490eabe4b21375c3a91726373b2551e25ee"}, +] + +[[package]] +name = "soupsieve" +version = "2.6" +requires_python = ">=3.8" +summary = "A modern CSS selector implementation for Beautiful Soup." +groups = ["dev"] +files = [ + {file = "soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9"}, + {file = "soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb"}, +] + +[[package]] +name = "sphinx" +version = "8.0.2" +requires_python = ">=3.10" +summary = "Python documentation generator" +groups = ["dev"] +dependencies = [ + "Jinja2>=3.1", + "Pygments>=2.17", + "alabaster>=0.7.14", + "babel>=2.13", + "colorama>=0.4.6; sys_platform == \"win32\"", + "docutils<0.22,>=0.20", + "imagesize>=1.3", + "packaging>=23.0", + "requests>=2.30.0", + "snowballstemmer>=2.2", + "sphinxcontrib-applehelp", + "sphinxcontrib-devhelp", + "sphinxcontrib-htmlhelp>=2.0.0", + "sphinxcontrib-jsmath", + "sphinxcontrib-qthelp", + "sphinxcontrib-serializinghtml>=1.1.9", + "tomli>=2; python_version < \"3.11\"", +] +files = [ + {file = "sphinx-8.0.2-py3-none-any.whl", hash = "sha256:56173572ae6c1b9a38911786e206a110c9749116745873feae4f9ce88e59391d"}, + {file = "sphinx-8.0.2.tar.gz", hash = "sha256:0cce1ddcc4fd3532cf1dd283bc7d886758362c5c1de6598696579ce96d8ffa5b"}, +] + +[[package]] +name = "sphinx-design" +version = "0.6.1" +requires_python = ">=3.9" +summary = "A sphinx extension for designing beautiful, view size responsive web components." +groups = ["dev"] +dependencies = [ + "sphinx<9,>=6", +] +files = [ + {file = "sphinx_design-0.6.1-py3-none-any.whl", hash = "sha256:b11f37db1a802a183d61b159d9a202314d4d2fe29c163437001324fe2f19549c"}, + {file = "sphinx_design-0.6.1.tar.gz", hash = "sha256:b44eea3719386d04d765c1a8257caca2b3e6f8421d7b3a5e742c0fd45f84e632"}, +] + +[[package]] +name = "sphinx-github-style" +version = "1.2.2" +summary = "GitHub source code links and syntax highlighting for Sphinx documentation" +groups = ["dev"] +dependencies = [ + "sphinx>=1.8", +] +files = [ + {file = "sphinx-github-style-1.2.2.tar.gz", hash = "sha256:aad6231fcc0a4f59df82531eb3a82dda8a461a94d9e304895c34ac1158d7347c"}, + {file = "sphinx_github_style-1.2.2-py3-none-any.whl", hash = "sha256:8f6fd1a2c1a5878428a010050549c8353354a1ca9650f6bb01049c649935677d"}, +] + +[[package]] +name = "sphinx-issues" +version = "4.1.0" +requires_python = ">=3.8" +summary = "A Sphinx extension for linking to your project's issue tracker" +groups = ["dev"] +dependencies = [ + "sphinx", +] +files = [ + {file = "sphinx_issues-4.1.0-py3-none-any.whl", hash = "sha256:d779dddff441175c9fddb7a4018eca38f9f6cdb1e0a2fe31d93b4f89587c7ba1"}, + {file = "sphinx_issues-4.1.0.tar.gz", hash = "sha256:a67f7ef31d164b420b2f21b6c9b020baeb4a014afd4045f5be314c984e8ee520"}, +] + +[[package]] +name = "sphinxawesome-theme" +version = "5.3.1" +requires_python = "<4.0,>=3.8" +summary = "An awesome theme for the Sphinx documentation generator" +groups = ["dev"] +dependencies = [ + "beautifulsoup4<5.0.0,>=4.9.1", + "sphinx<7.2; python_version >= \"3.8\" and python_version < \"3.9\"", + "sphinx<7.5,>=7.2; python_version >= \"3.9\" and python_version < \"3.10\"", + "sphinx<9,>=8; python_version >= \"3.10\" and python_version < \"3.13\"", +] +files = [ + {file = "sphinxawesome_theme-5.3.1-py3-none-any.whl", hash = "sha256:d34f276f9785138cf9bb60d3a7294e5bdb93118989e8965ed0d9fee691d7702a"}, + {file = "sphinxawesome_theme-5.3.1.tar.gz", hash = "sha256:91d4df71c55f7e6a4a617efe61f2267339ff63c56f39bec8b7b192b504f118c4"}, +] + +[[package]] +name = "sphinxcontrib-apidoc" +version = "0.5.0" +requires_python = ">=3.8" +summary = "A Sphinx extension for running 'sphinx-apidoc' on each build" +groups = ["dev"] +dependencies = [ + "Sphinx>=5.0.0", + "pbr", +] +files = [ + {file = "sphinxcontrib-apidoc-0.5.0.tar.gz", hash = "sha256:65efcd92212a5f823715fb95ee098b458a6bb09a5ee617d9ed3dead97177cd55"}, + {file = "sphinxcontrib_apidoc-0.5.0-py3-none-any.whl", hash = "sha256:c671d644d6dc468be91b813dcddf74d87893bff74fe8f1b8b01b69408f0fb776"}, +] + +[[package]] +name = "sphinxcontrib-applehelp" +version = "2.0.0" +requires_python = ">=3.9" +summary = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" +groups = ["dev"] +files = [ + {file = "sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5"}, + {file = "sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1"}, +] + +[[package]] +name = "sphinxcontrib-devhelp" +version = "2.0.0" +requires_python = ">=3.9" +summary = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents" +groups = ["dev"] +files = [ + {file = "sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2"}, + {file = "sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad"}, +] + +[[package]] +name = "sphinxcontrib-htmlhelp" +version = "2.1.0" +requires_python = ">=3.9" +summary = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" +groups = ["dev"] +files = [ + {file = "sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8"}, + {file = "sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9"}, +] + +[[package]] +name = "sphinxcontrib-jsmath" +version = "1.0.1" +requires_python = ">=3.5" +summary = "A sphinx extension which renders display math in HTML via JavaScript" +groups = ["dev"] +files = [ + {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, + {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, +] + +[[package]] +name = "sphinxcontrib-mermaid" +version = "0.9.2" +requires_python = ">=3.7" +summary = "Mermaid diagrams in yours Sphinx powered docs" +groups = ["dev"] +files = [ + {file = "sphinxcontrib-mermaid-0.9.2.tar.gz", hash = "sha256:252ef13dd23164b28f16d8b0205cf184b9d8e2b714a302274d9f59eb708e77af"}, + {file = "sphinxcontrib_mermaid-0.9.2-py3-none-any.whl", hash = "sha256:6795a72037ca55e65663d2a2c1a043d636dc3d30d418e56dd6087d1459d98a5d"}, +] + +[[package]] +name = "sphinxcontrib-qthelp" +version = "2.0.0" +requires_python = ">=3.9" +summary = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents" +groups = ["dev"] +files = [ + {file = "sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb"}, + {file = "sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab"}, +] + +[[package]] +name = "sphinxcontrib-serializinghtml" +version = "2.0.0" +requires_python = ">=3.9" +summary = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)" +groups = ["dev"] +files = [ + {file = "sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331"}, + {file = "sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d"}, +] + +[[package]] +name = "sphinxcontrib-typer" +version = "0.5.0" +requires_python = "<4.0,>=3.9" +summary = "Auto generate docs for typer commands." +groups = ["dev"] +dependencies = [ + "sphinx>=5.0.0", + "typer-slim[standard]<1.0.0,>=0.12.0", +] +files = [ + {file = "sphinxcontrib_typer-0.5.0-py3-none-any.whl", hash = "sha256:780ca6b5f85105e5f8a1d2168fd490a6411c209e2a8e2ec84d387f0d6fba0ce1"}, + {file = "sphinxcontrib_typer-0.5.0.tar.gz", hash = "sha256:cc8937020bd804deb3f5abd5628c0e39cc2859e1a076307c1397b42594c4d33b"}, +] + [[package]] name = "termcolor" version = "2.4.0" @@ -1010,12 +1508,23 @@ files = [ {file = "toolz-0.12.1.tar.gz", hash = "sha256:ecca342664893f177a13dac0e6b41cbd8ac25a358e5f215316d43e2100224f4d"}, ] +[[package]] +name = "typenames" +version = "1.3.0" +requires_python = ">=3.8" +summary = "String representations of type annotations." +groups = ["dev"] +files = [ + {file = "typenames-1.3.0-py3-none-any.whl", hash = "sha256:666dfd7baebe3675dbdf950f19de08d5b15e5f9e0a71fe91fb8135ea68fe0889"}, + {file = "typenames-1.3.0.tar.gz", hash = "sha256:205a1954512e28b6558e761c134e74d243003755676fe8cce49250b8fc192798"}, +] + [[package]] name = "typer" version = "0.12.5" requires_python = ">=3.7" summary = "Typer, build great CLIs. Easy to code. Based on Python type hints." -groups = ["default"] +groups = ["default", "dev"] dependencies = [ "click>=8.0.0", "rich>=10.11.0", @@ -1027,6 +1536,38 @@ files = [ {file = "typer-0.12.5.tar.gz", hash = "sha256:f592f089bedcc8ec1b974125d64851029c3b1af145f04aca64d69410f0c9b722"}, ] +[[package]] +name = "typer-slim" +version = "0.12.5" +requires_python = ">=3.7" +summary = "Typer, build great CLIs. Easy to code. Based on Python type hints." +groups = ["dev"] +dependencies = [ + "click>=8.0.0", + "typing-extensions>=3.7.4.3", +] +files = [ + {file = "typer_slim-0.12.5-py3-none-any.whl", hash = "sha256:9a994f721b828783dbf144e17461b1c720bb4598e0d5eff7c1b3f08ee58cb062"}, + {file = "typer_slim-0.12.5.tar.gz", hash = "sha256:c8e3fcf93cc7dd584036df8755d2e2363f85f8a4dd028c7911eed3f00cf0ebb1"}, +] + +[[package]] +name = "typer-slim" +version = "0.12.5" +extras = ["standard"] +requires_python = ">=3.7" +summary = "Typer, build great CLIs. Easy to code. Based on Python type hints." +groups = ["dev"] +dependencies = [ + "rich>=10.11.0", + "shellingham>=1.3.0", + "typer-slim==0.12.5", +] +files = [ + {file = "typer_slim-0.12.5-py3-none-any.whl", hash = "sha256:9a994f721b828783dbf144e17461b1c720bb4598e0d5eff7c1b3f08ee58cb062"}, + {file = "typer_slim-0.12.5.tar.gz", hash = "sha256:c8e3fcf93cc7dd584036df8755d2e2363f85f8a4dd028c7911eed3f00cf0ebb1"}, +] + [[package]] name = "typing-extensions" version = "4.12.2" @@ -1038,12 +1579,23 @@ files = [ {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] +[[package]] +name = "uc-micro-py" +version = "1.0.3" +requires_python = ">=3.7" +summary = "Micro subset of unicode data files for linkify-it-py projects." +groups = ["dev"] +files = [ + {file = "uc-micro-py-1.0.3.tar.gz", hash = "sha256:d321b92cff673ec58027c04015fcaa8bb1e005478643ff4a500882eaab88c48a"}, + {file = "uc_micro_py-1.0.3-py3-none-any.whl", hash = "sha256:db1dffff340817673d7b466ec86114a9dc0e9d4d9b5ba229d9d60e5c12600cd5"}, +] + [[package]] name = "urllib3" version = "2.2.3" requires_python = ">=3.8" summary = "HTTP library with thread-safe connection pooling, file post, and more." -groups = ["default"] +groups = ["default", "dev"] files = [ {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, diff --git a/pyproject.toml b/pyproject.toml index 6ebd8b68..4f01655b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,6 +48,8 @@ lint.help = "Run all linters/formatters (automatically run by pre-commit)" lint.shell = "pre-commit run --all-files" test.help = "Run unit/integration tests suite" test.shell = "pytest tests" +docs.help = "Build documentation (output is at docs/build/index.html)" +docs.shell = "sphinx-build docs docs/build" all.help = "Run lint+test" all.shell = { composite = ["lint", "test"] } exe.help = "Package the application into a standalone executable" @@ -70,6 +72,16 @@ dev = [ "pytest-unordered>=0.6.1", "pytest-raises>=0.11", "pytest-datadir-ng>=1.1.1", + "sphinx>=7.3.7", + "sphinxcontrib-apidoc>=0.5.0", + "sphinxcontrib-typer>=0.5.0", + "sphinxcontrib-mermaid>=0.9.2", + "sphinxawesome-theme>=5.2.0", + "sphinx-github-style>=1.2.2", + "sphinx-design>=0.6.1", + "sphinx-issues>=4.1.0", + "autodoc-pydantic[erdantic]>=2.2.0", + "myst-parser[linkify]>=4.0.0", "ruff>=0.6.3", "ruff-lsp>=0.0.55", "prettydiff[terminal]>=0.1.0",