├── .github ├── FUNDING.yml └── workflows │ ├── deploy.yml │ ├── linters.yml │ └── tests.yml ├── .gitignore ├── .pre-commit-config.yaml ├── LICENSE ├── README.md ├── parse2docs ├── __init__.py ├── app.py ├── argfinder.py ├── markdown_renderer.py └── module_loader.py ├── poetry.lock ├── pyproject.toml └── tests ├── __init__.py ├── demo_parser_in_function.py ├── demo_parser_in_module.py ├── test_argfinder.py ├── test_markdown_renderer.py └── test_module_loader.py /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [MrCordeiro] 4 | custom: [https://paypal.me/FernCordeiro} 5 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to PyPI 2 | 3 | on: 4 | workflow_dispatch: 5 | release: 6 | types: [created] 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v3 14 | 15 | - name: Set up Python 16 | uses: actions/setup-python@v4 17 | with: 18 | python-version: "3.11" 19 | 20 | - name: Install poetry 21 | run: curl -sSL https://install.python-poetry.org | python3 - 22 | 23 | - name: Configure poetry 24 | run: | 25 | poetry config virtualenvs.create false 26 | poetry config pypi-token.pypi ${{ secrets.PYPI_API_TOKEN }} 27 | 28 | - name: Install project dependencies 29 | run: poetry install 30 | 31 | - name: Publish package 32 | run: poetry publish --build --no-interaction 33 | -------------------------------------------------------------------------------- /.github/workflows/linters.yml: -------------------------------------------------------------------------------- 1 | name: Linters 2 | 3 | on: 4 | push: 5 | branches: 6 | - "main" 7 | - "master" 8 | pull_request: 9 | types: [opened, synchronize, reopened] 10 | 11 | concurrency: 12 | group: ${{ github.workflow }}-${{ github.ref }} 13 | cancel-in-progress: true 14 | 15 | jobs: 16 | 17 | linters: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v3 22 | 23 | - name: Set up Python 24 | uses: actions/setup-python@v4 25 | with: 26 | python-version: '3.11' 27 | 28 | - name: Install linters 29 | run: | 30 | python -m pip install --upgrade pip 31 | python -m pip install isort 32 | 33 | - name: isort 34 | uses: isort/isort-action@master 35 | with: 36 | configuration: --check-only --diff --profile black 37 | 38 | - name: black 39 | uses: psf/black@stable 40 | 41 | - name: ruff 42 | uses: jpetrucciani/ruff-check@main 43 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - "main" 7 | - "master" 8 | pull_request: 9 | types: [opened, synchronize, reopened] 10 | 11 | env: 12 | PROJECT_ID: "testing_project" 13 | 14 | concurrency: 15 | group: ${{ github.workflow }}-${{ github.ref }} 16 | cancel-in-progress: true 17 | 18 | permissions: 19 | pull-requests: write 20 | issues: write 21 | repository-projects: write 22 | contents: read 23 | 24 | jobs: 25 | tests: 26 | runs-on: ubuntu-latest 27 | steps: 28 | - name: Checkout 29 | uses: actions/checkout@v3 30 | 31 | - name: Set up Python 32 | uses: actions/setup-python@v4 33 | with: 34 | python-version: '3.11' 35 | 36 | - name: Install workflow dependencies 37 | shell: bash 38 | run: | 39 | python -m pip install --upgrade pip 40 | python -m pip install pytest pytest-cov coverage[toml] 41 | 42 | - name: Install project dependencies 43 | shell: bash 44 | run: | 45 | curl -sSL https://install.python-poetry.org | python3 - 46 | poetry config virtualenvs.create false 47 | poetry install 48 | 49 | - name: Run Tests 50 | run: | 51 | pytest . --cov 52 | coverage report 53 | coverage xml 54 | 55 | - name: Coverage Summary Report 56 | uses: irongut/CodeCoverageSummary@v1.0.2 57 | with: 58 | filename: coverage.xml 59 | badge: true 60 | format: 'markdown' 61 | output: 'both' 62 | 63 | - name: Add Coverage PR Comment 64 | uses: marocchino/sticky-pull-request-comment@v2 65 | if: github.event_name == 'pull_request' 66 | with: 67 | recreate: true 68 | path: code-coverage-results.md 69 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### JupyterNotebooks ### 2 | # gitignore template for Jupyter Notebooks 3 | # website: http://jupyter.org/ 4 | 5 | .ipynb_checkpoints 6 | */.ipynb_checkpoints/* 7 | 8 | # IPython 9 | profile_default/ 10 | ipython_config.py 11 | 12 | # Remove previous ipynb_checkpoints 13 | # git rm -r .ipynb_checkpoints/ 14 | 15 | ### Linux ### 16 | *~ 17 | 18 | # temporary files which can be created if a process still has a handle open of a deleted file 19 | .fuse_hidden* 20 | 21 | # KDE directory preferences 22 | .directory 23 | 24 | # Linux trash folder which might appear on any partition or disk 25 | .Trash-* 26 | 27 | # .nfs files are created when an open file is removed but is still being accessed 28 | .nfs* 29 | 30 | ### Python ### 31 | # Byte-compiled / optimized / DLL files 32 | __pycache__/ 33 | *.py[cod] 34 | *$py.class 35 | 36 | # C extensions 37 | *.so 38 | 39 | # Distribution / packaging 40 | .Python 41 | build/ 42 | develop-eggs/ 43 | dist/ 44 | downloads/ 45 | eggs/ 46 | .eggs/ 47 | lib/ 48 | lib64/ 49 | parts/ 50 | sdist/ 51 | var/ 52 | wheels/ 53 | share/python-wheels/ 54 | *.egg-info/ 55 | .installed.cfg 56 | *.egg 57 | MANIFEST 58 | 59 | # PyInstaller 60 | # Usually these files are written by a python script from a template 61 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 62 | *.manifest 63 | *.spec 64 | 65 | # Installer logs 66 | pip-log.txt 67 | pip-delete-this-directory.txt 68 | 69 | # Unit test / coverage reports 70 | htmlcov/ 71 | .tox/ 72 | .nox/ 73 | .coverage 74 | .coverage.* 75 | .cache 76 | nosetests.xml 77 | coverage.xml 78 | *.cover 79 | *.py,cover 80 | .hypothesis/ 81 | .pytest_cache/ 82 | cover/ 83 | 84 | # Translations 85 | *.mo 86 | *.pot 87 | 88 | # Django stuff: 89 | *.log 90 | local_settings.py 91 | db.sqlite3 92 | db.sqlite3-journal 93 | 94 | # Flask stuff: 95 | instance/ 96 | .webassets-cache 97 | 98 | # Scrapy stuff: 99 | .scrapy 100 | 101 | # Sphinx documentation 102 | docs/_build/ 103 | 104 | # PyBuilder 105 | .pybuilder/ 106 | target/ 107 | 108 | # Jupyter Notebook 109 | 110 | # IPython 111 | 112 | # pyenv 113 | # For a library or package, you might want to ignore these files since the code is 114 | # intended to run in multiple environments; otherwise, check them in: 115 | .python-version 116 | 117 | # pipenv 118 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 119 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 120 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 121 | # install all needed dependencies. 122 | #Pipfile.lock 123 | 124 | # poetry 125 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 126 | # This is especially recommended for binary packages to ensure reproducibility, and is more 127 | # commonly ignored for libraries. 128 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 129 | #poetry.lock 130 | 131 | # pdm 132 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 133 | #pdm.lock 134 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 135 | # in version control. 136 | # https://pdm.fming.dev/#use-with-ide 137 | .pdm.toml 138 | 139 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 140 | __pypackages__/ 141 | 142 | # Celery stuff 143 | celerybeat-schedule 144 | celerybeat.pid 145 | 146 | # SageMath parsed files 147 | *.sage.py 148 | 149 | # Environments 150 | .env 151 | .venv 152 | env/ 153 | venv/ 154 | *venv/ 155 | ENV/ 156 | env.bak/ 157 | venv.bak/ 158 | 159 | # Spyder project settings 160 | .spyderproject 161 | .spyproject 162 | 163 | # Rope project settings 164 | .ropeproject 165 | 166 | # mkdocs documentation 167 | /site 168 | 169 | # mypy 170 | .mypy_cache/ 171 | .dmypy.json 172 | dmypy.json 173 | 174 | # Pyre type checker 175 | .pyre/ 176 | 177 | # pytype static type analyzer 178 | .pytype/ 179 | 180 | # Cython debug symbols 181 | cython_debug/ 182 | 183 | # PyCharm 184 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 185 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 186 | # and can be added to the global gitignore or merged into this file. For a more nuclear 187 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 188 | #.idea/ 189 | 190 | ### Python Patch ### 191 | # Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration 192 | poetry.toml 193 | 194 | # ruff 195 | .ruff_cache/ 196 | 197 | # LSP config files 198 | pyrightconfig.json 199 | 200 | ### VisualStudioCode ### 201 | .vscode/* 202 | !.vscode/tasks.json 203 | !.vscode/launch.json 204 | !.vscode/extensions.json 205 | !.vscode/*.code-snippets 206 | 207 | # Local History for Visual Studio Code 208 | .history/ 209 | 210 | # Built Visual Studio Code Extensions 211 | *.vsix 212 | 213 | ### VisualStudioCode Patch ### 214 | # Ignore all local history of files 215 | .history 216 | .ionide 217 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | default_language_version: 2 | python: python3 3 | repos: 4 | - repo: https://github.com/pre-commit/pre-commit-hooks 5 | rev: v4.4.0 6 | hooks: 7 | - id: check-ast 8 | - id: check-merge-conflict 9 | - id: check-case-conflict 10 | - id: detect-private-key 11 | - id: check-added-large-files 12 | - id: check-json 13 | - id: check-symlinks 14 | - id: check-toml 15 | - id: trailing-whitespace 16 | 17 | - repo: https://github.com/psf/black 18 | rev: 24.3.0 19 | hooks: 20 | - id: black 21 | 22 | - repo: https://github.com/pycqa/isort 23 | rev: 5.12.0 24 | hooks: 25 | - id: isort 26 | name: isort (python) 27 | args: ["--profile", "black"] 28 | 29 | - repo: https://github.com/charliermarsh/ruff-pre-commit 30 | rev: v0.0.262 31 | hooks: 32 | - id: ruff 33 | 34 | - repo: https://github.com/asottile/pyupgrade 35 | rev: v3.3.1 36 | hooks: 37 | - id: pyupgrade 38 | args: 39 | - --py311-plus 40 | exclude: migrations/ 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 MrCordeiro 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Parse 2 Docs 2 | 3 | ![PyPI](https://img.shields.io/pypi/v/parse2docs) 4 | [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) 5 | [![Tests](https://github.com/MrCordeiro/parse2docs/actions/workflows/tests.yml/badge.svg)](https://github.com/MrCordeiro/parse2docs/actions/workflows/tests.yml) 6 | [![Linters](https://github.com/MrCordeiro/parse2docs/actions/workflows/linters.yml/badge.svg)](https://github.com/MrCordeiro/parse2docs/actions/workflows/linters.yml) 7 | 8 | `parse2docs` is a Python library that allows you to automatically generate usage documentation in Markdown format from Python scripts using the `argparse` module. 9 | 10 | ## Features 11 | 12 | * Scans the Python script for instances of `argparse.ArgumentParser`. 13 | * Generates a Markdown file with usage documentation based on the `ArgumentParser` object. 14 | * The generated documentation includes a table of contents, descriptions of each command line argument, and examples if provided. 15 | * Works with `ArgumentParser` instances declared at the module level or returned by functions. 16 | 17 | ## Installation 18 | 19 | `parse2docs` can be installed via `pip`: 20 | 21 | ```shell 22 | pip install parse2docs 23 | ``` 24 | 25 | ## Usage 26 | 27 | There are two ways to use parse2docs, either as a Python module in your script or directly from the command line using the provided command. 28 | 29 | ### As a Python module 30 | 31 | ```python 32 | import parse2docs 33 | 34 | # Path to the Python script 35 | script_path = 'path_to_your_python_script.py' 36 | 37 | # Generate markdown documentation 38 | markdown = parse2docs.generate_md_from_py_script(script_path) 39 | 40 | # Save the markdown to a .md file 41 | with open('output.md', 'w') as f: 42 | f.write(markdown) 43 | ``` 44 | 45 | This will generate a `output.md` file with the usage documentation in Markdown format. 46 | 47 | ### From the command line 48 | 49 | #### Description 50 | 51 | The following usage section was generated using `parse2docs` 😉: 52 | 53 | ```md 54 | ## Overall Usage Example 55 | 56 | `example.py ` 57 | 58 | ## Table of Contents 59 | 60 | * [file_path](#file_path) 61 | 62 | ## Options 63 | 64 | ### file_path 65 | 66 | Path to the Python script file containing the ArgumentParser. 67 | 68 | **Type**: `Path` 69 | 70 | **Required**: Yes 71 | ``` 72 | 73 | This will print the usage documentation in Markdown format to the console. 74 | 75 | ## Testing 76 | 77 | We use `pytest` for testing. Run the tests with the following command: 78 | 79 | ```bash 80 | python -m pytest tests/ 81 | ``` 82 | 83 | ## Contributing 84 | 85 | Contributions to `parse2docs` are welcome and awesome! Please submit a pull request or open an issue to discuss potential changes or improvements. 86 | -------------------------------------------------------------------------------- /parse2docs/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCordeiro/parse2docs/ff0a1aec98359e2e4cf6542d2e3e39956335882c/parse2docs/__init__.py -------------------------------------------------------------------------------- /parse2docs/app.py: -------------------------------------------------------------------------------- 1 | """Entry point for parse2docs.""" 2 | 3 | import logging 4 | import os 5 | from argparse import ArgumentParser 6 | from pathlib import Path 7 | 8 | from parse2docs.argfinder import get_argparser_from_module 9 | from parse2docs.markdown_renderer import generate_markdown 10 | from parse2docs.module_loader import get_module_from_path 11 | 12 | logger = logging.getLogger(__name__) 13 | 14 | 15 | def execute_from_command_line() -> None: 16 | """Execute parse2docs from the command line.""" 17 | parser = get_argument_parser() 18 | args = parser.parse_args() 19 | md = generate_md_from_py_script(args.file_path) 20 | print(md) 21 | 22 | 23 | def get_argument_parser() -> ArgumentParser: 24 | """Get the ArgumentParser for parse2docs.""" 25 | arg_parser = ArgumentParser() 26 | arg_parser.add_argument( 27 | "file_path", 28 | help="Path to the Python script file containing the ArgumentParser.", 29 | type=Path, 30 | ) 31 | return arg_parser 32 | 33 | 34 | def generate_md_from_py_script(file_path: str) -> str: 35 | """Generate usage documentation in Markdown format. 36 | 37 | Args: 38 | file_path (str): Path to the Python script file containing the 39 | ArgumentParser. 40 | 41 | Returns: 42 | str: A string of the usage documentation in Markdown format. 43 | 44 | Raises: 45 | ValueError: If the provided file path does not exist. 46 | """ 47 | if not os.path.isfile(file_path): 48 | raise ValueError(f"File {file_path} does not exist.") 49 | 50 | module = get_module_from_path(file_path) 51 | parser = get_argparser_from_module(module) 52 | return generate_markdown(parser) 53 | 54 | 55 | if __name__ == "__main__": 56 | execute_from_command_line() 57 | -------------------------------------------------------------------------------- /parse2docs/argfinder.py: -------------------------------------------------------------------------------- 1 | """Module for finding ArgumentParser objects in Python scripts.""" 2 | 3 | import inspect 4 | from argparse import ArgumentParser 5 | from types import ModuleType 6 | 7 | 8 | def get_argparser_from_module(module: ModuleType) -> ArgumentParser: 9 | """Find ArgumentParser in a given module. 10 | 11 | This function first looks for argparse.ArgumentParser instances in the 12 | module scope. If it doesn't find any, it then looks for functions that take 13 | no parameters, executes them, and checks if they return an 14 | argparse.ArgumentParser instance. 15 | 16 | Returns: 17 | ArgumentParser: ArgumentParser object from the Python script file. 18 | 19 | Raises: 20 | ValueError: If no ArgumentParser object is found in the provided file. 21 | """ 22 | 23 | search_functions = [_find_parser_in_scope, _find_parser_in_functions] 24 | parser = next((func(module) for func in search_functions if func(module)), None) 25 | 26 | if parser is None: 27 | raise ValueError("No ArgumentParser object found in the provided file.") 28 | 29 | return parser 30 | 31 | 32 | def _find_parser_in_scope(module: ModuleType) -> ArgumentParser | None: 33 | for _, obj in inspect.getmembers(module): 34 | if isinstance(obj, ArgumentParser): 35 | return obj 36 | 37 | 38 | def _find_parser_in_functions(module: ModuleType) -> ArgumentParser | None: 39 | for _, obj in inspect.getmembers(module): 40 | # We only care about functions 41 | if not inspect.isfunction(obj): 42 | continue 43 | 44 | try: 45 | # We only care about functions that take no parameters 46 | if len(inspect.signature(obj).parameters) > 0: 47 | continue 48 | result = obj() 49 | if isinstance(result, ArgumentParser): 50 | return result 51 | # If we can't inspect the function, just skip it 52 | except TypeError: 53 | pass 54 | -------------------------------------------------------------------------------- /parse2docs/markdown_renderer.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from argparse import Action, ArgumentParser, FileType 3 | from pathlib import Path 4 | 5 | 6 | def generate_markdown(parser: ArgumentParser) -> str: 7 | """Generate markdown from argparse object. 8 | 9 | Args: 10 | parser (ArgumentParser): argparse.ArgumentParser object. 11 | 12 | Returns: 13 | str: A string of the usage documentation in Markdown format. 14 | """ 15 | markdown_string = "# Usage Documentation\n\n" 16 | markdown_string += _add_description(parser) 17 | markdown_string += _add_overall_usage(parser) 18 | markdown_string += _add_table_of_contents(parser) 19 | 20 | action_docs = [ 21 | _document_action(action) for action in parser._actions if action.dest != "help" 22 | ] 23 | if action_docs: 24 | markdown_string += "## Options\n\n" 25 | 26 | markdown_string += "".join(action_docs) 27 | 28 | return markdown_string 29 | 30 | 31 | def _add_description(parser) -> str: 32 | return f"## Description\n\n{parser.description}\n\n" 33 | 34 | 35 | def _add_table_of_contents(parser: ArgumentParser) -> str: 36 | contents = "## Table of Contents\n\n" 37 | for action in parser._actions: 38 | if action.dest == "help": 39 | continue 40 | contents += f"- [{action.dest}](#{action.dest})\n" 41 | contents += "\n" 42 | return contents 43 | 44 | 45 | def _document_action(action: Action) -> str: 46 | doc = f"### {action.dest}\n\n" 47 | doc += f"{action.help}\n\n" 48 | 49 | if action.option_strings: 50 | doc += f"**Flags**: `{', '.join(action.option_strings)}`\n\n" 51 | 52 | if isinstance(action.type, FileType): 53 | doc += "**Type**: `file` \n\n" 54 | elif action.type: 55 | doc += f"**Type**: `{action.type.__name__}`\n\n" 56 | 57 | doc += "**Required**: Yes\n\n" if action.required else "**Required**: No\n\n" 58 | 59 | # Add example usage 60 | if action.metavar: 61 | if action.option_strings: 62 | cmd_example = f"{action.option_strings[0]} <{action.metavar}>" 63 | else: 64 | cmd_example = action.metavar 65 | doc += f"#### Example Usage\n\n`{cmd_example}`\n" 66 | 67 | return doc 68 | 69 | 70 | def _add_overall_usage(parser: ArgumentParser) -> str: 71 | cmd_example = [] 72 | for action in parser._actions: 73 | # When the action doesn't have any option strings, it's a positional 74 | # argument 75 | if not action.option_strings: 76 | cmd_example.append(f"<{action.dest}>") 77 | continue 78 | 79 | # Skip help flag 80 | if action.option_strings[0] == "-h": 81 | continue 82 | 83 | value = _get_example_value_from_action(action) 84 | 85 | # Include brackets for optional arguments 86 | if action.required: 87 | cmd_example.append(f"{action.option_strings[0]}{value}") 88 | else: 89 | cmd_example.append(f"[{action.option_strings[0]}{value}]") 90 | 91 | cmd_example = " ".join(cmd_example) 92 | script_name = _get_script_name() 93 | 94 | if cmd_example.strip() == "": 95 | return f"## Overall Usage Example\n\n`{script_name}`\n\n" 96 | 97 | return f"## Overall Usage Example\n\n`{script_name} {cmd_example}`\n\n" 98 | 99 | 100 | def _get_script_name() -> str: 101 | # Running from the command line, so the script name is the last argument 102 | if "parse2docs" in sys.argv: 103 | return Path(sys.argv[-1]).name 104 | 105 | # When running from a module, the script name is the module name 106 | return Path(__file__).name 107 | 108 | 109 | def _get_example_value_from_action(action: Action) -> str: 110 | if action.metavar: 111 | value = f" <{action.metavar}>" 112 | elif action.nargs == 0: 113 | value = "" 114 | else: 115 | value = " " 116 | return value 117 | -------------------------------------------------------------------------------- /parse2docs/module_loader.py: -------------------------------------------------------------------------------- 1 | import importlib 2 | import sys 3 | from pathlib import Path 4 | from types import ModuleType 5 | 6 | 7 | def get_module_from_path(path: Path) -> ModuleType: 8 | """Import a Python module from a given path.""" 9 | module_name = path.stem 10 | with SysPathContext(path): 11 | return importlib.import_module(module_name) 12 | 13 | 14 | class SysPathContext: 15 | """Context manager that temporarily adds a given path to the sys.path.""" 16 | 17 | def __init__(self, path: Path): 18 | self.script_dir = path.parent.absolute() 19 | self.old_path = sys.path.copy() 20 | 21 | def __enter__(self): 22 | sys.path.insert(0, str(self.script_dir)) 23 | 24 | def __exit__(self, exc_type, exc_val, exc_tb): 25 | sys.path = self.old_path 26 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand. 2 | 3 | [[package]] 4 | name = "appnope" 5 | version = "0.1.4" 6 | description = "Disable App Nap on macOS >= 10.9" 7 | optional = false 8 | python-versions = ">=3.6" 9 | groups = ["dev"] 10 | markers = "platform_system == \"Darwin\"" 11 | files = [ 12 | {file = "appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c"}, 13 | {file = "appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee"}, 14 | ] 15 | 16 | [[package]] 17 | name = "asttokens" 18 | version = "2.4.1" 19 | description = "Annotate AST trees with source code positions" 20 | optional = false 21 | python-versions = "*" 22 | groups = ["dev"] 23 | files = [ 24 | {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"}, 25 | {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"}, 26 | ] 27 | 28 | [package.dependencies] 29 | six = ">=1.12.0" 30 | 31 | [package.extras] 32 | astroid = ["astroid (>=1,<2) ; python_version < \"3\"", "astroid (>=2,<4) ; python_version >= \"3\""] 33 | test = ["astroid (>=1,<2) ; python_version < \"3\"", "astroid (>=2,<4) ; python_version >= \"3\"", "pytest"] 34 | 35 | [[package]] 36 | name = "black" 37 | version = "24.4.2" 38 | description = "The uncompromising code formatter." 39 | optional = false 40 | python-versions = ">=3.8" 41 | groups = ["dev"] 42 | files = [ 43 | {file = "black-24.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce"}, 44 | {file = "black-24.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021"}, 45 | {file = "black-24.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063"}, 46 | {file = "black-24.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96"}, 47 | {file = "black-24.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474"}, 48 | {file = "black-24.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c"}, 49 | {file = "black-24.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb"}, 50 | {file = "black-24.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1"}, 51 | {file = "black-24.4.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d"}, 52 | {file = "black-24.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04"}, 53 | {file = "black-24.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc"}, 54 | {file = "black-24.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0"}, 55 | {file = "black-24.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7"}, 56 | {file = "black-24.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94"}, 57 | {file = "black-24.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8"}, 58 | {file = "black-24.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c"}, 59 | {file = "black-24.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1"}, 60 | {file = "black-24.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741"}, 61 | {file = "black-24.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e"}, 62 | {file = "black-24.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7"}, 63 | {file = "black-24.4.2-py3-none-any.whl", hash = "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c"}, 64 | {file = "black-24.4.2.tar.gz", hash = "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d"}, 65 | ] 66 | 67 | [package.dependencies] 68 | click = ">=8.0.0" 69 | mypy-extensions = ">=0.4.3" 70 | packaging = ">=22.0" 71 | pathspec = ">=0.9.0" 72 | platformdirs = ">=2" 73 | 74 | [package.extras] 75 | colorama = ["colorama (>=0.4.3)"] 76 | d = ["aiohttp (>=3.7.4) ; sys_platform != \"win32\" or implementation_name != \"pypy\"", "aiohttp (>=3.7.4,!=3.9.0) ; sys_platform == \"win32\" and implementation_name == \"pypy\""] 77 | jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] 78 | uvloop = ["uvloop (>=0.15.2)"] 79 | 80 | [[package]] 81 | name = "cffi" 82 | version = "1.16.0" 83 | description = "Foreign Function Interface for Python calling C code." 84 | optional = false 85 | python-versions = ">=3.8" 86 | groups = ["dev"] 87 | markers = "implementation_name == \"pypy\"" 88 | files = [ 89 | {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, 90 | {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, 91 | {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, 92 | {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, 93 | {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, 94 | {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, 95 | {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, 96 | {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, 97 | {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, 98 | {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, 99 | {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, 100 | {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, 101 | {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, 102 | {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, 103 | {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, 104 | {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, 105 | {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, 106 | {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, 107 | {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, 108 | {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, 109 | {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, 110 | {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, 111 | {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, 112 | {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, 113 | {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, 114 | {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, 115 | {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, 116 | {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, 117 | {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, 118 | {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, 119 | {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, 120 | {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, 121 | {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, 122 | {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, 123 | {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, 124 | {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, 125 | {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, 126 | {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, 127 | {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, 128 | {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, 129 | {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, 130 | {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, 131 | {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, 132 | {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, 133 | {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, 134 | {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, 135 | {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, 136 | {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, 137 | {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, 138 | {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, 139 | {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, 140 | {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, 141 | ] 142 | 143 | [package.dependencies] 144 | pycparser = "*" 145 | 146 | [[package]] 147 | name = "cfgv" 148 | version = "3.4.0" 149 | description = "Validate configuration and produce human readable error messages." 150 | optional = false 151 | python-versions = ">=3.8" 152 | groups = ["dev"] 153 | files = [ 154 | {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, 155 | {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, 156 | ] 157 | 158 | [[package]] 159 | name = "click" 160 | version = "8.1.7" 161 | description = "Composable command line interface toolkit" 162 | optional = false 163 | python-versions = ">=3.7" 164 | groups = ["dev"] 165 | files = [ 166 | {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, 167 | {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, 168 | ] 169 | 170 | [package.dependencies] 171 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 172 | 173 | [[package]] 174 | name = "colorama" 175 | version = "0.4.6" 176 | description = "Cross-platform colored terminal text." 177 | optional = false 178 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" 179 | groups = ["dev"] 180 | markers = "platform_system == \"Windows\" or sys_platform == \"win32\"" 181 | files = [ 182 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, 183 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, 184 | ] 185 | 186 | [[package]] 187 | name = "comm" 188 | version = "0.2.2" 189 | description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc." 190 | optional = false 191 | python-versions = ">=3.8" 192 | groups = ["dev"] 193 | files = [ 194 | {file = "comm-0.2.2-py3-none-any.whl", hash = "sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3"}, 195 | {file = "comm-0.2.2.tar.gz", hash = "sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e"}, 196 | ] 197 | 198 | [package.dependencies] 199 | traitlets = ">=4" 200 | 201 | [package.extras] 202 | test = ["pytest"] 203 | 204 | [[package]] 205 | name = "coverage" 206 | version = "7.5.3" 207 | description = "Code coverage measurement for Python" 208 | optional = false 209 | python-versions = ">=3.8" 210 | groups = ["dev"] 211 | files = [ 212 | {file = "coverage-7.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a6519d917abb15e12380406d721e37613e2a67d166f9fb7e5a8ce0375744cd45"}, 213 | {file = "coverage-7.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aea7da970f1feccf48be7335f8b2ca64baf9b589d79e05b9397a06696ce1a1ec"}, 214 | {file = "coverage-7.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:923b7b1c717bd0f0f92d862d1ff51d9b2b55dbbd133e05680204465f454bb286"}, 215 | {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62bda40da1e68898186f274f832ef3e759ce929da9a9fd9fcf265956de269dbc"}, 216 | {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8b7339180d00de83e930358223c617cc343dd08e1aa5ec7b06c3a121aec4e1d"}, 217 | {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:25a5caf742c6195e08002d3b6c2dd6947e50efc5fc2c2205f61ecb47592d2d83"}, 218 | {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:05ac5f60faa0c704c0f7e6a5cbfd6f02101ed05e0aee4d2822637a9e672c998d"}, 219 | {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:239a4e75e09c2b12ea478d28815acf83334d32e722e7433471fbf641c606344c"}, 220 | {file = "coverage-7.5.3-cp310-cp310-win32.whl", hash = "sha256:a5812840d1d00eafae6585aba38021f90a705a25b8216ec7f66aebe5b619fb84"}, 221 | {file = "coverage-7.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:33ca90a0eb29225f195e30684ba4a6db05dbef03c2ccd50b9077714c48153cac"}, 222 | {file = "coverage-7.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f81bc26d609bf0fbc622c7122ba6307993c83c795d2d6f6f6fd8c000a770d974"}, 223 | {file = "coverage-7.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7cec2af81f9e7569280822be68bd57e51b86d42e59ea30d10ebdbb22d2cb7232"}, 224 | {file = "coverage-7.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55f689f846661e3f26efa535071775d0483388a1ccfab899df72924805e9e7cd"}, 225 | {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50084d3516aa263791198913a17354bd1dc627d3c1639209640b9cac3fef5807"}, 226 | {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:341dd8f61c26337c37988345ca5c8ccabeff33093a26953a1ac72e7d0103c4fb"}, 227 | {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ab0b028165eea880af12f66086694768f2c3139b2c31ad5e032c8edbafca6ffc"}, 228 | {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5bc5a8c87714b0c67cfeb4c7caa82b2d71e8864d1a46aa990b5588fa953673b8"}, 229 | {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:38a3b98dae8a7c9057bd91fbf3415c05e700a5114c5f1b5b0ea5f8f429ba6614"}, 230 | {file = "coverage-7.5.3-cp311-cp311-win32.whl", hash = "sha256:fcf7d1d6f5da887ca04302db8e0e0cf56ce9a5e05f202720e49b3e8157ddb9a9"}, 231 | {file = "coverage-7.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:8c836309931839cca658a78a888dab9676b5c988d0dd34ca247f5f3e679f4e7a"}, 232 | {file = "coverage-7.5.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:296a7d9bbc598e8744c00f7a6cecf1da9b30ae9ad51c566291ff1314e6cbbed8"}, 233 | {file = "coverage-7.5.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:34d6d21d8795a97b14d503dcaf74226ae51eb1f2bd41015d3ef332a24d0a17b3"}, 234 | {file = "coverage-7.5.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e317953bb4c074c06c798a11dbdd2cf9979dbcaa8ccc0fa4701d80042d4ebf1"}, 235 | {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:705f3d7c2b098c40f5b81790a5fedb274113373d4d1a69e65f8b68b0cc26f6db"}, 236 | {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1196e13c45e327d6cd0b6e471530a1882f1017eb83c6229fc613cd1a11b53cd"}, 237 | {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:015eddc5ccd5364dcb902eaecf9515636806fa1e0d5bef5769d06d0f31b54523"}, 238 | {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fd27d8b49e574e50caa65196d908f80e4dff64d7e592d0c59788b45aad7e8b35"}, 239 | {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:33fc65740267222fc02975c061eb7167185fef4cc8f2770267ee8bf7d6a42f84"}, 240 | {file = "coverage-7.5.3-cp312-cp312-win32.whl", hash = "sha256:7b2a19e13dfb5c8e145c7a6ea959485ee8e2204699903c88c7d25283584bfc08"}, 241 | {file = "coverage-7.5.3-cp312-cp312-win_amd64.whl", hash = "sha256:0bbddc54bbacfc09b3edaec644d4ac90c08ee8ed4844b0f86227dcda2d428fcb"}, 242 | {file = "coverage-7.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f78300789a708ac1f17e134593f577407d52d0417305435b134805c4fb135adb"}, 243 | {file = "coverage-7.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b368e1aee1b9b75757942d44d7598dcd22a9dbb126affcbba82d15917f0cc155"}, 244 | {file = "coverage-7.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f836c174c3a7f639bded48ec913f348c4761cbf49de4a20a956d3431a7c9cb24"}, 245 | {file = "coverage-7.5.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:244f509f126dc71369393ce5fea17c0592c40ee44e607b6d855e9c4ac57aac98"}, 246 | {file = "coverage-7.5.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4c2872b3c91f9baa836147ca33650dc5c172e9273c808c3c3199c75490e709d"}, 247 | {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dd4b3355b01273a56b20c219e74e7549e14370b31a4ffe42706a8cda91f19f6d"}, 248 | {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f542287b1489c7a860d43a7d8883e27ca62ab84ca53c965d11dac1d3a1fab7ce"}, 249 | {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:75e3f4e86804023e991096b29e147e635f5e2568f77883a1e6eed74512659ab0"}, 250 | {file = "coverage-7.5.3-cp38-cp38-win32.whl", hash = "sha256:c59d2ad092dc0551d9f79d9d44d005c945ba95832a6798f98f9216ede3d5f485"}, 251 | {file = "coverage-7.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:fa21a04112c59ad54f69d80e376f7f9d0f5f9123ab87ecd18fbb9ec3a2beed56"}, 252 | {file = "coverage-7.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f5102a92855d518b0996eb197772f5ac2a527c0ec617124ad5242a3af5e25f85"}, 253 | {file = "coverage-7.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d1da0a2e3b37b745a2b2a678a4c796462cf753aebf94edcc87dcc6b8641eae31"}, 254 | {file = "coverage-7.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8383a6c8cefba1b7cecc0149415046b6fc38836295bc4c84e820872eb5478b3d"}, 255 | {file = "coverage-7.5.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9aad68c3f2566dfae84bf46295a79e79d904e1c21ccfc66de88cd446f8686341"}, 256 | {file = "coverage-7.5.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e079c9ec772fedbade9d7ebc36202a1d9ef7291bc9b3a024ca395c4d52853d7"}, 257 | {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bde997cac85fcac227b27d4fb2c7608a2c5f6558469b0eb704c5726ae49e1c52"}, 258 | {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:990fb20b32990b2ce2c5f974c3e738c9358b2735bc05075d50a6f36721b8f303"}, 259 | {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3d5a67f0da401e105753d474369ab034c7bae51a4c31c77d94030d59e41df5bd"}, 260 | {file = "coverage-7.5.3-cp39-cp39-win32.whl", hash = "sha256:e08c470c2eb01977d221fd87495b44867a56d4d594f43739a8028f8646a51e0d"}, 261 | {file = "coverage-7.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:1d2a830ade66d3563bb61d1e3c77c8def97b30ed91e166c67d0632c018f380f0"}, 262 | {file = "coverage-7.5.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:3538d8fb1ee9bdd2e2692b3b18c22bb1c19ffbefd06880f5ac496e42d7bb3884"}, 263 | {file = "coverage-7.5.3.tar.gz", hash = "sha256:04aefca5190d1dc7a53a4c1a5a7f8568811306d7a8ee231c42fb69215571944f"}, 264 | ] 265 | 266 | [package.extras] 267 | toml = ["tomli ; python_full_version <= \"3.11.0a6\""] 268 | 269 | [[package]] 270 | name = "debugpy" 271 | version = "1.8.1" 272 | description = "An implementation of the Debug Adapter Protocol for Python" 273 | optional = false 274 | python-versions = ">=3.8" 275 | groups = ["dev"] 276 | files = [ 277 | {file = "debugpy-1.8.1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:3bda0f1e943d386cc7a0e71bfa59f4137909e2ed947fb3946c506e113000f741"}, 278 | {file = "debugpy-1.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dda73bf69ea479c8577a0448f8c707691152e6c4de7f0c4dec5a4bc11dee516e"}, 279 | {file = "debugpy-1.8.1-cp310-cp310-win32.whl", hash = "sha256:3a79c6f62adef994b2dbe9fc2cc9cc3864a23575b6e387339ab739873bea53d0"}, 280 | {file = "debugpy-1.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:7eb7bd2b56ea3bedb009616d9e2f64aab8fc7000d481faec3cd26c98a964bcdd"}, 281 | {file = "debugpy-1.8.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:016a9fcfc2c6b57f939673c874310d8581d51a0fe0858e7fac4e240c5eb743cb"}, 282 | {file = "debugpy-1.8.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd97ed11a4c7f6d042d320ce03d83b20c3fb40da892f994bc041bbc415d7a099"}, 283 | {file = "debugpy-1.8.1-cp311-cp311-win32.whl", hash = "sha256:0de56aba8249c28a300bdb0672a9b94785074eb82eb672db66c8144fff673146"}, 284 | {file = "debugpy-1.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:1a9fe0829c2b854757b4fd0a338d93bc17249a3bf69ecf765c61d4c522bb92a8"}, 285 | {file = "debugpy-1.8.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3ebb70ba1a6524d19fa7bb122f44b74170c447d5746a503e36adc244a20ac539"}, 286 | {file = "debugpy-1.8.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2e658a9630f27534e63922ebf655a6ab60c370f4d2fc5c02a5b19baf4410ace"}, 287 | {file = "debugpy-1.8.1-cp312-cp312-win32.whl", hash = "sha256:caad2846e21188797a1f17fc09c31b84c7c3c23baf2516fed5b40b378515bbf0"}, 288 | {file = "debugpy-1.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:edcc9f58ec0fd121a25bc950d4578df47428d72e1a0d66c07403b04eb93bcf98"}, 289 | {file = "debugpy-1.8.1-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:7a3afa222f6fd3d9dfecd52729bc2e12c93e22a7491405a0ecbf9e1d32d45b39"}, 290 | {file = "debugpy-1.8.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d915a18f0597ef685e88bb35e5d7ab968964b7befefe1aaea1eb5b2640b586c7"}, 291 | {file = "debugpy-1.8.1-cp38-cp38-win32.whl", hash = "sha256:92116039b5500633cc8d44ecc187abe2dfa9b90f7a82bbf81d079fcdd506bae9"}, 292 | {file = "debugpy-1.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:e38beb7992b5afd9d5244e96ad5fa9135e94993b0c551ceebf3fe1a5d9beb234"}, 293 | {file = "debugpy-1.8.1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:bfb20cb57486c8e4793d41996652e5a6a885b4d9175dd369045dad59eaacea42"}, 294 | {file = "debugpy-1.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efd3fdd3f67a7e576dd869c184c5dd71d9aaa36ded271939da352880c012e703"}, 295 | {file = "debugpy-1.8.1-cp39-cp39-win32.whl", hash = "sha256:58911e8521ca0c785ac7a0539f1e77e0ce2df753f786188f382229278b4cdf23"}, 296 | {file = "debugpy-1.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:6df9aa9599eb05ca179fb0b810282255202a66835c6efb1d112d21ecb830ddd3"}, 297 | {file = "debugpy-1.8.1-py2.py3-none-any.whl", hash = "sha256:28acbe2241222b87e255260c76741e1fbf04fdc3b6d094fcf57b6c6f75ce1242"}, 298 | {file = "debugpy-1.8.1.zip", hash = "sha256:f696d6be15be87aef621917585f9bb94b1dc9e8aced570db1b8a6fc14e8f9b42"}, 299 | ] 300 | 301 | [[package]] 302 | name = "decorator" 303 | version = "5.1.1" 304 | description = "Decorators for Humans" 305 | optional = false 306 | python-versions = ">=3.5" 307 | groups = ["dev"] 308 | files = [ 309 | {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, 310 | {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, 311 | ] 312 | 313 | [[package]] 314 | name = "distlib" 315 | version = "0.3.8" 316 | description = "Distribution utilities" 317 | optional = false 318 | python-versions = "*" 319 | groups = ["dev"] 320 | files = [ 321 | {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, 322 | {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, 323 | ] 324 | 325 | [[package]] 326 | name = "executing" 327 | version = "2.0.1" 328 | description = "Get the currently executing AST node of a frame, and other information" 329 | optional = false 330 | python-versions = ">=3.5" 331 | groups = ["dev"] 332 | files = [ 333 | {file = "executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"}, 334 | {file = "executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147"}, 335 | ] 336 | 337 | [package.extras] 338 | tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich ; python_version >= \"3.11\""] 339 | 340 | [[package]] 341 | name = "filelock" 342 | version = "3.14.0" 343 | description = "A platform independent file lock." 344 | optional = false 345 | python-versions = ">=3.8" 346 | groups = ["dev"] 347 | files = [ 348 | {file = "filelock-3.14.0-py3-none-any.whl", hash = "sha256:43339835842f110ca7ae60f1e1c160714c5a6afd15a2873419ab185334975c0f"}, 349 | {file = "filelock-3.14.0.tar.gz", hash = "sha256:6ea72da3be9b8c82afd3edcf99f2fffbb5076335a5ae4d03248bb5b6c3eae78a"}, 350 | ] 351 | 352 | [package.extras] 353 | docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] 354 | testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] 355 | typing = ["typing-extensions (>=4.8) ; python_version < \"3.11\""] 356 | 357 | [[package]] 358 | name = "identify" 359 | version = "2.5.36" 360 | description = "File identification library for Python" 361 | optional = false 362 | python-versions = ">=3.8" 363 | groups = ["dev"] 364 | files = [ 365 | {file = "identify-2.5.36-py2.py3-none-any.whl", hash = "sha256:37d93f380f4de590500d9dba7db359d0d3da95ffe7f9de1753faa159e71e7dfa"}, 366 | {file = "identify-2.5.36.tar.gz", hash = "sha256:e5e00f54165f9047fbebeb4a560f9acfb8af4c88232be60a488e9b68d122745d"}, 367 | ] 368 | 369 | [package.extras] 370 | license = ["ukkonen"] 371 | 372 | [[package]] 373 | name = "iniconfig" 374 | version = "2.0.0" 375 | description = "brain-dead simple config-ini parsing" 376 | optional = false 377 | python-versions = ">=3.7" 378 | groups = ["dev"] 379 | files = [ 380 | {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, 381 | {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, 382 | ] 383 | 384 | [[package]] 385 | name = "ipykernel" 386 | version = "6.29.4" 387 | description = "IPython Kernel for Jupyter" 388 | optional = false 389 | python-versions = ">=3.8" 390 | groups = ["dev"] 391 | files = [ 392 | {file = "ipykernel-6.29.4-py3-none-any.whl", hash = "sha256:1181e653d95c6808039c509ef8e67c4126b3b3af7781496c7cbfb5ed938a27da"}, 393 | {file = "ipykernel-6.29.4.tar.gz", hash = "sha256:3d44070060f9475ac2092b760123fadf105d2e2493c24848b6691a7c4f42af5c"}, 394 | ] 395 | 396 | [package.dependencies] 397 | appnope = {version = "*", markers = "platform_system == \"Darwin\""} 398 | comm = ">=0.1.1" 399 | debugpy = ">=1.6.5" 400 | ipython = ">=7.23.1" 401 | jupyter-client = ">=6.1.12" 402 | jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" 403 | matplotlib-inline = ">=0.1" 404 | nest-asyncio = "*" 405 | packaging = "*" 406 | psutil = "*" 407 | pyzmq = ">=24" 408 | tornado = ">=6.1" 409 | traitlets = ">=5.4.0" 410 | 411 | [package.extras] 412 | cov = ["coverage[toml]", "curio", "matplotlib", "pytest-cov", "trio"] 413 | docs = ["myst-parser", "pydata-sphinx-theme", "sphinx", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "trio"] 414 | pyqt5 = ["pyqt5"] 415 | pyside6 = ["pyside6"] 416 | test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio (>=0.23.5)", "pytest-cov", "pytest-timeout"] 417 | 418 | [[package]] 419 | name = "ipython" 420 | version = "8.25.0" 421 | description = "IPython: Productive Interactive Computing" 422 | optional = false 423 | python-versions = ">=3.10" 424 | groups = ["dev"] 425 | files = [ 426 | {file = "ipython-8.25.0-py3-none-any.whl", hash = "sha256:53eee7ad44df903a06655871cbab66d156a051fd86f3ec6750470ac9604ac1ab"}, 427 | {file = "ipython-8.25.0.tar.gz", hash = "sha256:c6ed726a140b6e725b911528f80439c534fac915246af3efc39440a6b0f9d716"}, 428 | ] 429 | 430 | [package.dependencies] 431 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 432 | decorator = "*" 433 | jedi = ">=0.16" 434 | matplotlib-inline = "*" 435 | pexpect = {version = ">4.3", markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\""} 436 | prompt-toolkit = ">=3.0.41,<3.1.0" 437 | pygments = ">=2.4.0" 438 | stack-data = "*" 439 | traitlets = ">=5.13.0" 440 | typing-extensions = {version = ">=4.6", markers = "python_version < \"3.12\""} 441 | 442 | [package.extras] 443 | all = ["ipython[black,doc,kernel,matplotlib,nbconvert,nbformat,notebook,parallel,qtconsole]", "ipython[test,test-extra]"] 444 | black = ["black"] 445 | doc = ["docrepr", "exceptiongroup", "intersphinx-registry", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinxcontrib-jquery", "tomli ; python_version < \"3.11\"", "typing-extensions"] 446 | kernel = ["ipykernel"] 447 | matplotlib = ["matplotlib"] 448 | nbconvert = ["nbconvert"] 449 | nbformat = ["nbformat"] 450 | notebook = ["ipywidgets", "notebook"] 451 | parallel = ["ipyparallel"] 452 | qtconsole = ["qtconsole"] 453 | test = ["pickleshare", "pytest", "pytest-asyncio (<0.22)", "testpath"] 454 | test-extra = ["curio", "ipython[test]", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.23)", "pandas", "trio"] 455 | 456 | [[package]] 457 | name = "jedi" 458 | version = "0.19.1" 459 | description = "An autocompletion tool for Python that can be used for text editors." 460 | optional = false 461 | python-versions = ">=3.6" 462 | groups = ["dev"] 463 | files = [ 464 | {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"}, 465 | {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"}, 466 | ] 467 | 468 | [package.dependencies] 469 | parso = ">=0.8.3,<0.9.0" 470 | 471 | [package.extras] 472 | docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] 473 | qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] 474 | testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] 475 | 476 | [[package]] 477 | name = "jupyter-client" 478 | version = "8.6.2" 479 | description = "Jupyter protocol implementation and client libraries" 480 | optional = false 481 | python-versions = ">=3.8" 482 | groups = ["dev"] 483 | files = [ 484 | {file = "jupyter_client-8.6.2-py3-none-any.whl", hash = "sha256:50cbc5c66fd1b8f65ecb66bc490ab73217993632809b6e505687de18e9dea39f"}, 485 | {file = "jupyter_client-8.6.2.tar.gz", hash = "sha256:2bda14d55ee5ba58552a8c53ae43d215ad9868853489213f37da060ced54d8df"}, 486 | ] 487 | 488 | [package.dependencies] 489 | jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" 490 | python-dateutil = ">=2.8.2" 491 | pyzmq = ">=23.0" 492 | tornado = ">=6.2" 493 | traitlets = ">=5.3" 494 | 495 | [package.extras] 496 | docs = ["ipykernel", "myst-parser", "pydata-sphinx-theme", "sphinx (>=4)", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] 497 | test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko ; sys_platform == \"win32\"", "pre-commit", "pytest (<8.2.0)", "pytest-cov", "pytest-jupyter[client] (>=0.4.1)", "pytest-timeout"] 498 | 499 | [[package]] 500 | name = "jupyter-core" 501 | version = "5.7.2" 502 | description = "Jupyter core package. A base package on which Jupyter projects rely." 503 | optional = false 504 | python-versions = ">=3.8" 505 | groups = ["dev"] 506 | files = [ 507 | {file = "jupyter_core-5.7.2-py3-none-any.whl", hash = "sha256:4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409"}, 508 | {file = "jupyter_core-5.7.2.tar.gz", hash = "sha256:aa5f8d32bbf6b431ac830496da7392035d6f61b4f54872f15c4bd2a9c3f536d9"}, 509 | ] 510 | 511 | [package.dependencies] 512 | platformdirs = ">=2.5" 513 | pywin32 = {version = ">=300", markers = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\""} 514 | traitlets = ">=5.3" 515 | 516 | [package.extras] 517 | docs = ["myst-parser", "pydata-sphinx-theme", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "traitlets"] 518 | test = ["ipykernel", "pre-commit", "pytest (<8)", "pytest-cov", "pytest-timeout"] 519 | 520 | [[package]] 521 | name = "matplotlib-inline" 522 | version = "0.1.7" 523 | description = "Inline Matplotlib backend for Jupyter" 524 | optional = false 525 | python-versions = ">=3.8" 526 | groups = ["dev"] 527 | files = [ 528 | {file = "matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca"}, 529 | {file = "matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90"}, 530 | ] 531 | 532 | [package.dependencies] 533 | traitlets = "*" 534 | 535 | [[package]] 536 | name = "mypy-extensions" 537 | version = "1.0.0" 538 | description = "Type system extensions for programs checked with the mypy type checker." 539 | optional = false 540 | python-versions = ">=3.5" 541 | groups = ["dev"] 542 | files = [ 543 | {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, 544 | {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, 545 | ] 546 | 547 | [[package]] 548 | name = "nest-asyncio" 549 | version = "1.6.0" 550 | description = "Patch asyncio to allow nested event loops" 551 | optional = false 552 | python-versions = ">=3.5" 553 | groups = ["dev"] 554 | files = [ 555 | {file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"}, 556 | {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"}, 557 | ] 558 | 559 | [[package]] 560 | name = "nodeenv" 561 | version = "1.9.1" 562 | description = "Node.js virtual environment builder" 563 | optional = false 564 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" 565 | groups = ["dev"] 566 | files = [ 567 | {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, 568 | {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, 569 | ] 570 | 571 | [[package]] 572 | name = "packaging" 573 | version = "24.1" 574 | description = "Core utilities for Python packages" 575 | optional = false 576 | python-versions = ">=3.8" 577 | groups = ["dev"] 578 | files = [ 579 | {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, 580 | {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, 581 | ] 582 | 583 | [[package]] 584 | name = "parso" 585 | version = "0.8.4" 586 | description = "A Python Parser" 587 | optional = false 588 | python-versions = ">=3.6" 589 | groups = ["dev"] 590 | files = [ 591 | {file = "parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18"}, 592 | {file = "parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d"}, 593 | ] 594 | 595 | [package.extras] 596 | qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] 597 | testing = ["docopt", "pytest"] 598 | 599 | [[package]] 600 | name = "pathspec" 601 | version = "0.12.1" 602 | description = "Utility library for gitignore style pattern matching of file paths." 603 | optional = false 604 | python-versions = ">=3.8" 605 | groups = ["dev"] 606 | files = [ 607 | {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, 608 | {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, 609 | ] 610 | 611 | [[package]] 612 | name = "pexpect" 613 | version = "4.9.0" 614 | description = "Pexpect allows easy control of interactive console applications." 615 | optional = false 616 | python-versions = "*" 617 | groups = ["dev"] 618 | markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\"" 619 | files = [ 620 | {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, 621 | {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, 622 | ] 623 | 624 | [package.dependencies] 625 | ptyprocess = ">=0.5" 626 | 627 | [[package]] 628 | name = "platformdirs" 629 | version = "4.2.2" 630 | description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." 631 | optional = false 632 | python-versions = ">=3.8" 633 | groups = ["dev"] 634 | files = [ 635 | {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, 636 | {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, 637 | ] 638 | 639 | [package.extras] 640 | docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] 641 | test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] 642 | type = ["mypy (>=1.8)"] 643 | 644 | [[package]] 645 | name = "pluggy" 646 | version = "1.5.0" 647 | description = "plugin and hook calling mechanisms for python" 648 | optional = false 649 | python-versions = ">=3.8" 650 | groups = ["dev"] 651 | files = [ 652 | {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, 653 | {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, 654 | ] 655 | 656 | [package.extras] 657 | dev = ["pre-commit", "tox"] 658 | testing = ["pytest", "pytest-benchmark"] 659 | 660 | [[package]] 661 | name = "pre-commit" 662 | version = "3.7.1" 663 | description = "A framework for managing and maintaining multi-language pre-commit hooks." 664 | optional = false 665 | python-versions = ">=3.9" 666 | groups = ["dev"] 667 | files = [ 668 | {file = "pre_commit-3.7.1-py2.py3-none-any.whl", hash = "sha256:fae36fd1d7ad7d6a5a1c0b0d5adb2ed1a3bda5a21bf6c3e5372073d7a11cd4c5"}, 669 | {file = "pre_commit-3.7.1.tar.gz", hash = "sha256:8ca3ad567bc78a4972a3f1a477e94a79d4597e8140a6e0b651c5e33899c3654a"}, 670 | ] 671 | 672 | [package.dependencies] 673 | cfgv = ">=2.0.0" 674 | identify = ">=1.0.0" 675 | nodeenv = ">=0.11.1" 676 | pyyaml = ">=5.1" 677 | virtualenv = ">=20.10.0" 678 | 679 | [[package]] 680 | name = "prompt-toolkit" 681 | version = "3.0.47" 682 | description = "Library for building powerful interactive command lines in Python" 683 | optional = false 684 | python-versions = ">=3.7.0" 685 | groups = ["dev"] 686 | files = [ 687 | {file = "prompt_toolkit-3.0.47-py3-none-any.whl", hash = "sha256:0d7bfa67001d5e39d02c224b663abc33687405033a8c422d0d675a5a13361d10"}, 688 | {file = "prompt_toolkit-3.0.47.tar.gz", hash = "sha256:1e1b29cb58080b1e69f207c893a1a7bf16d127a5c30c9d17a25a5d77792e5360"}, 689 | ] 690 | 691 | [package.dependencies] 692 | wcwidth = "*" 693 | 694 | [[package]] 695 | name = "psutil" 696 | version = "5.9.8" 697 | description = "Cross-platform lib for process and system monitoring in Python." 698 | optional = false 699 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" 700 | groups = ["dev"] 701 | files = [ 702 | {file = "psutil-5.9.8-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:26bd09967ae00920df88e0352a91cff1a78f8d69b3ecabbfe733610c0af486c8"}, 703 | {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73"}, 704 | {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:611052c4bc70432ec770d5d54f64206aa7203a101ec273a0cd82418c86503bb7"}, 705 | {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:50187900d73c1381ba1454cf40308c2bf6f34268518b3f36a9b663ca87e65e36"}, 706 | {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d"}, 707 | {file = "psutil-5.9.8-cp27-none-win32.whl", hash = "sha256:36f435891adb138ed3c9e58c6af3e2e6ca9ac2f365efe1f9cfef2794e6c93b4e"}, 708 | {file = "psutil-5.9.8-cp27-none-win_amd64.whl", hash = "sha256:bd1184ceb3f87651a67b2708d4c3338e9b10c5df903f2e3776b62303b26cb631"}, 709 | {file = "psutil-5.9.8-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:aee678c8720623dc456fa20659af736241f575d79429a0e5e9cf88ae0605cc81"}, 710 | {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cb6403ce6d8e047495a701dc7c5bd788add903f8986d523e3e20b98b733e421"}, 711 | {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4"}, 712 | {file = "psutil-5.9.8-cp36-cp36m-win32.whl", hash = "sha256:7d79560ad97af658a0f6adfef8b834b53f64746d45b403f225b85c5c2c140eee"}, 713 | {file = "psutil-5.9.8-cp36-cp36m-win_amd64.whl", hash = "sha256:27cc40c3493bb10de1be4b3f07cae4c010ce715290a5be22b98493509c6299e2"}, 714 | {file = "psutil-5.9.8-cp37-abi3-win32.whl", hash = "sha256:bc56c2a1b0d15aa3eaa5a60c9f3f8e3e565303b465dbf57a1b730e7a2b9844e0"}, 715 | {file = "psutil-5.9.8-cp37-abi3-win_amd64.whl", hash = "sha256:8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf"}, 716 | {file = "psutil-5.9.8-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8"}, 717 | {file = "psutil-5.9.8.tar.gz", hash = "sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c"}, 718 | ] 719 | 720 | [package.extras] 721 | test = ["enum34 ; python_version <= \"3.4\"", "ipaddress ; python_version < \"3.0\"", "mock ; python_version < \"3.0\"", "pywin32 ; sys_platform == \"win32\"", "wmi ; sys_platform == \"win32\""] 722 | 723 | [[package]] 724 | name = "ptyprocess" 725 | version = "0.7.0" 726 | description = "Run a subprocess in a pseudo terminal" 727 | optional = false 728 | python-versions = "*" 729 | groups = ["dev"] 730 | markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\"" 731 | files = [ 732 | {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, 733 | {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, 734 | ] 735 | 736 | [[package]] 737 | name = "pure-eval" 738 | version = "0.2.2" 739 | description = "Safely evaluate AST nodes without side effects" 740 | optional = false 741 | python-versions = "*" 742 | groups = ["dev"] 743 | files = [ 744 | {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, 745 | {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, 746 | ] 747 | 748 | [package.extras] 749 | tests = ["pytest"] 750 | 751 | [[package]] 752 | name = "pycparser" 753 | version = "2.22" 754 | description = "C parser in Python" 755 | optional = false 756 | python-versions = ">=3.8" 757 | groups = ["dev"] 758 | markers = "implementation_name == \"pypy\"" 759 | files = [ 760 | {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, 761 | {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, 762 | ] 763 | 764 | [[package]] 765 | name = "pygments" 766 | version = "2.18.0" 767 | description = "Pygments is a syntax highlighting package written in Python." 768 | optional = false 769 | python-versions = ">=3.8" 770 | groups = ["dev"] 771 | files = [ 772 | {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, 773 | {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, 774 | ] 775 | 776 | [package.extras] 777 | windows-terminal = ["colorama (>=0.4.6)"] 778 | 779 | [[package]] 780 | name = "pytest" 781 | version = "7.4.4" 782 | description = "pytest: simple powerful testing with Python" 783 | optional = false 784 | python-versions = ">=3.7" 785 | groups = ["dev"] 786 | files = [ 787 | {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, 788 | {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, 789 | ] 790 | 791 | [package.dependencies] 792 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 793 | iniconfig = "*" 794 | packaging = "*" 795 | pluggy = ">=0.12,<2.0" 796 | 797 | [package.extras] 798 | testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] 799 | 800 | [[package]] 801 | name = "pytest-cov" 802 | version = "4.1.0" 803 | description = "Pytest plugin for measuring coverage." 804 | optional = false 805 | python-versions = ">=3.7" 806 | groups = ["dev"] 807 | files = [ 808 | {file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"}, 809 | {file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"}, 810 | ] 811 | 812 | [package.dependencies] 813 | coverage = {version = ">=5.2.1", extras = ["toml"]} 814 | pytest = ">=4.6" 815 | 816 | [package.extras] 817 | testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] 818 | 819 | [[package]] 820 | name = "python-dateutil" 821 | version = "2.9.0.post0" 822 | description = "Extensions to the standard Python datetime module" 823 | optional = false 824 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" 825 | groups = ["dev"] 826 | files = [ 827 | {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, 828 | {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, 829 | ] 830 | 831 | [package.dependencies] 832 | six = ">=1.5" 833 | 834 | [[package]] 835 | name = "pywin32" 836 | version = "306" 837 | description = "Python for Window Extensions" 838 | optional = false 839 | python-versions = "*" 840 | groups = ["dev"] 841 | markers = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\"" 842 | files = [ 843 | {file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"}, 844 | {file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"}, 845 | {file = "pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407"}, 846 | {file = "pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e"}, 847 | {file = "pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a"}, 848 | {file = "pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b"}, 849 | {file = "pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e"}, 850 | {file = "pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040"}, 851 | {file = "pywin32-306-cp37-cp37m-win32.whl", hash = "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65"}, 852 | {file = "pywin32-306-cp37-cp37m-win_amd64.whl", hash = "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36"}, 853 | {file = "pywin32-306-cp38-cp38-win32.whl", hash = "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a"}, 854 | {file = "pywin32-306-cp38-cp38-win_amd64.whl", hash = "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0"}, 855 | {file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"}, 856 | {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"}, 857 | ] 858 | 859 | [[package]] 860 | name = "pyyaml" 861 | version = "6.0.1" 862 | description = "YAML parser and emitter for Python" 863 | optional = false 864 | python-versions = ">=3.6" 865 | groups = ["dev"] 866 | files = [ 867 | {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, 868 | {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, 869 | {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, 870 | {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, 871 | {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, 872 | {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, 873 | {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, 874 | {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, 875 | {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, 876 | {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, 877 | {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, 878 | {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, 879 | {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, 880 | {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, 881 | {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, 882 | {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, 883 | {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, 884 | {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, 885 | {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, 886 | {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, 887 | {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, 888 | {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, 889 | {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, 890 | {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, 891 | {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, 892 | {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, 893 | {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, 894 | {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, 895 | {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, 896 | {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, 897 | {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, 898 | {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, 899 | {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, 900 | {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, 901 | {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, 902 | {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, 903 | {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, 904 | {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, 905 | {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, 906 | {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, 907 | {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, 908 | {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, 909 | {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, 910 | {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, 911 | {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, 912 | {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, 913 | {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, 914 | {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, 915 | {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, 916 | {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, 917 | {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, 918 | ] 919 | 920 | [[package]] 921 | name = "pyzmq" 922 | version = "26.0.3" 923 | description = "Python bindings for 0MQ" 924 | optional = false 925 | python-versions = ">=3.7" 926 | groups = ["dev"] 927 | files = [ 928 | {file = "pyzmq-26.0.3-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:44dd6fc3034f1eaa72ece33588867df9e006a7303725a12d64c3dff92330f625"}, 929 | {file = "pyzmq-26.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:acb704195a71ac5ea5ecf2811c9ee19ecdc62b91878528302dd0be1b9451cc90"}, 930 | {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dbb9c997932473a27afa93954bb77a9f9b786b4ccf718d903f35da3232317de"}, 931 | {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6bcb34f869d431799c3ee7d516554797f7760cb2198ecaa89c3f176f72d062be"}, 932 | {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ece17ec5f20d7d9b442e5174ae9f020365d01ba7c112205a4d59cf19dc38ee"}, 933 | {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:ba6e5e6588e49139a0979d03a7deb9c734bde647b9a8808f26acf9c547cab1bf"}, 934 | {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3bf8b000a4e2967e6dfdd8656cd0757d18c7e5ce3d16339e550bd462f4857e59"}, 935 | {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2136f64fbb86451dbbf70223635a468272dd20075f988a102bf8a3f194a411dc"}, 936 | {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e8918973fbd34e7814f59143c5f600ecd38b8038161239fd1a3d33d5817a38b8"}, 937 | {file = "pyzmq-26.0.3-cp310-cp310-win32.whl", hash = "sha256:0aaf982e68a7ac284377d051c742610220fd06d330dcd4c4dbb4cdd77c22a537"}, 938 | {file = "pyzmq-26.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:f1a9b7d00fdf60b4039f4455afd031fe85ee8305b019334b72dcf73c567edc47"}, 939 | {file = "pyzmq-26.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:80b12f25d805a919d53efc0a5ad7c0c0326f13b4eae981a5d7b7cc343318ebb7"}, 940 | {file = "pyzmq-26.0.3-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:a72a84570f84c374b4c287183debc776dc319d3e8ce6b6a0041ce2e400de3f32"}, 941 | {file = "pyzmq-26.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7ca684ee649b55fd8f378127ac8462fb6c85f251c2fb027eb3c887e8ee347bcd"}, 942 | {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e222562dc0f38571c8b1ffdae9d7adb866363134299264a1958d077800b193b7"}, 943 | {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f17cde1db0754c35a91ac00b22b25c11da6eec5746431d6e5092f0cd31a3fea9"}, 944 | {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b7c0c0b3244bb2275abe255d4a30c050d541c6cb18b870975553f1fb6f37527"}, 945 | {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:ac97a21de3712afe6a6c071abfad40a6224fd14fa6ff0ff8d0c6e6cd4e2f807a"}, 946 | {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:88b88282e55fa39dd556d7fc04160bcf39dea015f78e0cecec8ff4f06c1fc2b5"}, 947 | {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:72b67f966b57dbd18dcc7efbc1c7fc9f5f983e572db1877081f075004614fcdd"}, 948 | {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f4b6cecbbf3b7380f3b61de3a7b93cb721125dc125c854c14ddc91225ba52f83"}, 949 | {file = "pyzmq-26.0.3-cp311-cp311-win32.whl", hash = "sha256:eed56b6a39216d31ff8cd2f1d048b5bf1700e4b32a01b14379c3b6dde9ce3aa3"}, 950 | {file = "pyzmq-26.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:3191d312c73e3cfd0f0afdf51df8405aafeb0bad71e7ed8f68b24b63c4f36500"}, 951 | {file = "pyzmq-26.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:b6907da3017ef55139cf0e417c5123a84c7332520e73a6902ff1f79046cd3b94"}, 952 | {file = "pyzmq-26.0.3-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:068ca17214038ae986d68f4a7021f97e187ed278ab6dccb79f837d765a54d753"}, 953 | {file = "pyzmq-26.0.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7821d44fe07335bea256b9f1f41474a642ca55fa671dfd9f00af8d68a920c2d4"}, 954 | {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eeb438a26d87c123bb318e5f2b3d86a36060b01f22fbdffd8cf247d52f7c9a2b"}, 955 | {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:69ea9d6d9baa25a4dc9cef5e2b77b8537827b122214f210dd925132e34ae9b12"}, 956 | {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7daa3e1369355766dea11f1d8ef829905c3b9da886ea3152788dc25ee6079e02"}, 957 | {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:6ca7a9a06b52d0e38ccf6bca1aeff7be178917893f3883f37b75589d42c4ac20"}, 958 | {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1b7d0e124948daa4d9686d421ef5087c0516bc6179fdcf8828b8444f8e461a77"}, 959 | {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e746524418b70f38550f2190eeee834db8850088c834d4c8406fbb9bc1ae10b2"}, 960 | {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:6b3146f9ae6af82c47a5282ac8803523d381b3b21caeae0327ed2f7ecb718798"}, 961 | {file = "pyzmq-26.0.3-cp312-cp312-win32.whl", hash = "sha256:2b291d1230845871c00c8462c50565a9cd6026fe1228e77ca934470bb7d70ea0"}, 962 | {file = "pyzmq-26.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:926838a535c2c1ea21c903f909a9a54e675c2126728c21381a94ddf37c3cbddf"}, 963 | {file = "pyzmq-26.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:5bf6c237f8c681dfb91b17f8435b2735951f0d1fad10cc5dfd96db110243370b"}, 964 | {file = "pyzmq-26.0.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c0991f5a96a8e620f7691e61178cd8f457b49e17b7d9cfa2067e2a0a89fc1d5"}, 965 | {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:dbf012d8fcb9f2cf0643b65df3b355fdd74fc0035d70bb5c845e9e30a3a4654b"}, 966 | {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:01fbfbeb8249a68d257f601deb50c70c929dc2dfe683b754659569e502fbd3aa"}, 967 | {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c8eb19abe87029c18f226d42b8a2c9efdd139d08f8bf6e085dd9075446db450"}, 968 | {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:5344b896e79800af86ad643408ca9aa303a017f6ebff8cee5a3163c1e9aec987"}, 969 | {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:204e0f176fd1d067671157d049466869b3ae1fc51e354708b0dc41cf94e23a3a"}, 970 | {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a42db008d58530efa3b881eeee4991146de0b790e095f7ae43ba5cc612decbc5"}, 971 | {file = "pyzmq-26.0.3-cp37-cp37m-win32.whl", hash = "sha256:8d7a498671ca87e32b54cb47c82a92b40130a26c5197d392720a1bce1b3c77cf"}, 972 | {file = "pyzmq-26.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:3b4032a96410bdc760061b14ed6a33613ffb7f702181ba999df5d16fb96ba16a"}, 973 | {file = "pyzmq-26.0.3-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:2cc4e280098c1b192c42a849de8de2c8e0f3a84086a76ec5b07bfee29bda7d18"}, 974 | {file = "pyzmq-26.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5bde86a2ed3ce587fa2b207424ce15b9a83a9fa14422dcc1c5356a13aed3df9d"}, 975 | {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:34106f68e20e6ff253c9f596ea50397dbd8699828d55e8fa18bd4323d8d966e6"}, 976 | {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ebbbd0e728af5db9b04e56389e2299a57ea8b9dd15c9759153ee2455b32be6ad"}, 977 | {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6b1d1c631e5940cac5a0b22c5379c86e8df6a4ec277c7a856b714021ab6cfad"}, 978 | {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e891ce81edd463b3b4c3b885c5603c00141151dd9c6936d98a680c8c72fe5c67"}, 979 | {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9b273ecfbc590a1b98f014ae41e5cf723932f3b53ba9367cfb676f838038b32c"}, 980 | {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b32bff85fb02a75ea0b68f21e2412255b5731f3f389ed9aecc13a6752f58ac97"}, 981 | {file = "pyzmq-26.0.3-cp38-cp38-win32.whl", hash = "sha256:f6c21c00478a7bea93caaaef9e7629145d4153b15a8653e8bb4609d4bc70dbfc"}, 982 | {file = "pyzmq-26.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:3401613148d93ef0fd9aabdbddb212de3db7a4475367f49f590c837355343972"}, 983 | {file = "pyzmq-26.0.3-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:2ed8357f4c6e0daa4f3baf31832df8a33334e0fe5b020a61bc8b345a3db7a606"}, 984 | {file = "pyzmq-26.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c1c8f2a2ca45292084c75bb6d3a25545cff0ed931ed228d3a1810ae3758f975f"}, 985 | {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:b63731993cdddcc8e087c64e9cf003f909262b359110070183d7f3025d1c56b5"}, 986 | {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b3cd31f859b662ac5d7f4226ec7d8bd60384fa037fc02aee6ff0b53ba29a3ba8"}, 987 | {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:115f8359402fa527cf47708d6f8a0f8234f0e9ca0cab7c18c9c189c194dbf620"}, 988 | {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:715bdf952b9533ba13dfcf1f431a8f49e63cecc31d91d007bc1deb914f47d0e4"}, 989 | {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e1258c639e00bf5e8a522fec6c3eaa3e30cf1c23a2f21a586be7e04d50c9acab"}, 990 | {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:15c59e780be8f30a60816a9adab900c12a58d79c1ac742b4a8df044ab2a6d920"}, 991 | {file = "pyzmq-26.0.3-cp39-cp39-win32.whl", hash = "sha256:d0cdde3c78d8ab5b46595054e5def32a755fc028685add5ddc7403e9f6de9879"}, 992 | {file = "pyzmq-26.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:ce828058d482ef860746bf532822842e0ff484e27f540ef5c813d516dd8896d2"}, 993 | {file = "pyzmq-26.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:788f15721c64109cf720791714dc14afd0f449d63f3a5487724f024345067381"}, 994 | {file = "pyzmq-26.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2c18645ef6294d99b256806e34653e86236eb266278c8ec8112622b61db255de"}, 995 | {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7e6bc96ebe49604df3ec2c6389cc3876cabe475e6bfc84ced1bf4e630662cb35"}, 996 | {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:971e8990c5cc4ddcff26e149398fc7b0f6a042306e82500f5e8db3b10ce69f84"}, 997 | {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8416c23161abd94cc7da80c734ad7c9f5dbebdadfdaa77dad78244457448223"}, 998 | {file = "pyzmq-26.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:082a2988364b60bb5de809373098361cf1dbb239623e39e46cb18bc035ed9c0c"}, 999 | {file = "pyzmq-26.0.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d57dfbf9737763b3a60d26e6800e02e04284926329aee8fb01049635e957fe81"}, 1000 | {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:77a85dca4c2430ac04dc2a2185c2deb3858a34fe7f403d0a946fa56970cf60a1"}, 1001 | {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4c82a6d952a1d555bf4be42b6532927d2a5686dd3c3e280e5f63225ab47ac1f5"}, 1002 | {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4496b1282c70c442809fc1b151977c3d967bfb33e4e17cedbf226d97de18f709"}, 1003 | {file = "pyzmq-26.0.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:e4946d6bdb7ba972dfda282f9127e5756d4f299028b1566d1245fa0d438847e6"}, 1004 | {file = "pyzmq-26.0.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:03c0ae165e700364b266876d712acb1ac02693acd920afa67da2ebb91a0b3c09"}, 1005 | {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3e3070e680f79887d60feeda051a58d0ac36622e1759f305a41059eff62c6da7"}, 1006 | {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6ca08b840fe95d1c2bd9ab92dac5685f949fc6f9ae820ec16193e5ddf603c3b2"}, 1007 | {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e76654e9dbfb835b3518f9938e565c7806976c07b37c33526b574cc1a1050480"}, 1008 | {file = "pyzmq-26.0.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:871587bdadd1075b112e697173e946a07d722459d20716ceb3d1bd6c64bd08ce"}, 1009 | {file = "pyzmq-26.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d0a2d1bd63a4ad79483049b26514e70fa618ce6115220da9efdff63688808b17"}, 1010 | {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0270b49b6847f0d106d64b5086e9ad5dc8a902413b5dbbb15d12b60f9c1747a4"}, 1011 | {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:703c60b9910488d3d0954ca585c34f541e506a091a41930e663a098d3b794c67"}, 1012 | {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74423631b6be371edfbf7eabb02ab995c2563fee60a80a30829176842e71722a"}, 1013 | {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4adfbb5451196842a88fda3612e2c0414134874bffb1c2ce83ab4242ec9e027d"}, 1014 | {file = "pyzmq-26.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3516119f4f9b8671083a70b6afaa0a070f5683e431ab3dc26e9215620d7ca1ad"}, 1015 | {file = "pyzmq-26.0.3.tar.gz", hash = "sha256:dba7d9f2e047dfa2bca3b01f4f84aa5246725203d6284e3790f2ca15fba6b40a"}, 1016 | ] 1017 | 1018 | [package.dependencies] 1019 | cffi = {version = "*", markers = "implementation_name == \"pypy\""} 1020 | 1021 | [[package]] 1022 | name = "ruff" 1023 | version = "0.0.275" 1024 | description = "An extremely fast Python linter, written in Rust." 1025 | optional = false 1026 | python-versions = ">=3.7" 1027 | groups = ["dev"] 1028 | files = [ 1029 | {file = "ruff-0.0.275-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:5e6554a072e7ce81eb6f0bec1cebd3dcb0e358652c0f4900d7d630d61691e914"}, 1030 | {file = "ruff-0.0.275-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:1cc599022fe5ffb143a965b8d659eb64161ab8ab4433d208777eab018a1aab67"}, 1031 | {file = "ruff-0.0.275-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5206fc1cd8c1c1deadd2e6360c0dbcd690f1c845da588ca9d32e4a764a402c60"}, 1032 | {file = "ruff-0.0.275-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0c4e6468da26f77b90cae35319d310999f471a8c352998e9b39937a23750149e"}, 1033 | {file = "ruff-0.0.275-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0dbdea02942131dbc15dd45f431d152224f15e1dd1859fcd0c0487b658f60f1a"}, 1034 | {file = "ruff-0.0.275-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:22efd9f41af27ef8fb9779462c46c35c89134d33e326c889971e10b2eaf50c63"}, 1035 | {file = "ruff-0.0.275-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2c09662112cfa22d7467a19252a546291fd0eae4f423e52b75a7a2000a1894db"}, 1036 | {file = "ruff-0.0.275-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80043726662144876a381efaab88841c88e8df8baa69559f96b22d4fa216bef1"}, 1037 | {file = "ruff-0.0.275-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5859ee543b01b7eb67835dfd505faa8bb7cc1550f0295c92c1401b45b42be399"}, 1038 | {file = "ruff-0.0.275-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c8ace4d40a57b5ea3c16555f25a6b16bc5d8b2779ae1912ce2633543d4e9b1da"}, 1039 | {file = "ruff-0.0.275-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8347fc16aa185aae275906c4ac5b770e00c896b6a0acd5ba521f158801911998"}, 1040 | {file = "ruff-0.0.275-py3-none-musllinux_1_2_i686.whl", hash = "sha256:ec43658c64bfda44fd84bbea9da8c7a3b34f65448192d1c4dd63e9f4e7abfdd4"}, 1041 | {file = "ruff-0.0.275-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:508b13f7ca37274cceaba4fb3ea5da6ca192356323d92acf39462337c33ad14e"}, 1042 | {file = "ruff-0.0.275-py3-none-win32.whl", hash = "sha256:6afb1c4422f24f361e877937e2a44b3f8176774a476f5e33845ebfe887dd5ec2"}, 1043 | {file = "ruff-0.0.275-py3-none-win_amd64.whl", hash = "sha256:d9b264d78621bf7b698b6755d4913ab52c19bd28bee1a16001f954d64c1a1220"}, 1044 | {file = "ruff-0.0.275-py3-none-win_arm64.whl", hash = "sha256:a19ce3bea71023eee5f0f089dde4a4272d088d5ac0b675867e074983238ccc65"}, 1045 | {file = "ruff-0.0.275.tar.gz", hash = "sha256:a63a0b645da699ae5c758fce19188e901b3033ec54d862d93fcd042addf7f38d"}, 1046 | ] 1047 | 1048 | [[package]] 1049 | name = "six" 1050 | version = "1.16.0" 1051 | description = "Python 2 and 3 compatibility utilities" 1052 | optional = false 1053 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" 1054 | groups = ["dev"] 1055 | files = [ 1056 | {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, 1057 | {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, 1058 | ] 1059 | 1060 | [[package]] 1061 | name = "stack-data" 1062 | version = "0.6.3" 1063 | description = "Extract data from python stack frames and tracebacks for informative displays" 1064 | optional = false 1065 | python-versions = "*" 1066 | groups = ["dev"] 1067 | files = [ 1068 | {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, 1069 | {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, 1070 | ] 1071 | 1072 | [package.dependencies] 1073 | asttokens = ">=2.1.0" 1074 | executing = ">=1.2.0" 1075 | pure-eval = "*" 1076 | 1077 | [package.extras] 1078 | tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] 1079 | 1080 | [[package]] 1081 | name = "tornado" 1082 | version = "6.5.1" 1083 | description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." 1084 | optional = false 1085 | python-versions = ">=3.9" 1086 | groups = ["dev"] 1087 | files = [ 1088 | {file = "tornado-6.5.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d50065ba7fd11d3bd41bcad0825227cc9a95154bad83239357094c36708001f7"}, 1089 | {file = "tornado-6.5.1-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9e9ca370f717997cb85606d074b0e5b247282cf5e2e1611568b8821afe0342d6"}, 1090 | {file = "tornado-6.5.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b77e9dfa7ed69754a54c89d82ef746398be82f749df69c4d3abe75c4d1ff4888"}, 1091 | {file = "tornado-6.5.1-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:253b76040ee3bab8bcf7ba9feb136436a3787208717a1fb9f2c16b744fba7331"}, 1092 | {file = "tornado-6.5.1-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:308473f4cc5a76227157cdf904de33ac268af770b2c5f05ca6c1161d82fdd95e"}, 1093 | {file = "tornado-6.5.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:caec6314ce8a81cf69bd89909f4b633b9f523834dc1a352021775d45e51d9401"}, 1094 | {file = "tornado-6.5.1-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:13ce6e3396c24e2808774741331638ee6c2f50b114b97a55c5b442df65fd9692"}, 1095 | {file = "tornado-6.5.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5cae6145f4cdf5ab24744526cc0f55a17d76f02c98f4cff9daa08ae9a217448a"}, 1096 | {file = "tornado-6.5.1-cp39-abi3-win32.whl", hash = "sha256:e0a36e1bc684dca10b1aa75a31df8bdfed656831489bc1e6a6ebed05dc1ec365"}, 1097 | {file = "tornado-6.5.1-cp39-abi3-win_amd64.whl", hash = "sha256:908e7d64567cecd4c2b458075589a775063453aeb1d2a1853eedb806922f568b"}, 1098 | {file = "tornado-6.5.1-cp39-abi3-win_arm64.whl", hash = "sha256:02420a0eb7bf617257b9935e2b754d1b63897525d8a289c9d65690d580b4dcf7"}, 1099 | {file = "tornado-6.5.1.tar.gz", hash = "sha256:84ceece391e8eb9b2b95578db65e920d2a61070260594819589609ba9bc6308c"}, 1100 | ] 1101 | 1102 | [[package]] 1103 | name = "traitlets" 1104 | version = "5.14.3" 1105 | description = "Traitlets Python configuration system" 1106 | optional = false 1107 | python-versions = ">=3.8" 1108 | groups = ["dev"] 1109 | files = [ 1110 | {file = "traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"}, 1111 | {file = "traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7"}, 1112 | ] 1113 | 1114 | [package.extras] 1115 | docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] 1116 | test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<8.2)", "pytest-mock", "pytest-mypy-testing"] 1117 | 1118 | [[package]] 1119 | name = "typing-extensions" 1120 | version = "4.12.2" 1121 | description = "Backported and Experimental Type Hints for Python 3.8+" 1122 | optional = false 1123 | python-versions = ">=3.8" 1124 | groups = ["dev"] 1125 | markers = "python_version < \"3.12\"" 1126 | files = [ 1127 | {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, 1128 | {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, 1129 | ] 1130 | 1131 | [[package]] 1132 | name = "virtualenv" 1133 | version = "20.26.6" 1134 | description = "Virtual Python Environment builder" 1135 | optional = false 1136 | python-versions = ">=3.7" 1137 | groups = ["dev"] 1138 | files = [ 1139 | {file = "virtualenv-20.26.6-py3-none-any.whl", hash = "sha256:7345cc5b25405607a624d8418154577459c3e0277f5466dd79c49d5e492995f2"}, 1140 | {file = "virtualenv-20.26.6.tar.gz", hash = "sha256:280aede09a2a5c317e409a00102e7077c6432c5a38f0ef938e643805a7ad2c48"}, 1141 | ] 1142 | 1143 | [package.dependencies] 1144 | distlib = ">=0.3.7,<1" 1145 | filelock = ">=3.12.2,<4" 1146 | platformdirs = ">=3.9.1,<5" 1147 | 1148 | [package.extras] 1149 | docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] 1150 | test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8) ; platform_python_implementation == \"PyPy\" or platform_python_implementation == \"CPython\" and sys_platform == \"win32\" and python_version >= \"3.13\"", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10) ; platform_python_implementation == \"CPython\""] 1151 | 1152 | [[package]] 1153 | name = "wcwidth" 1154 | version = "0.2.13" 1155 | description = "Measures the displayed width of unicode strings in a terminal" 1156 | optional = false 1157 | python-versions = "*" 1158 | groups = ["dev"] 1159 | files = [ 1160 | {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, 1161 | {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, 1162 | ] 1163 | 1164 | [metadata] 1165 | lock-version = "2.1" 1166 | python-versions = "^3.11" 1167 | content-hash = "114cf31efe4b7b575b02aee82e926ee36552170de8b2ace9f1ea50fd040c4f57" 1168 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "parse2docs" 3 | version = "0.1.3" 4 | description = "Generate usage documentation from Python scripts using the `argparse` module" 5 | authors = ["Fernando Cordeiro"] 6 | readme = "README.md" 7 | license = "MIT" 8 | 9 | [tool.poetry.dependencies] 10 | python = "^3.11" 11 | 12 | [tool.poetry.group.dev.dependencies] 13 | black = ">=23.1,<25.0" 14 | pre-commit = "^3.2.2" 15 | ipykernel = "^6.22.0" 16 | ruff = "^0.0.275" 17 | pytest = "^7.4.0" 18 | pytest-cov = "^4.1.0" 19 | 20 | [tool.poetry.scripts] 21 | parse2docs = "parse2docs.app:execute_from_command_line" 22 | 23 | [tool.coverage.report] 24 | fail_under = 90 25 | 26 | [tool.coverage.run] 27 | omit = ["tests/*"] 28 | 29 | [build-system] 30 | requires = ["poetry-core"] 31 | build-backend = "poetry.core.masonry.api" 32 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrCordeiro/parse2docs/ff0a1aec98359e2e4cf6542d2e3e39956335882c/tests/__init__.py -------------------------------------------------------------------------------- /tests/demo_parser_in_function.py: -------------------------------------------------------------------------------- 1 | """Sample script that copies a file from source to destination.""" 2 | 3 | import argparse 4 | import shutil 5 | 6 | 7 | def copy_file(src, dest): 8 | """ 9 | Function to copy a file from source to destination. 10 | 11 | :param src: Source file path 12 | :type src: str 13 | :param dest: Destination file path 14 | :type dest: str 15 | """ 16 | shutil.copy2(src, dest) 17 | 18 | 19 | def main(): 20 | """ 21 | Main function to parse command line arguments and execute file copy. 22 | """ 23 | parser = get_argument_parser() 24 | 25 | args = parser.parse_args() 26 | 27 | if args.verbose: 28 | print(f"Copying file from {args.source} to {args.destination}") 29 | 30 | copy_file(args.source, args.destination) 31 | 32 | if args.verbose: 33 | print("File copied successfully") 34 | 35 | 36 | def get_argument_parser(): 37 | parser = argparse.ArgumentParser(description="A simple file copy script.") 38 | parser.add_argument( 39 | "-s", 40 | "--source", 41 | type=str, 42 | required=True, 43 | help="Source file path. Example: -s '/path/to/source'", 44 | ) 45 | parser.add_argument( 46 | "-d", "--destination", type=str, required=True, help="Destination file path" 47 | ) 48 | parser.add_argument( 49 | "-v", "--verbose", action="store_true", help="Enable verbose mode" 50 | ) 51 | 52 | return parser 53 | 54 | 55 | if __name__ == "__main__": 56 | main() 57 | -------------------------------------------------------------------------------- /tests/demo_parser_in_module.py: -------------------------------------------------------------------------------- 1 | """Sample script that copies a file from source to destination.""" 2 | 3 | import argparse 4 | import shutil 5 | 6 | 7 | def copy_file(src, dest): 8 | """ 9 | Function to copy a file from source to destination. 10 | 11 | :param src: Source file path 12 | :type src: str 13 | :param dest: Destination file path 14 | :type dest: str 15 | """ 16 | shutil.copy2(src, dest) 17 | 18 | 19 | parser = argparse.ArgumentParser(description="A simple file copy script.") 20 | parser.add_argument( 21 | "-s", 22 | "--source", 23 | type=str, 24 | required=True, 25 | help="Source file path. Example: -s '/path/to/source'", 26 | ) 27 | parser.add_argument( 28 | "-d", "--destination", type=str, required=True, help="Destination file path" 29 | ) 30 | parser.add_argument("-v", "--verbose", action="store_true", help="Enable verbose mode") 31 | 32 | 33 | def main(): 34 | """ 35 | Main function to parse command line arguments and execute file copy. 36 | """ 37 | 38 | args = parser.parse_args() 39 | 40 | if args.verbose: 41 | print(f"Copying file from {args.source} to {args.destination}") 42 | 43 | copy_file(args.source, args.destination) 44 | 45 | if args.verbose: 46 | print("File copied successfully") 47 | 48 | 49 | if __name__ == "__main__": 50 | main() 51 | -------------------------------------------------------------------------------- /tests/test_argfinder.py: -------------------------------------------------------------------------------- 1 | from argparse import ArgumentParser 2 | from types import ModuleType 3 | 4 | import pytest 5 | 6 | from parse2docs.argfinder import get_argparser_from_module 7 | 8 | from . import demo_parser_in_function, demo_parser_in_module 9 | 10 | 11 | def test_find_argparser_in_module(): 12 | assert isinstance(get_argparser_from_module(demo_parser_in_module), ArgumentParser) 13 | 14 | 15 | def test_find_argparser_in_functions(): 16 | assert isinstance( 17 | get_argparser_from_module(demo_parser_in_function), ArgumentParser 18 | ) 19 | 20 | 21 | def testget_argparser_from_module_no_parser(): 22 | empty_module = ModuleType("empty_module", "Empty test module") 23 | with pytest.raises(ValueError): 24 | get_argparser_from_module(empty_module) 25 | -------------------------------------------------------------------------------- /tests/test_markdown_renderer.py: -------------------------------------------------------------------------------- 1 | from argparse import ArgumentParser 2 | from unittest.mock import patch 3 | 4 | import pytest 5 | 6 | from parse2docs.markdown_renderer import ( 7 | _add_description, 8 | _add_overall_usage, 9 | _add_table_of_contents, 10 | _document_action, 11 | generate_markdown, 12 | ) 13 | 14 | 15 | @pytest.fixture 16 | def parser(): 17 | parser = ArgumentParser(description="A simple file copy script.") 18 | parser.add_argument( 19 | "-s", 20 | "--source", 21 | metavar="source_path", 22 | type=str, 23 | required=True, 24 | help="Source file path", 25 | ) 26 | parser.add_argument( 27 | "-d", 28 | "--destination", 29 | metavar="dest_path", 30 | type=str, 31 | required=True, 32 | help="Destination file path", 33 | ) 34 | parser.add_argument( 35 | "-v", "--verbose", action="store_true", help="Enable verbose mode" 36 | ) 37 | return parser 38 | 39 | 40 | @pytest.fixture 41 | def empty_parser(): 42 | return ArgumentParser(description="A script with no options.") 43 | 44 | 45 | def test_generate_markdown(parser: ArgumentParser): 46 | markdown = generate_markdown(parser) 47 | assert "# Usage Documentation" in markdown 48 | assert "## Description" in markdown 49 | assert "A simple file copy script." in markdown 50 | assert "## Overall Usage Example" in markdown 51 | assert "## Table of Contents" in markdown 52 | assert "## Options" in markdown 53 | 54 | 55 | def test_generate_markdown_on_empty_parser(empty_parser: ArgumentParser): 56 | markdown = generate_markdown(empty_parser) 57 | assert ( 58 | "## Options" not in markdown 59 | ), "Options section should not be present on a parser with no arguments" 60 | 61 | 62 | def test_add_description(parser: ArgumentParser): 63 | description = _add_description(parser) 64 | assert ( 65 | description == "## Description\n\nA simple file copy script.\n\n" 66 | ), "Description should be added to the markdown" 67 | 68 | 69 | @pytest.mark.parametrize( 70 | "argv, script_name", 71 | [ 72 | (["parse2docs", "script.py"], "script.py"), 73 | (["poetry", "run", "parse2docs", "script.py"], "script.py"), 74 | (["script.py", "-s", "source"], "markdown_renderer.py"), 75 | ], 76 | ) 77 | def test_add_overall_usage(argv: list[str], script_name: str, parser: ArgumentParser): 78 | expected_usage = ( 79 | f"## Overall Usage Example\n\n`{script_name} -s -d " 80 | " [-v]`\n\n" 81 | ) 82 | with patch("parse2docs.module_loader.sys.argv", argv): 83 | usage = _add_overall_usage(parser) 84 | assert usage == expected_usage, "Overall usage should be added to the markdown" 85 | 86 | 87 | def test_add_table_of_contents(parser: ArgumentParser): 88 | contents = _add_table_of_contents(parser) 89 | assert "- [source](#source)" in contents 90 | assert "- [destination](#destination)" in contents 91 | assert "- [verbose](#verbose)" in contents 92 | 93 | 94 | def test_document_action(parser: ArgumentParser): 95 | for action in parser._actions: 96 | if action.dest == "help": 97 | continue 98 | 99 | expected_flags = f"**Flags**: `{', '.join(action.option_strings)}`\n\n" 100 | expected_required = f"**Required**: {'Yes' if action.required else 'No'}\n\n" 101 | 102 | if action.metavar: 103 | if action.option_strings: 104 | cmd_example = f"{action.option_strings[0]} <{action.metavar}>" 105 | else: 106 | cmd_example = action.metavar 107 | expected_usage = f"#### Example Usage\n\n`{cmd_example}`\n" 108 | else: 109 | expected_usage = "" 110 | 111 | documentation = _document_action(action) 112 | 113 | assert f"### {action.dest}\n\n" in documentation 114 | assert f"{action.help}\n\n" in documentation 115 | assert expected_flags in documentation 116 | assert expected_required in documentation 117 | assert expected_usage in documentation 118 | -------------------------------------------------------------------------------- /tests/test_module_loader.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from pathlib import Path 3 | 4 | from parse2docs.module_loader import SysPathContext, get_module_from_path 5 | 6 | 7 | def test_sys_path_context(): 8 | original_sys_path = sys.path.copy() 9 | test_file_path = Path(__file__).resolve() 10 | test_script_dir = str(test_file_path.parent) 11 | 12 | with SysPathContext(test_file_path): 13 | assert sys.path[0] == test_script_dir, ( 14 | "When entering the context, the first entry in sys.path should be the " 15 | "parent directory" 16 | ) 17 | 18 | assert ( 19 | sys.path == original_sys_path 20 | ), "When leaving the context, sys.path should be restored to its original state" 21 | 22 | 23 | def test_get_module_from_path(): 24 | # Test importing a module from a path 25 | demo_module_path = Path(__file__).parent / "demo_parser_in_module.py" 26 | demo_module = get_module_from_path(demo_module_path) 27 | assert hasattr(demo_module, "main") 28 | --------------------------------------------------------------------------------