├── tests ├── __init__.py ├── test_rich_tools.py ├── test_text.py └── test_table.py ├── .coveragerc ├── rich_tools ├── __init__.py ├── text.py └── table.py ├── examples ├── table_from_csv.py ├── sample_input.csv ├── strip_markup_tags.py ├── table_to_dicts.py ├── df_to_table.py └── table_to_df.py ├── .github ├── CODEOWNERS └── workflows │ ├── codecov.yml │ ├── test.yml │ └── codeql-analysis.yml ├── LICENSE ├── pyproject.toml ├── CONTRIBUTING.md ├── CHANGELOG.md ├── .gitignore ├── README.md └── poetry.lock /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | source=rich_tools -------------------------------------------------------------------------------- /rich_tools/__init__.py: -------------------------------------------------------------------------------- 1 | from .text import * # noqa: F403 2 | from .table import * # noqa: F403 3 | 4 | __version__ = "0.6.0" 5 | -------------------------------------------------------------------------------- /examples/table_from_csv.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from rich import print 3 | from rich_tools import df_to_table 4 | 5 | if __name__ == "__main__": 6 | df = pd.read_csv("sample_input.csv") 7 | table = df_to_table(df) 8 | print(table) 9 | -------------------------------------------------------------------------------- /examples/sample_input.csv: -------------------------------------------------------------------------------- 1 | Date,Title,Production Budget,Box Office 2 | "Dec 20, 2019",Star Wars: The Rise of Skywalker,"$275,000,000","$375,126,118" 3 | "May 25, 2018",Solo: A Star Wars Story,"$275,000,000","$393,151,347" 4 | "Dec 15, 2017",Star Wars Ep. VIII: The Last Jedi,"$262,000,000","$1,332,539,889" -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # CODEOWNERS 2 | # Configure pull request (PR) reviewers for different areas of the repository. 3 | # Docs: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners 4 | 5 | # Avi Perl is the overall reviewer for PRs. 6 | * @avi-perl -------------------------------------------------------------------------------- /examples/strip_markup_tags.py: -------------------------------------------------------------------------------- 1 | from rich.console import Console 2 | 3 | from rich_tools import strip_markup_tags 4 | 5 | console = Console() 6 | 7 | 8 | if __name__ == "__main__": 9 | string_example = ( 10 | "Where there is a [bold cyan]Will[/bold cyan] there [u]is[/u] a [i]way[/i]." 11 | ) 12 | 13 | print(f"Raw string: {string_example}") 14 | console.print(f"What is looks like: {string_example}") 15 | print(f"After calling strip_markup_tags(): {strip_markup_tags(string_example)}") 16 | -------------------------------------------------------------------------------- /tests/test_rich_tools.py: -------------------------------------------------------------------------------- 1 | import toml 2 | from pathlib import Path 3 | 4 | from rich_tools import __version__ 5 | 6 | 7 | def test_versions_are_in_sync(): 8 | """Checks if the pyproject.toml and package.__init__.py __version__ are in sync.""" 9 | 10 | path = Path(__file__).resolve().parents[1] / "pyproject.toml" 11 | pyproject = toml.loads(open(str(path)).read()) 12 | pyproject_version = pyproject["tool"]["poetry"]["version"] 13 | 14 | package_init_version = __version__ 15 | 16 | assert package_init_version == pyproject_version 17 | -------------------------------------------------------------------------------- /tests/test_text.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """Tests for `rich_tools.text`""" 4 | 5 | from rich_tools import strip_markup_tags 6 | from rich_tools.text import _strip_tags 7 | 8 | 9 | def test_strip_markup_tags(): 10 | marked_up_text = "[bold]Bold[/bold]" 11 | assert strip_markup_tags(marked_up_text) == "Bold" 12 | 13 | 14 | def test__strip_tags_do_false(): 15 | marked_up_text = "[bold]Bold[/bold]" 16 | assert _strip_tags(marked_up_text, do=False) == marked_up_text 17 | 18 | 19 | def test__strip_tags_do_true(): 20 | marked_up_text = "[bold]Bold[/bold]" 21 | assert _strip_tags(marked_up_text, do=True) == "Bold" 22 | -------------------------------------------------------------------------------- /.github/workflows/codecov.yml: -------------------------------------------------------------------------------- 1 | name: Codecov 2 | on: [push] 3 | jobs: 4 | run: 5 | runs-on: ${{ matrix.os }} 6 | strategy: 7 | matrix: 8 | os: [ubuntu-latest, macos-latest, windows-latest] 9 | env: 10 | OS: ${{ matrix.os }} 11 | PYTHON: '3.9' 12 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 13 | steps: 14 | - uses: actions/checkout@master 15 | - name: Setup Python 16 | uses: actions/setup-python@master 17 | with: 18 | python-version: 3.9 19 | - name: Generate coverage report 20 | run: | 21 | pip install pytest 22 | pip install pytest-cov 23 | pip install poetry 24 | poetry install 25 | poetry run pytest --cov=./ --cov-report=xml 26 | - name: Upload coverage to Codecov 27 | uses: codecov/codecov-action@v2 28 | with: 29 | flags: unittests 30 | verbose: true -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2025 Avrohom Perl 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /examples/table_to_dicts.py: -------------------------------------------------------------------------------- 1 | from rich import print 2 | from rich.table import Table 3 | from rich_tools import table_to_dicts 4 | 5 | 6 | if __name__ == "__main__": 7 | table = Table(show_header=True, header_style="bold magenta") 8 | table.add_column("Date", style="dim", width=12) 9 | table.add_column("Title") 10 | table.add_column("Production Budget", justify="right") 11 | table.add_column("Box Office", justify="right") 12 | table.add_row( 13 | "Dec 20, 2019", 14 | "Star Wars: The Rise of Skywalker", 15 | "$275,000,000", 16 | "$375,126,118", 17 | ) 18 | table.add_row( 19 | "May 25, 2018", 20 | "[red]Solo[/red]: A Star Wars Story", 21 | "$275,000,000", 22 | "$393,151,347", 23 | ) 24 | table.add_row( 25 | "Dec 15, 2017", 26 | "Star Wars Ep. VIII: The Last Jedi", 27 | "$262,000,000", 28 | "[bold]$1,332,539,889[/bold]", 29 | ) 30 | 31 | table_items = table_to_dicts(table) 32 | 33 | for item in table_items: 34 | print(item) 35 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | strategy: 13 | matrix: 14 | python-version: ["3.13", "3.12", "3.11", "3.10", 3.9, 3.8] 15 | steps: 16 | - uses: actions/checkout@v4 17 | - name: Set up Python ${{ matrix.python-version }} 18 | uses: actions/setup-python@v5 19 | with: 20 | python-version: ${{ matrix.python-version }} 21 | 22 | - name: Install Poetry 23 | run: | 24 | python -m pip install --upgrade pip 25 | pip install poetry 26 | 27 | - name: Install dependencies with Poetry 28 | run: | 29 | poetry install 30 | 31 | - name: Lint with Ruff 32 | run: | 33 | poetry run ruff check 34 | 35 | - name: Format with Ruff 36 | run: | 37 | poetry run ruff format 38 | 39 | - name: Test with pytest 40 | run: | 41 | poetry run pytest 42 | -------------------------------------------------------------------------------- /examples/df_to_table.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | 3 | import pandas as pd 4 | from rich import box 5 | from rich.console import Console 6 | 7 | from rich_tools import df_to_table 8 | 9 | console = Console() 10 | 11 | 12 | if __name__ == "__main__": 13 | sample_data = { 14 | "Date": [ 15 | datetime(year=2019, month=12, day=20), 16 | datetime(year=2018, month=5, day=25), 17 | datetime(year=2017, month=12, day=15), 18 | ], 19 | "Title": [ 20 | "Star Wars: The Rise of Skywalker", 21 | "[red]Solo[/red]: A Star Wars Story", 22 | "Star Wars Ep. VIII: The Last Jedi", 23 | ], 24 | "Production Budget": ["$275,000,000", "$275,000,000", "$262,000,000"], 25 | "Box Office": ["$375,126,118", "$393,151,347", "$1,332,539,889"], 26 | } 27 | df = pd.DataFrame(sample_data) 28 | 29 | # Modify the table instance to have the data from the DataFrame 30 | table = df_to_table(df) 31 | 32 | # Update the style of the table 33 | table.row_styles = ["none", "dim"] 34 | table.box = box.SIMPLE_HEAD 35 | 36 | console.print(table) 37 | -------------------------------------------------------------------------------- /examples/table_to_df.py: -------------------------------------------------------------------------------- 1 | from rich.console import Console 2 | from rich.table import Table 3 | 4 | from rich_tools import table_to_df 5 | 6 | console = Console() 7 | 8 | 9 | if __name__ == "__main__": 10 | table = Table(show_header=True, header_style="bold magenta") 11 | table.add_column("Date", style="dim", width=12) 12 | table.add_column("Title") 13 | table.add_column("Production Budget", justify="right") 14 | table.add_column("Box Office", justify="right") 15 | table.add_row( 16 | "Dec 20, 2019", 17 | "Star Wars: The Rise of Skywalker", 18 | "$275,000,000", 19 | "$375,126,118", 20 | ) 21 | table.add_row( 22 | "May 25, 2018", 23 | "[red]Solo[/red]: A Star Wars Story", 24 | "$275,000,000", 25 | "$393,151,347", 26 | ) 27 | table.add_row( 28 | "Dec 15, 2017", 29 | "Star Wars Ep. VIII: The Last Jedi", 30 | "$262,000,000", 31 | "[bold]$1,332,539,889[/bold]", 32 | ) 33 | 34 | # Show the rich Table 35 | console.print(table) 36 | 37 | # Convert the Table into a DataFrame 38 | df = table_to_df(table) 39 | print(df) 40 | -------------------------------------------------------------------------------- /rich_tools/text.py: -------------------------------------------------------------------------------- 1 | from rich.text import Text 2 | 3 | 4 | def strip_markup_tags(value: str) -> str: 5 | """Remove rich markup tags from a string. 6 | 7 | Example: "[bold]Bold[/bold]" becomes "Bold" 8 | 9 | Args: 10 | value (string): A string containing rich markup 11 | 12 | Returns: 13 | str: A plain string no longer containing rich markup.""" 14 | 15 | return Text.from_markup(value).plain 16 | 17 | 18 | def _strip_tags(value: str, do: bool) -> str: 19 | """Internal helper function to run `strip_markup_tags` conditionally. 20 | 21 | The purpose of this function is concise code when conditionally calling `strip_markup_tags`. 22 | 23 | For example: 24 | { 25 | _strip_tags(x.header, remove_markup): [_strip_tags(y, remove_markup) for y in x.cells] 26 | for x in rich_table.columns 27 | } 28 | This would be much more verbose without this helper function. 29 | 30 | Args: 31 | value (string): A string containing rich markup 32 | do (bool): A bool specifying if `_strip_tags` should do anything at all 33 | 34 | Returns: 35 | str: A string either containing rich markup, or not, depending on the value of `do`.""" 36 | 37 | if do: 38 | return strip_markup_tags(value) 39 | else: 40 | return value 41 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "rich-tools" 3 | version = "0.6.0" 4 | description = "A python package with helpful tools when working with the rich python library." 5 | authors = ["Avi Perl "] 6 | license = "MIT" 7 | readme = "README.md" 8 | repository = "https://github.com/avi-perl/rich_tools" 9 | keywords = ["rich", "pandas"] 10 | classifiers = [ 11 | "Development Status :: 4 - Beta", 12 | "Environment :: Console", 13 | "Intended Audience :: Developers", 14 | "Operating System :: Microsoft :: Windows", 15 | "Operating System :: MacOS", 16 | "Operating System :: POSIX :: Linux", 17 | "Programming Language :: Python :: 3.8", 18 | "Programming Language :: Python :: 3.9", 19 | "Programming Language :: Python :: 3.10", 20 | "Programming Language :: Python :: 3.11", 21 | "Programming Language :: Python :: 3.12", 22 | "Programming Language :: Python :: 3.13", 23 | "Typing :: Typed", 24 | ] 25 | 26 | [tool.poetry.dependencies] 27 | python = "^3.9" 28 | rich = "^14.1.0" 29 | pandas = "^2.2.2" 30 | 31 | [tool.poetry.dev-dependencies] 32 | pytest = "^8.3.2" 33 | coverage = "^7.6.1" 34 | pytest-cov = "^6.2.1" 35 | toml = "^0.10.2" 36 | 37 | [tool.poetry.group.dev.dependencies] 38 | ruff = "^0.6.4" 39 | 40 | [build-system] 41 | requires = ["poetry-core>=1.0.0"] 42 | build-backend = "poetry.core.masonry.api" 43 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Rich Tools 2 | 3 | This project welcomes contributions in the form of Pull Requests. 4 | For clear bug-fixes / typos etc. just submit a PR. 5 | For new features or if there is any doubt in how to fix a bug, you might want 6 | to open an issue prior to starting work. 7 | 8 | ## Development Environment 9 | 10 | Rich Tools uses [poetry](https://python-poetry.org/docs/) for packaging and 11 | dependency management. To start developing with Rich Tools, install Poetry 12 | using the [recommended method](https://python-poetry.org/docs/#installation) or run: 13 | 14 | ```bash 15 | pip install poetry 16 | ``` 17 | 18 | Once Poetry is installed, install the dependencies with the following command: 19 | 20 | ```bash 21 | poetry install 22 | ``` 23 | 24 | ### Tests 25 | 26 | Run tests with the following command: 27 | 28 | ```bash 29 | poetry run pytest 30 | ``` 31 | 32 | New code should ideally have tests and not break existing tests. 33 | 34 | If you are not familiar with writing tests but still want to contribute to this package, 35 | please feel free to submit your pull request, and I will work on tests. 🙂 36 | 37 | ### Type Checking 38 | 39 | Please add type annotations for all new code. 40 | 41 | ### Code Formatting 42 | 43 | Rich Tools uses [`Ruff`](https://github.com/astral-sh/ruff) for code formatting. 44 | I recommend setting up Ruff in your editor to format on save. 45 | 46 | To run Ruff from the command line: 47 | 48 | ```bash 49 | poetry run ruff check 50 | poetry run ruff format 51 | ``` -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [0.6.0] - 2025-08-25 9 | 10 | ### Changed 11 | 12 | - Updated rich to version 14.1.0 13 | 14 | ### Added 15 | 16 | - Added support for Python 3.13 17 | 18 | ### Removed 19 | 20 | - Removed support for Python 3.7 21 | 22 | ## [0.5.1] - 2024-09-09 23 | 24 | ### Changed 25 | 26 | - Library dependencies updated to latest versions of everything. 27 | - Migrated from use of Black to Ruff for linting and formatting. 28 | - Many thanks to [johnlettman](https://github.com/johnlettman) for his contributions and pushing me to upgrade. 29 | 30 | ## [0.5.0] - 2021-10-13 31 | 32 | ### Added 33 | 34 | - Added a new function `rich_tools.strip_markup_tags()` that removes rich markup tags from a string. 35 | It's a simple helper function to call the rich library's method: `Text.from_markup("[i]str[/i]").plain` 36 | 37 | ### Changed 38 | 39 | - `rich_tools.table_to_df()` now supports a `remove_markup` argument that when False will leave rich markup in the 40 | values added to the `df`. 41 | 42 | 43 | ## [0.4.0] - 2021-10-13 44 | 45 | ### Added 46 | 47 | - Added a new function `table_to_dicts()` that converts a `Table` instance's records into dictionaries and 48 | yields them back one at a time. 49 | 50 | 51 | ## [0.3.0] - 2021-10-12 52 | 53 | ### Changed 54 | 55 | - Made the passing of a `Table` instance to `df_to_table` optional. 56 | 57 | 58 | ## [0.2.0] - 2021-10-11 59 | 60 | ### Changed 61 | 62 | - Support (and encourage) importing functions directly from `rich_tools`. 63 | - Previously we would use `from rich_tools.table import df_to_table` 64 | - Now we support `from rich_tools import df_to_table` 65 | - The old import is still available if the extra namespace is your preference. 66 | 67 | 68 | ## [0.1.2] - 2021-10-10 69 | 70 | ### Changed 71 | 72 | - Changed the import of `pandas` in `rich_tools/table.py`. 73 | 74 | 75 | ## [0.1.0] - 2021-10-10 76 | 77 | ### Added 78 | 79 | - Added base code, tests, and examples for the first release. -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | schedule: 21 | - cron: '45 16 * * 2' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'python' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 37 | # Learn more: 38 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 39 | 40 | steps: 41 | - name: Checkout repository 42 | uses: actions/checkout@v2 43 | 44 | # Initializes the CodeQL tools for scanning. 45 | - name: Initialize CodeQL 46 | uses: github/codeql-action/init@v1 47 | with: 48 | languages: ${{ matrix.language }} 49 | # If you wish to specify custom queries, you can do so here or in a config file. 50 | # By default, queries listed here will override any specified in a config file. 51 | # Prefix the list here with "+" to use these queries and those in the config file. 52 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 53 | 54 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 55 | # If this step fails, then you should remove it and run the build manually (see below) 56 | - name: Autobuild 57 | uses: github/codeql-action/autobuild@v1 58 | 59 | # ℹ️ Command-line programs to run using the OS shell. 60 | # 📚 https://git.io/JvXDl 61 | 62 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 63 | # and modify them (or add more) to build your code if your project 64 | # uses a compiled language 65 | 66 | #- run: | 67 | # make bootstrap 68 | # make release 69 | 70 | - name: Perform CodeQL Analysis 71 | uses: github/codeql-action/analyze@v1 72 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 98 | __pypackages__/ 99 | 100 | # Celery stuff 101 | celerybeat-schedule 102 | celerybeat.pid 103 | 104 | # SageMath parsed files 105 | *.sage.py 106 | 107 | # Environments 108 | .env 109 | .venv 110 | env/ 111 | venv/ 112 | ENV/ 113 | env.bak/ 114 | venv.bak/ 115 | 116 | # Spyder project settings 117 | .spyderproject 118 | .spyproject 119 | 120 | # Rope project settings 121 | .ropeproject 122 | 123 | # mkdocs documentation 124 | /site 125 | 126 | # mypy 127 | .mypy_cache/ 128 | .dmypy.json 129 | dmypy.json 130 | 131 | # Pyre type checker 132 | .pyre/ 133 | 134 | # pytype static type analyzer 135 | .pytype/ 136 | 137 | # Cython debug symbols 138 | cython_debug/ 139 | 140 | #PyCharm 141 | .idea 142 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

🔧 Rich Tools

2 |

3 | A python package with helpful functions for use alongside with the rich python library. 4 |

5 |

6 | 7 | PyPI version 8 | 9 | 10 | Supported Python Versions 11 | 12 | 13 | Test 14 | 15 | 16 | 17 | 18 |

19 | 20 | --- 21 | 22 | #### The current features are: 23 | 24 | - **Convert a [Pandas](https://pandas.pydata.org/) DataFrame into a [rich](https://github.com/willmcgugan/rich) Table ➜ `df_to_table()`** 25 | 26 | By making this conversion, we can now pretty print a DataFrame in the terminal with rich. Bridging the gap between 27 | pandas and rich also provides a path for loading external data into a rich Table using Pandas functions such as `.from_csv()`! 28 | - **Convert a [rich](https://github.com/willmcgugan/rich) Table into a [Pandas](https://pandas.pydata.org/) DataFrame ➜ `table_to_df()`** 29 | 30 | By bridging the gap between a rich Table and a DataFrame, we can now take additional actions on our data such as 31 | saving the data to a csv using the Pandas function `.to_csv()`! 32 | - **Convert a [rich](https://github.com/willmcgugan/rich) Table into a list of dictionaries. ➜ `table_to_dicts()`** 33 | 34 | Get your tables rows as a list of dictionaries with column names as key, and row contents as values. 35 | - **Strip [rich](https://github.com/willmcgugan/rich) markup tags from a string. ➜ `strip_markup_tags()`** 36 | 37 | Helper function to remove tags from text formatted with rich. `"[bold]Bold[/bold]"` becomes `"Bold"` 38 | 39 | ### Installation 40 | ```bash 41 | $ pip install rich-tools 42 | ``` 43 | 44 | ### Example 45 | Additional examples can be found in the [examples](examples) dir. 46 | ```python 47 | # Print csv data to the terminal as a pretty printed rich formatted table 48 | 49 | import pandas as pd 50 | from rich import print 51 | from rich_tools import df_to_table 52 | 53 | if __name__ == '__main__': 54 | df = pd.read_csv("sample_input.csv") 55 | table = df_to_table(df) 56 | print(table) 57 | 58 | ``` 59 | 60 | ### Credits 61 | - Like the [rich](https://github.com/willmcgugan/rich) package itself, its creator [Will McGugan](https://twitter.com/willmcgugan) 62 | is awesome! Check out [Textual](https://github.com/willmcgugan/textual) "a TUI (Text User Interface) framework for 63 | Python inspired by modern web development". Thank you for the advice you've given on this project! 🙏 64 | - I am grateful for folks who give some of their time to this project in any form. Check out the list of 65 | [contributors](https://github.com/avi-perl/rich_tools/graphs/contributors) and learn more about contributing [here](CONTRIBUTING.md). -------------------------------------------------------------------------------- /rich_tools/table.py: -------------------------------------------------------------------------------- 1 | from typing import Optional, Iterator, Dict, Any 2 | 3 | import pandas as pd 4 | from rich.table import Table 5 | 6 | from rich_tools.text import _strip_tags 7 | 8 | 9 | def df_to_table( 10 | pandas_dataframe: pd.DataFrame, 11 | rich_table: Table = Table(), 12 | show_index: bool = True, 13 | index_name: Optional[str] = None, 14 | ) -> Table: 15 | """Convert a pandas.DataFrame obj into a rich.Table obj. 16 | 17 | Args: 18 | pandas_dataframe (DataFrame): A Pandas DataFrame to be converted to a rich Table. 19 | rich_table (Table): A rich Table that should be populated by the DataFrame values. 20 | show_index (bool): Add a column with a row count to the table. Defaults to True. 21 | index_name (str, optional): The column name to give to the index column. Defaults to None, showing no value. 22 | 23 | Returns: 24 | Table: The rich Table instance passed, populated with the DataFrame values.""" 25 | 26 | if show_index: 27 | index_name = str(index_name) if index_name else "" 28 | rich_table.add_column(index_name) 29 | 30 | for column in pandas_dataframe.columns: 31 | rich_table.add_column(str(column)) 32 | 33 | for index, value_list in enumerate(pandas_dataframe.values.tolist()): 34 | row = [str(index)] if show_index else [] 35 | row += [str(x) for x in value_list] 36 | rich_table.add_row(*row) 37 | 38 | return rich_table 39 | 40 | 41 | def table_to_df(rich_table: Table, remove_markup: bool = True) -> pd.DataFrame: 42 | """Convert a rich.Table obj into a pandas.DataFrame obj with any rich formatting removed from the values. 43 | 44 | Args: 45 | rich_table (Table): A rich Table that should be populated by the DataFrame values. 46 | remove_markup (bool): Removes rich markup from the keys and values in the table if True. 47 | 48 | Returns: 49 | DataFrame: A pandas DataFrame with the Table data as its values.""" 50 | 51 | return pd.DataFrame( 52 | { 53 | _strip_tags(x.header, remove_markup): [ 54 | _strip_tags(y, remove_markup) for y in x.cells 55 | ] 56 | for x in rich_table.columns 57 | } 58 | ) 59 | 60 | 61 | def table_to_dicts( 62 | rich_table: Table, remove_markup: bool = True 63 | ) -> Iterator[Dict[str, Any]]: 64 | """Convert a rich.Table obj into a list of dictionary's with keys set as column names. 65 | 66 | Args: 67 | rich_table (Table): A rich Table instance containing data to be converted into a list of dictionary's. 68 | remove_markup (bool): Removes rich markup from the keys and values in the table if True. 69 | 70 | Raises: 71 | ValueError: Raised in cases where the Table contains keys that do not make sense converted to a dict. 72 | For example if the Table has a header with an empty string or duplicate keys. 73 | 74 | Returns: 75 | Iterator: A list of the input Table's rows, each as a dictionary.""" 76 | 77 | column_keys = [_strip_tags(c.header, remove_markup) for c in rich_table.columns] 78 | 79 | if "" in column_keys: 80 | raise ValueError("You cannot convert a Table instance that has blank header") 81 | 82 | if len(column_keys) != len(set(column_keys)): 83 | raise ValueError( 84 | "You cannot convert a Table instance that has duplicate headers" 85 | ) 86 | 87 | column_values = [ 88 | [_strip_tags(v, remove_markup) for v in c._cells] for c in rich_table.columns 89 | ] 90 | 91 | return (dict(zip(column_keys, row_values)) for row_values in zip(*column_values)) 92 | -------------------------------------------------------------------------------- /tests/test_table.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """Tests for `rich_tools.table`""" 4 | 5 | from datetime import datetime 6 | 7 | import pytest 8 | 9 | import pandas as pd 10 | from rich.table import Table 11 | 12 | from rich_tools import table_to_df, df_to_table, table_to_dicts 13 | 14 | 15 | @pytest.fixture 16 | def df(): 17 | return pd.DataFrame.from_dict( 18 | { 19 | "field_1": [datetime.now(), print, "string", str, 1], 20 | "field_2": [datetime.now(), print, "string", str, 1], 21 | } 22 | ) 23 | 24 | 25 | @pytest.fixture 26 | def table(): 27 | table = Table() 28 | table.add_column("Date", style="dim", width=12) 29 | table.add_column("Title") 30 | table.add_column("Production Budget", justify="right") 31 | table.add_column("Box Office", justify="right") 32 | table.add_row( 33 | "Dec 20, 2019", 34 | "Star Wars: The Rise of Skywalker", 35 | "$275,000,000", 36 | "$375,126,118", 37 | ) 38 | table.add_row( 39 | "May 25, 2018", 40 | "[red]Solo[/red]: A Star Wars Story", 41 | "$275,000,000", 42 | "$393,151,347", 43 | ) 44 | table.add_row( 45 | "Dec 15, 2017", 46 | "Star Wars Ep. VIII: The Last Jedi", 47 | "$262,000,000", 48 | "[bold]$1,332,539,889[/bold]", 49 | ) 50 | return table 51 | 52 | 53 | def test_df_to_table(df): 54 | new_table = df_to_table(df, Table()) 55 | 56 | assert isinstance(new_table, Table) 57 | assert new_table.row_count == len(df.index) 58 | # Index was added to the table, so the number of columns will be +1 59 | assert len(new_table.columns) == df.shape[1] + 1 60 | 61 | 62 | def test_df_to_table_default_table(df): 63 | new_table = df_to_table(df) 64 | 65 | assert isinstance(new_table, Table) 66 | assert new_table.row_count == len(df.index) 67 | # Index was added to the table, so the number of columns will be +1 68 | assert len(new_table.columns) == df.shape[1] + 1 69 | 70 | 71 | def test_df_to_table_alt_table_used(df): 72 | table = Table(show_header=True, header_style="bold magenta") 73 | new_table = df_to_table(df, table) 74 | 75 | assert new_table.header_style == "bold magenta" 76 | assert df_to_table(df).header_style != "bold magenta" 77 | 78 | 79 | def test_df_to_table_show_index_true(df): 80 | new_table = df_to_table(df, Table(), show_index=True) 81 | assert len(new_table.columns) == df.shape[1] + 1 82 | 83 | 84 | def test_df_to_table_show_index_false(df): 85 | new_table = df_to_table(df, Table(), show_index=False) 86 | assert len(new_table.columns) == df.shape[1] 87 | 88 | 89 | def test_df_to_table_index_name(df): 90 | new_table = df_to_table(df, Table(), index_name="test") 91 | assert len(new_table.columns) == df.shape[1] + 1 92 | assert new_table.columns[0].header == "test" 93 | 94 | new_table = df_to_table(df, Table(), index_name=1) 95 | assert new_table.columns[0].header == "1" 96 | 97 | 98 | def test_table_to_df(table): 99 | df = table_to_df(table) 100 | 101 | assert isinstance(df, pd.DataFrame) 102 | assert len(df.index) == table.row_count 103 | assert df.shape[1] == len(table.columns) 104 | 105 | 106 | def test_table_to_df_remove_markup_false(): 107 | table = Table() 108 | table.add_column("[bold]Bold[/bold]") 109 | table.add_row( 110 | "[bold]Bold value[/bold]", 111 | ) 112 | 113 | df = table_to_df(table, remove_markup=False) 114 | df_col_names = df.columns.values.tolist() 115 | 116 | assert df_col_names[0] == "[bold]Bold[/bold]" 117 | assert df.loc[0, :].values.tolist()[0] == "[bold]Bold value[/bold]" 118 | 119 | 120 | def test_table_to_df_remove_markup_true(): 121 | table = Table() 122 | table.add_column("[bold]Bold[/bold]") 123 | table.add_row( 124 | "[bold]Bold value[/bold]", 125 | ) 126 | 127 | df = table_to_df(table, remove_markup=True) 128 | df_col_names = df.columns.values.tolist() 129 | 130 | assert df_col_names[0] == "Bold" 131 | assert df.loc[0, :].values.tolist()[0] == "Bold value" 132 | 133 | 134 | def test_table_to_dicts(table): 135 | dicts = table_to_dicts(table) 136 | assert table.row_count == len(list(dicts)) 137 | 138 | 139 | def test_table_to_dicts_blank_header(): 140 | table = Table() 141 | table.add_column("") 142 | table.add_column("Title") 143 | table.add_row( 144 | "0", 145 | "Title", 146 | ) 147 | 148 | with pytest.raises(ValueError): 149 | table_to_dicts(table) 150 | 151 | 152 | def test_table_to_dicts_dupe_header(): 153 | table = Table() 154 | table.add_column("Title") 155 | table.add_column("Title") 156 | table.add_row( 157 | "Title", 158 | "Title", 159 | ) 160 | 161 | with pytest.raises(ValueError): 162 | table_to_dicts(table) 163 | 164 | 165 | def test_table_to_dicts_remove_markup_true(): 166 | table = Table() 167 | table.add_column("[bold]Bold[/bold]") 168 | table.add_row( 169 | "[bold]Bold value[/bold]", 170 | ) 171 | 172 | dicts = table_to_dicts(table, remove_markup=True) 173 | dicts = list(dicts) 174 | 175 | assert list(dicts[0].keys())[0] == "Bold" 176 | assert list(dicts[0].values())[0] == "Bold value" 177 | 178 | 179 | def test_table_to_dicts_remove_markup_false(): 180 | table = Table() 181 | table.add_column("[bold]Bold[/bold]") 182 | table.add_row( 183 | "[bold]Bold value[/bold]", 184 | ) 185 | 186 | dicts = table_to_dicts(table, remove_markup=False) 187 | dicts = list(dicts) 188 | 189 | assert list(dicts[0].keys())[0] == "[bold]Bold[/bold]" 190 | assert list(dicts[0].values())[0] == "[bold]Bold value[/bold]" 191 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. 2 | 3 | [[package]] 4 | name = "colorama" 5 | version = "0.4.6" 6 | description = "Cross-platform colored terminal text." 7 | optional = false 8 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" 9 | files = [ 10 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, 11 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, 12 | ] 13 | 14 | [[package]] 15 | name = "coverage" 16 | version = "7.10.5" 17 | description = "Code coverage measurement for Python" 18 | optional = false 19 | python-versions = ">=3.9" 20 | files = [ 21 | {file = "coverage-7.10.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c6a5c3414bfc7451b879141ce772c546985163cf553f08e0f135f0699a911801"}, 22 | {file = "coverage-7.10.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bc8e4d99ce82f1710cc3c125adc30fd1487d3cf6c2cd4994d78d68a47b16989a"}, 23 | {file = "coverage-7.10.5-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:02252dc1216e512a9311f596b3169fad54abcb13827a8d76d5630c798a50a754"}, 24 | {file = "coverage-7.10.5-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:73269df37883e02d460bee0cc16be90509faea1e3bd105d77360b512d5bb9c33"}, 25 | {file = "coverage-7.10.5-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f8a81b0614642f91c9effd53eec284f965577591f51f547a1cbeb32035b4c2f"}, 26 | {file = "coverage-7.10.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6a29f8e0adb7f8c2b95fa2d4566a1d6e6722e0a637634c6563cb1ab844427dd9"}, 27 | {file = "coverage-7.10.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fcf6ab569436b4a647d4e91accba12509ad9f2554bc93d3aee23cc596e7f99c3"}, 28 | {file = "coverage-7.10.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:90dc3d6fb222b194a5de60af8d190bedeeddcbc7add317e4a3cd333ee6b7c879"}, 29 | {file = "coverage-7.10.5-cp310-cp310-win32.whl", hash = "sha256:414a568cd545f9dc75f0686a0049393de8098414b58ea071e03395505b73d7a8"}, 30 | {file = "coverage-7.10.5-cp310-cp310-win_amd64.whl", hash = "sha256:e551f9d03347196271935fd3c0c165f0e8c049220280c1120de0084d65e9c7ff"}, 31 | {file = "coverage-7.10.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c177e6ffe2ebc7c410785307758ee21258aa8e8092b44d09a2da767834f075f2"}, 32 | {file = "coverage-7.10.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:14d6071c51ad0f703d6440827eaa46386169b5fdced42631d5a5ac419616046f"}, 33 | {file = "coverage-7.10.5-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:61f78c7c3bc272a410c5ae3fde7792b4ffb4acc03d35a7df73ca8978826bb7ab"}, 34 | {file = "coverage-7.10.5-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f39071caa126f69d63f99b324fb08c7b1da2ec28cbb1fe7b5b1799926492f65c"}, 35 | {file = "coverage-7.10.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:343a023193f04d46edc46b2616cdbee68c94dd10208ecd3adc56fcc54ef2baa1"}, 36 | {file = "coverage-7.10.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:585ffe93ae5894d1ebdee69fc0b0d4b7c75d8007983692fb300ac98eed146f78"}, 37 | {file = "coverage-7.10.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b0ef4e66f006ed181df29b59921bd8fc7ed7cd6a9289295cd8b2824b49b570df"}, 38 | {file = "coverage-7.10.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:eb7b0bbf7cc1d0453b843eca7b5fa017874735bef9bfdfa4121373d2cc885ed6"}, 39 | {file = "coverage-7.10.5-cp311-cp311-win32.whl", hash = "sha256:1d043a8a06987cc0c98516e57c4d3fc2c1591364831e9deb59c9e1b4937e8caf"}, 40 | {file = "coverage-7.10.5-cp311-cp311-win_amd64.whl", hash = "sha256:fefafcca09c3ac56372ef64a40f5fe17c5592fab906e0fdffd09543f3012ba50"}, 41 | {file = "coverage-7.10.5-cp311-cp311-win_arm64.whl", hash = "sha256:7e78b767da8b5fc5b2faa69bb001edafcd6f3995b42a331c53ef9572c55ceb82"}, 42 | {file = "coverage-7.10.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c2d05c7e73c60a4cecc7d9b60dbfd603b4ebc0adafaef371445b47d0f805c8a9"}, 43 | {file = "coverage-7.10.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:32ddaa3b2c509778ed5373b177eb2bf5662405493baeff52278a0b4f9415188b"}, 44 | {file = "coverage-7.10.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:dd382410039fe062097aa0292ab6335a3f1e7af7bba2ef8d27dcda484918f20c"}, 45 | {file = "coverage-7.10.5-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7fa22800f3908df31cea6fb230f20ac49e343515d968cc3a42b30d5c3ebf9b5a"}, 46 | {file = "coverage-7.10.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f366a57ac81f5e12797136552f5b7502fa053c861a009b91b80ed51f2ce651c6"}, 47 | {file = "coverage-7.10.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5f1dc8f1980a272ad4a6c84cba7981792344dad33bf5869361576b7aef42733a"}, 48 | {file = "coverage-7.10.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2285c04ee8676f7938b02b4936d9b9b672064daab3187c20f73a55f3d70e6b4a"}, 49 | {file = "coverage-7.10.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c2492e4dd9daab63f5f56286f8a04c51323d237631eb98505d87e4c4ff19ec34"}, 50 | {file = "coverage-7.10.5-cp312-cp312-win32.whl", hash = "sha256:38a9109c4ee8135d5df5505384fc2f20287a47ccbe0b3f04c53c9a1989c2bbaf"}, 51 | {file = "coverage-7.10.5-cp312-cp312-win_amd64.whl", hash = "sha256:6b87f1ad60b30bc3c43c66afa7db6b22a3109902e28c5094957626a0143a001f"}, 52 | {file = "coverage-7.10.5-cp312-cp312-win_arm64.whl", hash = "sha256:672a6c1da5aea6c629819a0e1461e89d244f78d7b60c424ecf4f1f2556c041d8"}, 53 | {file = "coverage-7.10.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ef3b83594d933020f54cf65ea1f4405d1f4e41a009c46df629dd964fcb6e907c"}, 54 | {file = "coverage-7.10.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2b96bfdf7c0ea9faebce088a3ecb2382819da4fbc05c7b80040dbc428df6af44"}, 55 | {file = "coverage-7.10.5-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:63df1fdaffa42d914d5c4d293e838937638bf75c794cf20bee12978fc8c4e3bc"}, 56 | {file = "coverage-7.10.5-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8002dc6a049aac0e81ecec97abfb08c01ef0c1fbf962d0c98da3950ace89b869"}, 57 | {file = "coverage-7.10.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:63d4bb2966d6f5f705a6b0c6784c8969c468dbc4bcf9d9ded8bff1c7e092451f"}, 58 | {file = "coverage-7.10.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1f672efc0731a6846b157389b6e6d5d5e9e59d1d1a23a5c66a99fd58339914d5"}, 59 | {file = "coverage-7.10.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:3f39cef43d08049e8afc1fde4a5da8510fc6be843f8dea350ee46e2a26b2f54c"}, 60 | {file = "coverage-7.10.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2968647e3ed5a6c019a419264386b013979ff1fb67dd11f5c9886c43d6a31fc2"}, 61 | {file = "coverage-7.10.5-cp313-cp313-win32.whl", hash = "sha256:0d511dda38595b2b6934c2b730a1fd57a3635c6aa2a04cb74714cdfdd53846f4"}, 62 | {file = "coverage-7.10.5-cp313-cp313-win_amd64.whl", hash = "sha256:9a86281794a393513cf117177fd39c796b3f8e3759bb2764259a2abba5cce54b"}, 63 | {file = "coverage-7.10.5-cp313-cp313-win_arm64.whl", hash = "sha256:cebd8e906eb98bb09c10d1feed16096700b1198d482267f8bf0474e63a7b8d84"}, 64 | {file = "coverage-7.10.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0520dff502da5e09d0d20781df74d8189ab334a1e40d5bafe2efaa4158e2d9e7"}, 65 | {file = "coverage-7.10.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d9cd64aca68f503ed3f1f18c7c9174cbb797baba02ca8ab5112f9d1c0328cd4b"}, 66 | {file = "coverage-7.10.5-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0913dd1613a33b13c4f84aa6e3f4198c1a21ee28ccb4f674985c1f22109f0aae"}, 67 | {file = "coverage-7.10.5-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1b7181c0feeb06ed8a02da02792f42f829a7b29990fef52eff257fef0885d760"}, 68 | {file = "coverage-7.10.5-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36d42b7396b605f774d4372dd9c49bed71cbabce4ae1ccd074d155709dd8f235"}, 69 | {file = "coverage-7.10.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b4fdc777e05c4940b297bf47bf7eedd56a39a61dc23ba798e4b830d585486ca5"}, 70 | {file = "coverage-7.10.5-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:42144e8e346de44a6f1dbd0a56575dd8ab8dfa7e9007da02ea5b1c30ab33a7db"}, 71 | {file = "coverage-7.10.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:66c644cbd7aed8fe266d5917e2c9f65458a51cfe5eeff9c05f15b335f697066e"}, 72 | {file = "coverage-7.10.5-cp313-cp313t-win32.whl", hash = "sha256:2d1b73023854068c44b0c554578a4e1ef1b050ed07cf8b431549e624a29a66ee"}, 73 | {file = "coverage-7.10.5-cp313-cp313t-win_amd64.whl", hash = "sha256:54a1532c8a642d8cc0bd5a9a51f5a9dcc440294fd06e9dda55e743c5ec1a8f14"}, 74 | {file = "coverage-7.10.5-cp313-cp313t-win_arm64.whl", hash = "sha256:74d5b63fe3f5f5d372253a4ef92492c11a4305f3550631beaa432fc9df16fcff"}, 75 | {file = "coverage-7.10.5-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:68c5e0bc5f44f68053369fa0d94459c84548a77660a5f2561c5e5f1e3bed7031"}, 76 | {file = "coverage-7.10.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:cf33134ffae93865e32e1e37df043bef15a5e857d8caebc0099d225c579b0fa3"}, 77 | {file = "coverage-7.10.5-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ad8fa9d5193bafcf668231294241302b5e683a0518bf1e33a9a0dfb142ec3031"}, 78 | {file = "coverage-7.10.5-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:146fa1531973d38ab4b689bc764592fe6c2f913e7e80a39e7eeafd11f0ef6db2"}, 79 | {file = "coverage-7.10.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6013a37b8a4854c478d3219ee8bc2392dea51602dd0803a12d6f6182a0061762"}, 80 | {file = "coverage-7.10.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:eb90fe20db9c3d930fa2ad7a308207ab5b86bf6a76f54ab6a40be4012d88fcae"}, 81 | {file = "coverage-7.10.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:384b34482272e960c438703cafe63316dfbea124ac62006a455c8410bf2a2262"}, 82 | {file = "coverage-7.10.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:467dc74bd0a1a7de2bedf8deaf6811f43602cb532bd34d81ffd6038d6d8abe99"}, 83 | {file = "coverage-7.10.5-cp314-cp314-win32.whl", hash = "sha256:556d23d4e6393ca898b2e63a5bca91e9ac2d5fb13299ec286cd69a09a7187fde"}, 84 | {file = "coverage-7.10.5-cp314-cp314-win_amd64.whl", hash = "sha256:f4446a9547681533c8fa3e3c6cf62121eeee616e6a92bd9201c6edd91beffe13"}, 85 | {file = "coverage-7.10.5-cp314-cp314-win_arm64.whl", hash = "sha256:5e78bd9cf65da4c303bf663de0d73bf69f81e878bf72a94e9af67137c69b9fe9"}, 86 | {file = "coverage-7.10.5-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:5661bf987d91ec756a47c7e5df4fbcb949f39e32f9334ccd3f43233bbb65e508"}, 87 | {file = "coverage-7.10.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a46473129244db42a720439a26984f8c6f834762fc4573616c1f37f13994b357"}, 88 | {file = "coverage-7.10.5-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1f64b8d3415d60f24b058b58d859e9512624bdfa57a2d1f8aff93c1ec45c429b"}, 89 | {file = "coverage-7.10.5-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:44d43de99a9d90b20e0163f9770542357f58860a26e24dc1d924643bd6aa7cb4"}, 90 | {file = "coverage-7.10.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a931a87e5ddb6b6404e65443b742cb1c14959622777f2a4efd81fba84f5d91ba"}, 91 | {file = "coverage-7.10.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f9559b906a100029274448f4c8b8b0a127daa4dade5661dfd821b8c188058842"}, 92 | {file = "coverage-7.10.5-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:b08801e25e3b4526ef9ced1aa29344131a8f5213c60c03c18fe4c6170ffa2874"}, 93 | {file = "coverage-7.10.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ed9749bb8eda35f8b636fb7632f1c62f735a236a5d4edadd8bbcc5ea0542e732"}, 94 | {file = "coverage-7.10.5-cp314-cp314t-win32.whl", hash = "sha256:609b60d123fc2cc63ccee6d17e4676699075db72d14ac3c107cc4976d516f2df"}, 95 | {file = "coverage-7.10.5-cp314-cp314t-win_amd64.whl", hash = "sha256:0666cf3d2c1626b5a3463fd5b05f5e21f99e6aec40a3192eee4d07a15970b07f"}, 96 | {file = "coverage-7.10.5-cp314-cp314t-win_arm64.whl", hash = "sha256:bc85eb2d35e760120540afddd3044a5bf69118a91a296a8b3940dfc4fdcfe1e2"}, 97 | {file = "coverage-7.10.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:62835c1b00c4a4ace24c1a88561a5a59b612fbb83a525d1c70ff5720c97c0610"}, 98 | {file = "coverage-7.10.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5255b3bbcc1d32a4069d6403820ac8e6dbcc1d68cb28a60a1ebf17e47028e898"}, 99 | {file = "coverage-7.10.5-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3876385722e335d6e991c430302c24251ef9c2a9701b2b390f5473199b1b8ebf"}, 100 | {file = "coverage-7.10.5-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8048ce4b149c93447a55d279078c8ae98b08a6951a3c4d2d7e87f4efc7bfe100"}, 101 | {file = "coverage-7.10.5-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4028e7558e268dd8bcf4d9484aad393cafa654c24b4885f6f9474bf53183a82a"}, 102 | {file = "coverage-7.10.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:03f47dc870eec0367fcdd603ca6a01517d2504e83dc18dbfafae37faec66129a"}, 103 | {file = "coverage-7.10.5-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2d488d7d42b6ded7ea0704884f89dcabd2619505457de8fc9a6011c62106f6e5"}, 104 | {file = "coverage-7.10.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b3dcf2ead47fa8be14224ee817dfc1df98043af568fe120a22f81c0eb3c34ad2"}, 105 | {file = "coverage-7.10.5-cp39-cp39-win32.whl", hash = "sha256:02650a11324b80057b8c9c29487020073d5e98a498f1857f37e3f9b6ea1b2426"}, 106 | {file = "coverage-7.10.5-cp39-cp39-win_amd64.whl", hash = "sha256:b45264dd450a10f9e03237b41a9a24e85cbb1e278e5a32adb1a303f58f0017f3"}, 107 | {file = "coverage-7.10.5-py3-none-any.whl", hash = "sha256:0be24d35e4db1d23d0db5c0f6a74a962e2ec83c426b5cac09f4234aadef38e4a"}, 108 | {file = "coverage-7.10.5.tar.gz", hash = "sha256:f2e57716a78bc3ae80b2207be0709a3b2b63b9f2dcf9740ee6ac03588a2015b6"}, 109 | ] 110 | 111 | [package.dependencies] 112 | tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} 113 | 114 | [package.extras] 115 | toml = ["tomli"] 116 | 117 | [[package]] 118 | name = "exceptiongroup" 119 | version = "1.3.0" 120 | description = "Backport of PEP 654 (exception groups)" 121 | optional = false 122 | python-versions = ">=3.7" 123 | files = [ 124 | {file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"}, 125 | {file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"}, 126 | ] 127 | 128 | [package.dependencies] 129 | typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} 130 | 131 | [package.extras] 132 | test = ["pytest (>=6)"] 133 | 134 | [[package]] 135 | name = "iniconfig" 136 | version = "2.1.0" 137 | description = "brain-dead simple config-ini parsing" 138 | optional = false 139 | python-versions = ">=3.8" 140 | files = [ 141 | {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"}, 142 | {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, 143 | ] 144 | 145 | [[package]] 146 | name = "markdown-it-py" 147 | version = "3.0.0" 148 | description = "Python port of markdown-it. Markdown parsing, done right!" 149 | optional = false 150 | python-versions = ">=3.8" 151 | files = [ 152 | {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, 153 | {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, 154 | ] 155 | 156 | [package.dependencies] 157 | mdurl = ">=0.1,<1.0" 158 | 159 | [package.extras] 160 | benchmarking = ["psutil", "pytest", "pytest-benchmark"] 161 | code-style = ["pre-commit (>=3.0,<4.0)"] 162 | compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] 163 | linkify = ["linkify-it-py (>=1,<3)"] 164 | plugins = ["mdit-py-plugins"] 165 | profiling = ["gprof2dot"] 166 | rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] 167 | testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] 168 | 169 | [[package]] 170 | name = "mdurl" 171 | version = "0.1.2" 172 | description = "Markdown URL utilities" 173 | optional = false 174 | python-versions = ">=3.7" 175 | files = [ 176 | {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, 177 | {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, 178 | ] 179 | 180 | [[package]] 181 | name = "numpy" 182 | version = "2.0.2" 183 | description = "Fundamental package for array computing in Python" 184 | optional = false 185 | python-versions = ">=3.9" 186 | files = [ 187 | {file = "numpy-2.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:51129a29dbe56f9ca83438b706e2e69a39892b5eda6cedcb6b0c9fdc9b0d3ece"}, 188 | {file = "numpy-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f15975dfec0cf2239224d80e32c3170b1d168335eaedee69da84fbe9f1f9cd04"}, 189 | {file = "numpy-2.0.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:8c5713284ce4e282544c68d1c3b2c7161d38c256d2eefc93c1d683cf47683e66"}, 190 | {file = "numpy-2.0.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:becfae3ddd30736fe1889a37f1f580e245ba79a5855bff5f2a29cb3ccc22dd7b"}, 191 | {file = "numpy-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2da5960c3cf0df7eafefd806d4e612c5e19358de82cb3c343631188991566ccd"}, 192 | {file = "numpy-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:496f71341824ed9f3d2fd36cf3ac57ae2e0165c143b55c3a035ee219413f3318"}, 193 | {file = "numpy-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a61ec659f68ae254e4d237816e33171497e978140353c0c2038d46e63282d0c8"}, 194 | {file = "numpy-2.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d731a1c6116ba289c1e9ee714b08a8ff882944d4ad631fd411106a30f083c326"}, 195 | {file = "numpy-2.0.2-cp310-cp310-win32.whl", hash = "sha256:984d96121c9f9616cd33fbd0618b7f08e0cfc9600a7ee1d6fd9b239186d19d97"}, 196 | {file = "numpy-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:c7b0be4ef08607dd04da4092faee0b86607f111d5ae68036f16cc787e250a131"}, 197 | {file = "numpy-2.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:49ca4decb342d66018b01932139c0961a8f9ddc7589611158cb3c27cbcf76448"}, 198 | {file = "numpy-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:11a76c372d1d37437857280aa142086476136a8c0f373b2e648ab2c8f18fb195"}, 199 | {file = "numpy-2.0.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:807ec44583fd708a21d4a11d94aedf2f4f3c3719035c76a2bbe1fe8e217bdc57"}, 200 | {file = "numpy-2.0.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8cafab480740e22f8d833acefed5cc87ce276f4ece12fdaa2e8903db2f82897a"}, 201 | {file = "numpy-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a15f476a45e6e5a3a79d8a14e62161d27ad897381fecfa4a09ed5322f2085669"}, 202 | {file = "numpy-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13e689d772146140a252c3a28501da66dfecd77490b498b168b501835041f951"}, 203 | {file = "numpy-2.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9ea91dfb7c3d1c56a0e55657c0afb38cf1eeae4544c208dc465c3c9f3a7c09f9"}, 204 | {file = "numpy-2.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c1c9307701fec8f3f7a1e6711f9089c06e6284b3afbbcd259f7791282d660a15"}, 205 | {file = "numpy-2.0.2-cp311-cp311-win32.whl", hash = "sha256:a392a68bd329eafac5817e5aefeb39038c48b671afd242710b451e76090e81f4"}, 206 | {file = "numpy-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:286cd40ce2b7d652a6f22efdfc6d1edf879440e53e76a75955bc0c826c7e64dc"}, 207 | {file = "numpy-2.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:df55d490dea7934f330006d0f81e8551ba6010a5bf035a249ef61a94f21c500b"}, 208 | {file = "numpy-2.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8df823f570d9adf0978347d1f926b2a867d5608f434a7cff7f7908c6570dcf5e"}, 209 | {file = "numpy-2.0.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9a92ae5c14811e390f3767053ff54eaee3bf84576d99a2456391401323f4ec2c"}, 210 | {file = "numpy-2.0.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:a842d573724391493a97a62ebbb8e731f8a5dcc5d285dfc99141ca15a3302d0c"}, 211 | {file = "numpy-2.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05e238064fc0610c840d1cf6a13bf63d7e391717d247f1bf0318172e759e692"}, 212 | {file = "numpy-2.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0123ffdaa88fa4ab64835dcbde75dcdf89c453c922f18dced6e27c90d1d0ec5a"}, 213 | {file = "numpy-2.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:96a55f64139912d61de9137f11bf39a55ec8faec288c75a54f93dfd39f7eb40c"}, 214 | {file = "numpy-2.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec9852fb39354b5a45a80bdab5ac02dd02b15f44b3804e9f00c556bf24b4bded"}, 215 | {file = "numpy-2.0.2-cp312-cp312-win32.whl", hash = "sha256:671bec6496f83202ed2d3c8fdc486a8fc86942f2e69ff0e986140339a63bcbe5"}, 216 | {file = "numpy-2.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:cfd41e13fdc257aa5778496b8caa5e856dc4896d4ccf01841daee1d96465467a"}, 217 | {file = "numpy-2.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9059e10581ce4093f735ed23f3b9d283b9d517ff46009ddd485f1747eb22653c"}, 218 | {file = "numpy-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:423e89b23490805d2a5a96fe40ec507407b8ee786d66f7328be214f9679df6dd"}, 219 | {file = "numpy-2.0.2-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:2b2955fa6f11907cf7a70dab0d0755159bca87755e831e47932367fc8f2f2d0b"}, 220 | {file = "numpy-2.0.2-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:97032a27bd9d8988b9a97a8c4d2c9f2c15a81f61e2f21404d7e8ef00cb5be729"}, 221 | {file = "numpy-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e795a8be3ddbac43274f18588329c72939870a16cae810c2b73461c40718ab1"}, 222 | {file = "numpy-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b258c385842546006213344c50655ff1555a9338e2e5e02a0756dc3e803dd"}, 223 | {file = "numpy-2.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fec9451a7789926bcf7c2b8d187292c9f93ea30284802a0ab3f5be8ab36865d"}, 224 | {file = "numpy-2.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9189427407d88ff25ecf8f12469d4d39d35bee1db5d39fc5c168c6f088a6956d"}, 225 | {file = "numpy-2.0.2-cp39-cp39-win32.whl", hash = "sha256:905d16e0c60200656500c95b6b8dca5d109e23cb24abc701d41c02d74c6b3afa"}, 226 | {file = "numpy-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:a3f4ab0caa7f053f6797fcd4e1e25caee367db3112ef2b6ef82d749530768c73"}, 227 | {file = "numpy-2.0.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7f0a0c6f12e07fa94133c8a67404322845220c06a9e80e85999afe727f7438b8"}, 228 | {file = "numpy-2.0.2-pp39-pypy39_pp73-macosx_14_0_x86_64.whl", hash = "sha256:312950fdd060354350ed123c0e25a71327d3711584beaef30cdaa93320c392d4"}, 229 | {file = "numpy-2.0.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26df23238872200f63518dd2aa984cfca675d82469535dc7162dc2ee52d9dd5c"}, 230 | {file = "numpy-2.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a46288ec55ebbd58947d31d72be2c63cbf839f0a63b49cb755022310792a3385"}, 231 | {file = "numpy-2.0.2.tar.gz", hash = "sha256:883c987dee1880e2a864ab0dc9892292582510604156762362d9326444636e78"}, 232 | ] 233 | 234 | [[package]] 235 | name = "numpy" 236 | version = "2.3.2" 237 | description = "Fundamental package for array computing in Python" 238 | optional = false 239 | python-versions = ">=3.11" 240 | files = [ 241 | {file = "numpy-2.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:852ae5bed3478b92f093e30f785c98e0cb62fa0a939ed057c31716e18a7a22b9"}, 242 | {file = "numpy-2.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a0e27186e781a69959d0230dd9909b5e26024f8da10683bd6344baea1885168"}, 243 | {file = "numpy-2.3.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:f0a1a8476ad77a228e41619af2fa9505cf69df928e9aaa165746584ea17fed2b"}, 244 | {file = "numpy-2.3.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:cbc95b3813920145032412f7e33d12080f11dc776262df1712e1638207dde9e8"}, 245 | {file = "numpy-2.3.2-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f75018be4980a7324edc5930fe39aa391d5734531b1926968605416ff58c332d"}, 246 | {file = "numpy-2.3.2-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20b8200721840f5621b7bd03f8dcd78de33ec522fc40dc2641aa09537df010c3"}, 247 | {file = "numpy-2.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f91e5c028504660d606340a084db4b216567ded1056ea2b4be4f9d10b67197f"}, 248 | {file = "numpy-2.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:fb1752a3bb9a3ad2d6b090b88a9a0ae1cd6f004ef95f75825e2f382c183b2097"}, 249 | {file = "numpy-2.3.2-cp311-cp311-win32.whl", hash = "sha256:4ae6863868aaee2f57503c7a5052b3a2807cf7a3914475e637a0ecd366ced220"}, 250 | {file = "numpy-2.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:240259d6564f1c65424bcd10f435145a7644a65a6811cfc3201c4a429ba79170"}, 251 | {file = "numpy-2.3.2-cp311-cp311-win_arm64.whl", hash = "sha256:4209f874d45f921bde2cff1ffcd8a3695f545ad2ffbef6d3d3c6768162efab89"}, 252 | {file = "numpy-2.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bc3186bea41fae9d8e90c2b4fb5f0a1f5a690682da79b92574d63f56b529080b"}, 253 | {file = "numpy-2.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f4f0215edb189048a3c03bd5b19345bdfa7b45a7a6f72ae5945d2a28272727f"}, 254 | {file = "numpy-2.3.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:8b1224a734cd509f70816455c3cffe13a4f599b1bf7130f913ba0e2c0b2006c0"}, 255 | {file = "numpy-2.3.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:3dcf02866b977a38ba3ec10215220609ab9667378a9e2150615673f3ffd6c73b"}, 256 | {file = "numpy-2.3.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:572d5512df5470f50ada8d1972c5f1082d9a0b7aa5944db8084077570cf98370"}, 257 | {file = "numpy-2.3.2-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8145dd6d10df13c559d1e4314df29695613575183fa2e2d11fac4c208c8a1f73"}, 258 | {file = "numpy-2.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:103ea7063fa624af04a791c39f97070bf93b96d7af7eb23530cd087dc8dbe9dc"}, 259 | {file = "numpy-2.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc927d7f289d14f5e037be917539620603294454130b6de200091e23d27dc9be"}, 260 | {file = "numpy-2.3.2-cp312-cp312-win32.whl", hash = "sha256:d95f59afe7f808c103be692175008bab926b59309ade3e6d25009e9a171f7036"}, 261 | {file = "numpy-2.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:9e196ade2400c0c737d93465327d1ae7c06c7cb8a1756121ebf54b06ca183c7f"}, 262 | {file = "numpy-2.3.2-cp312-cp312-win_arm64.whl", hash = "sha256:ee807923782faaf60d0d7331f5e86da7d5e3079e28b291973c545476c2b00d07"}, 263 | {file = "numpy-2.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c8d9727f5316a256425892b043736d63e89ed15bbfe6556c5ff4d9d4448ff3b3"}, 264 | {file = "numpy-2.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:efc81393f25f14d11c9d161e46e6ee348637c0a1e8a54bf9dedc472a3fae993b"}, 265 | {file = "numpy-2.3.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:dd937f088a2df683cbb79dda9a772b62a3e5a8a7e76690612c2737f38c6ef1b6"}, 266 | {file = "numpy-2.3.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:11e58218c0c46c80509186e460d79fbdc9ca1eb8d8aee39d8f2dc768eb781089"}, 267 | {file = "numpy-2.3.2-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5ad4ebcb683a1f99f4f392cc522ee20a18b2bb12a2c1c42c3d48d5a1adc9d3d2"}, 268 | {file = "numpy-2.3.2-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:938065908d1d869c7d75d8ec45f735a034771c6ea07088867f713d1cd3bbbe4f"}, 269 | {file = "numpy-2.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:66459dccc65d8ec98cc7df61307b64bf9e08101f9598755d42d8ae65d9a7a6ee"}, 270 | {file = "numpy-2.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a7af9ed2aa9ec5950daf05bb11abc4076a108bd3c7db9aa7251d5f107079b6a6"}, 271 | {file = "numpy-2.3.2-cp313-cp313-win32.whl", hash = "sha256:906a30249315f9c8e17b085cc5f87d3f369b35fedd0051d4a84686967bdbbd0b"}, 272 | {file = "numpy-2.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:c63d95dc9d67b676e9108fe0d2182987ccb0f11933c1e8959f42fa0da8d4fa56"}, 273 | {file = "numpy-2.3.2-cp313-cp313-win_arm64.whl", hash = "sha256:b05a89f2fb84d21235f93de47129dd4f11c16f64c87c33f5e284e6a3a54e43f2"}, 274 | {file = "numpy-2.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4e6ecfeddfa83b02318f4d84acf15fbdbf9ded18e46989a15a8b6995dfbf85ab"}, 275 | {file = "numpy-2.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:508b0eada3eded10a3b55725b40806a4b855961040180028f52580c4729916a2"}, 276 | {file = "numpy-2.3.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:754d6755d9a7588bdc6ac47dc4ee97867271b17cee39cb87aef079574366db0a"}, 277 | {file = "numpy-2.3.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:a9f66e7d2b2d7712410d3bc5684149040ef5f19856f20277cd17ea83e5006286"}, 278 | {file = "numpy-2.3.2-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:de6ea4e5a65d5a90c7d286ddff2b87f3f4ad61faa3db8dabe936b34c2275b6f8"}, 279 | {file = "numpy-2.3.2-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a3ef07ec8cbc8fc9e369c8dcd52019510c12da4de81367d8b20bc692aa07573a"}, 280 | {file = "numpy-2.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:27c9f90e7481275c7800dc9c24b7cc40ace3fdb970ae4d21eaff983a32f70c91"}, 281 | {file = "numpy-2.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:07b62978075b67eee4065b166d000d457c82a1efe726cce608b9db9dd66a73a5"}, 282 | {file = "numpy-2.3.2-cp313-cp313t-win32.whl", hash = "sha256:c771cfac34a4f2c0de8e8c97312d07d64fd8f8ed45bc9f5726a7e947270152b5"}, 283 | {file = "numpy-2.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:72dbebb2dcc8305c431b2836bcc66af967df91be793d63a24e3d9b741374c450"}, 284 | {file = "numpy-2.3.2-cp313-cp313t-win_arm64.whl", hash = "sha256:72c6df2267e926a6d5286b0a6d556ebe49eae261062059317837fda12ddf0c1a"}, 285 | {file = "numpy-2.3.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:448a66d052d0cf14ce9865d159bfc403282c9bc7bb2a31b03cc18b651eca8b1a"}, 286 | {file = "numpy-2.3.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:546aaf78e81b4081b2eba1d105c3b34064783027a06b3ab20b6eba21fb64132b"}, 287 | {file = "numpy-2.3.2-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:87c930d52f45df092f7578889711a0768094debf73cfcde105e2d66954358125"}, 288 | {file = "numpy-2.3.2-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:8dc082ea901a62edb8f59713c6a7e28a85daddcb67454c839de57656478f5b19"}, 289 | {file = "numpy-2.3.2-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:af58de8745f7fa9ca1c0c7c943616c6fe28e75d0c81f5c295810e3c83b5be92f"}, 290 | {file = "numpy-2.3.2-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed5527c4cf10f16c6d0b6bee1f89958bccb0ad2522c8cadc2efd318bcd545f5"}, 291 | {file = "numpy-2.3.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:095737ed986e00393ec18ec0b21b47c22889ae4b0cd2d5e88342e08b01141f58"}, 292 | {file = "numpy-2.3.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b5e40e80299607f597e1a8a247ff8d71d79c5b52baa11cc1cce30aa92d2da6e0"}, 293 | {file = "numpy-2.3.2-cp314-cp314-win32.whl", hash = "sha256:7d6e390423cc1f76e1b8108c9b6889d20a7a1f59d9a60cac4a050fa734d6c1e2"}, 294 | {file = "numpy-2.3.2-cp314-cp314-win_amd64.whl", hash = "sha256:b9d0878b21e3918d76d2209c924ebb272340da1fb51abc00f986c258cd5e957b"}, 295 | {file = "numpy-2.3.2-cp314-cp314-win_arm64.whl", hash = "sha256:2738534837c6a1d0c39340a190177d7d66fdf432894f469728da901f8f6dc910"}, 296 | {file = "numpy-2.3.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:4d002ecf7c9b53240be3bb69d80f86ddbd34078bae04d87be81c1f58466f264e"}, 297 | {file = "numpy-2.3.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:293b2192c6bcce487dbc6326de5853787f870aeb6c43f8f9c6496db5b1781e45"}, 298 | {file = "numpy-2.3.2-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:0a4f2021a6da53a0d580d6ef5db29947025ae8b35b3250141805ea9a32bbe86b"}, 299 | {file = "numpy-2.3.2-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:9c144440db4bf3bb6372d2c3e49834cc0ff7bb4c24975ab33e01199e645416f2"}, 300 | {file = "numpy-2.3.2-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f92d6c2a8535dc4fe4419562294ff957f83a16ebdec66df0805e473ffaad8bd0"}, 301 | {file = "numpy-2.3.2-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cefc2219baa48e468e3db7e706305fcd0c095534a192a08f31e98d83a7d45fb0"}, 302 | {file = "numpy-2.3.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:76c3e9501ceb50b2ff3824c3589d5d1ab4ac857b0ee3f8f49629d0de55ecf7c2"}, 303 | {file = "numpy-2.3.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:122bf5ed9a0221b3419672493878ba4967121514b1d7d4656a7580cd11dddcbf"}, 304 | {file = "numpy-2.3.2-cp314-cp314t-win32.whl", hash = "sha256:6f1ae3dcb840edccc45af496f312528c15b1f79ac318169d094e85e4bb35fdf1"}, 305 | {file = "numpy-2.3.2-cp314-cp314t-win_amd64.whl", hash = "sha256:087ffc25890d89a43536f75c5fe8770922008758e8eeeef61733957041ed2f9b"}, 306 | {file = "numpy-2.3.2-cp314-cp314t-win_arm64.whl", hash = "sha256:092aeb3449833ea9c0bf0089d70c29ae480685dd2377ec9cdbbb620257f84631"}, 307 | {file = "numpy-2.3.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:14a91ebac98813a49bc6aa1a0dfc09513dcec1d97eaf31ca21a87221a1cdcb15"}, 308 | {file = "numpy-2.3.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:71669b5daae692189540cffc4c439468d35a3f84f0c88b078ecd94337f6cb0ec"}, 309 | {file = "numpy-2.3.2-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:69779198d9caee6e547adb933941ed7520f896fd9656834c300bdf4dd8642712"}, 310 | {file = "numpy-2.3.2-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:2c3271cc4097beb5a60f010bcc1cc204b300bb3eafb4399376418a83a1c6373c"}, 311 | {file = "numpy-2.3.2-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8446acd11fe3dc1830568c941d44449fd5cb83068e5c70bd5a470d323d448296"}, 312 | {file = "numpy-2.3.2-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aa098a5ab53fa407fded5870865c6275a5cd4101cfdef8d6fafc48286a96e981"}, 313 | {file = "numpy-2.3.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:6936aff90dda378c09bea075af0d9c675fe3a977a9d2402f95a87f440f59f619"}, 314 | {file = "numpy-2.3.2.tar.gz", hash = "sha256:e0486a11ec30cdecb53f184d496d1c6a20786c81e55e41640270130056f8ee48"}, 315 | ] 316 | 317 | [[package]] 318 | name = "packaging" 319 | version = "25.0" 320 | description = "Core utilities for Python packages" 321 | optional = false 322 | python-versions = ">=3.8" 323 | files = [ 324 | {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, 325 | {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, 326 | ] 327 | 328 | [[package]] 329 | name = "pandas" 330 | version = "2.3.2" 331 | description = "Powerful data structures for data analysis, time series, and statistics" 332 | optional = false 333 | python-versions = ">=3.9" 334 | files = [ 335 | {file = "pandas-2.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:52bc29a946304c360561974c6542d1dd628ddafa69134a7131fdfd6a5d7a1a35"}, 336 | {file = "pandas-2.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:220cc5c35ffaa764dd5bb17cf42df283b5cb7fdf49e10a7b053a06c9cb48ee2b"}, 337 | {file = "pandas-2.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42c05e15111221384019897df20c6fe893b2f697d03c811ee67ec9e0bb5a3424"}, 338 | {file = "pandas-2.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc03acc273c5515ab69f898df99d9d4f12c4d70dbfc24c3acc6203751d0804cf"}, 339 | {file = "pandas-2.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d25c20a03e8870f6339bcf67281b946bd20b86f1a544ebbebb87e66a8d642cba"}, 340 | {file = "pandas-2.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21bb612d148bb5860b7eb2c10faacf1a810799245afd342cf297d7551513fbb6"}, 341 | {file = "pandas-2.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:b62d586eb25cb8cb70a5746a378fc3194cb7f11ea77170d59f889f5dfe3cec7a"}, 342 | {file = "pandas-2.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1333e9c299adcbb68ee89a9bb568fc3f20f9cbb419f1dd5225071e6cddb2a743"}, 343 | {file = "pandas-2.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:76972bcbd7de8e91ad5f0ca884a9f2c477a2125354af624e022c49e5bd0dfff4"}, 344 | {file = "pandas-2.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b98bdd7c456a05eef7cd21fd6b29e3ca243591fe531c62be94a2cc987efb5ac2"}, 345 | {file = "pandas-2.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d81573b3f7db40d020983f78721e9bfc425f411e616ef019a10ebf597aedb2e"}, 346 | {file = "pandas-2.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e190b738675a73b581736cc8ec71ae113d6c3768d0bd18bffa5b9a0927b0b6ea"}, 347 | {file = "pandas-2.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c253828cb08f47488d60f43c5fc95114c771bbfff085da54bfc79cb4f9e3a372"}, 348 | {file = "pandas-2.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:9467697b8083f9667b212633ad6aa4ab32436dcbaf4cd57325debb0ddef2012f"}, 349 | {file = "pandas-2.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fbb977f802156e7a3f829e9d1d5398f6192375a3e2d1a9ee0803e35fe70a2b9"}, 350 | {file = "pandas-2.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1b9b52693123dd234b7c985c68b709b0b009f4521000d0525f2b95c22f15944b"}, 351 | {file = "pandas-2.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bd281310d4f412733f319a5bc552f86d62cddc5f51d2e392c8787335c994175"}, 352 | {file = "pandas-2.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96d31a6b4354e3b9b8a2c848af75d31da390657e3ac6f30c05c82068b9ed79b9"}, 353 | {file = "pandas-2.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:df4df0b9d02bb873a106971bb85d448378ef14b86ba96f035f50bbd3688456b4"}, 354 | {file = "pandas-2.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:213a5adf93d020b74327cb2c1b842884dbdd37f895f42dcc2f09d451d949f811"}, 355 | {file = "pandas-2.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:8c13b81a9347eb8c7548f53fd9a4f08d4dfe996836543f805c987bafa03317ae"}, 356 | {file = "pandas-2.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0c6ecbac99a354a051ef21c5307601093cb9e0f4b1855984a084bfec9302699e"}, 357 | {file = "pandas-2.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c6f048aa0fd080d6a06cc7e7537c09b53be6642d330ac6f54a600c3ace857ee9"}, 358 | {file = "pandas-2.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0064187b80a5be6f2f9c9d6bdde29372468751dfa89f4211a3c5871854cfbf7a"}, 359 | {file = "pandas-2.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ac8c320bded4718b298281339c1a50fb00a6ba78cb2a63521c39bec95b0209b"}, 360 | {file = "pandas-2.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:114c2fe4f4328cf98ce5716d1532f3ab79c5919f95a9cfee81d9140064a2e4d6"}, 361 | {file = "pandas-2.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:48fa91c4dfb3b2b9bfdb5c24cd3567575f4e13f9636810462ffed8925352be5a"}, 362 | {file = "pandas-2.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:12d039facec710f7ba305786837d0225a3444af7bbd9c15c32ca2d40d157ed8b"}, 363 | {file = "pandas-2.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:c624b615ce97864eb588779ed4046186f967374185c047070545253a52ab2d57"}, 364 | {file = "pandas-2.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0cee69d583b9b128823d9514171cabb6861e09409af805b54459bd0c821a35c2"}, 365 | {file = "pandas-2.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2319656ed81124982900b4c37f0e0c58c015af9a7bbc62342ba5ad07ace82ba9"}, 366 | {file = "pandas-2.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b37205ad6f00d52f16b6d09f406434ba928c1a1966e2771006a9033c736d30d2"}, 367 | {file = "pandas-2.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:837248b4fc3a9b83b9c6214699a13f069dc13510a6a6d7f9ba33145d2841a012"}, 368 | {file = "pandas-2.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d2c3554bd31b731cd6490d94a28f3abb8dd770634a9e06eb6d2911b9827db370"}, 369 | {file = "pandas-2.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:88080a0ff8a55eac9c84e3ff3c7665b3b5476c6fbc484775ca1910ce1c3e0b87"}, 370 | {file = "pandas-2.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d4a558c7620340a0931828d8065688b3cc5b4c8eb674bcaf33d18ff4a6870b4a"}, 371 | {file = "pandas-2.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45178cf09d1858a1509dc73ec261bf5b25a625a389b65be2e47b559905f0ab6a"}, 372 | {file = "pandas-2.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77cefe00e1b210f9c76c697fedd8fdb8d3dd86563e9c8adc9fa72b90f5e9e4c2"}, 373 | {file = "pandas-2.3.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:13bd629c653856f00c53dc495191baa59bcafbbf54860a46ecc50d3a88421a96"}, 374 | {file = "pandas-2.3.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:36d627906fd44b5fd63c943264e11e96e923f8de77d6016dc2f667b9ad193438"}, 375 | {file = "pandas-2.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:a9d7ec92d71a420185dec44909c32e9a362248c4ae2238234b76d5be37f208cc"}, 376 | {file = "pandas-2.3.2.tar.gz", hash = "sha256:ab7b58f8f82706890924ccdfb5f48002b83d2b5a3845976a9fb705d36c34dcdb"}, 377 | ] 378 | 379 | [package.dependencies] 380 | numpy = [ 381 | {version = ">=1.22.4", markers = "python_version < \"3.11\""}, 382 | {version = ">=1.23.2", markers = "python_version == \"3.11\""}, 383 | {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, 384 | ] 385 | python-dateutil = ">=2.8.2" 386 | pytz = ">=2020.1" 387 | tzdata = ">=2022.7" 388 | 389 | [package.extras] 390 | all = ["PyQt5 (>=5.15.9)", "SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)", "beautifulsoup4 (>=4.11.2)", "bottleneck (>=1.3.6)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=2022.12.0)", "fsspec (>=2022.11.0)", "gcsfs (>=2022.11.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.9.2)", "matplotlib (>=3.6.3)", "numba (>=0.56.4)", "numexpr (>=2.8.4)", "odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "pandas-gbq (>=0.19.0)", "psycopg2 (>=2.9.6)", "pyarrow (>=10.0.1)", "pymysql (>=1.0.2)", "pyreadstat (>=1.2.0)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "qtpy (>=2.3.0)", "s3fs (>=2022.11.0)", "scipy (>=1.10.0)", "tables (>=3.8.0)", "tabulate (>=0.9.0)", "xarray (>=2022.12.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)", "zstandard (>=0.19.0)"] 391 | aws = ["s3fs (>=2022.11.0)"] 392 | clipboard = ["PyQt5 (>=5.15.9)", "qtpy (>=2.3.0)"] 393 | compression = ["zstandard (>=0.19.0)"] 394 | computation = ["scipy (>=1.10.0)", "xarray (>=2022.12.0)"] 395 | consortium-standard = ["dataframe-api-compat (>=0.1.7)"] 396 | excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)"] 397 | feather = ["pyarrow (>=10.0.1)"] 398 | fss = ["fsspec (>=2022.11.0)"] 399 | gcp = ["gcsfs (>=2022.11.0)", "pandas-gbq (>=0.19.0)"] 400 | hdf5 = ["tables (>=3.8.0)"] 401 | html = ["beautifulsoup4 (>=4.11.2)", "html5lib (>=1.1)", "lxml (>=4.9.2)"] 402 | mysql = ["SQLAlchemy (>=2.0.0)", "pymysql (>=1.0.2)"] 403 | output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.9.0)"] 404 | parquet = ["pyarrow (>=10.0.1)"] 405 | performance = ["bottleneck (>=1.3.6)", "numba (>=0.56.4)", "numexpr (>=2.8.4)"] 406 | plot = ["matplotlib (>=3.6.3)"] 407 | postgresql = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "psycopg2 (>=2.9.6)"] 408 | pyarrow = ["pyarrow (>=10.0.1)"] 409 | spss = ["pyreadstat (>=1.2.0)"] 410 | sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)"] 411 | test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"] 412 | xml = ["lxml (>=4.9.2)"] 413 | 414 | [[package]] 415 | name = "pluggy" 416 | version = "1.6.0" 417 | description = "plugin and hook calling mechanisms for python" 418 | optional = false 419 | python-versions = ">=3.9" 420 | files = [ 421 | {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, 422 | {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, 423 | ] 424 | 425 | [package.extras] 426 | dev = ["pre-commit", "tox"] 427 | testing = ["coverage", "pytest", "pytest-benchmark"] 428 | 429 | [[package]] 430 | name = "pygments" 431 | version = "2.19.2" 432 | description = "Pygments is a syntax highlighting package written in Python." 433 | optional = false 434 | python-versions = ">=3.8" 435 | files = [ 436 | {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"}, 437 | {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"}, 438 | ] 439 | 440 | [package.extras] 441 | windows-terminal = ["colorama (>=0.4.6)"] 442 | 443 | [[package]] 444 | name = "pytest" 445 | version = "8.4.1" 446 | description = "pytest: simple powerful testing with Python" 447 | optional = false 448 | python-versions = ">=3.9" 449 | files = [ 450 | {file = "pytest-8.4.1-py3-none-any.whl", hash = "sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7"}, 451 | {file = "pytest-8.4.1.tar.gz", hash = "sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c"}, 452 | ] 453 | 454 | [package.dependencies] 455 | colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""} 456 | exceptiongroup = {version = ">=1", markers = "python_version < \"3.11\""} 457 | iniconfig = ">=1" 458 | packaging = ">=20" 459 | pluggy = ">=1.5,<2" 460 | pygments = ">=2.7.2" 461 | tomli = {version = ">=1", markers = "python_version < \"3.11\""} 462 | 463 | [package.extras] 464 | dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"] 465 | 466 | [[package]] 467 | name = "pytest-cov" 468 | version = "6.2.1" 469 | description = "Pytest plugin for measuring coverage." 470 | optional = false 471 | python-versions = ">=3.9" 472 | files = [ 473 | {file = "pytest_cov-6.2.1-py3-none-any.whl", hash = "sha256:f5bc4c23f42f1cdd23c70b1dab1bbaef4fc505ba950d53e0081d0730dd7e86d5"}, 474 | {file = "pytest_cov-6.2.1.tar.gz", hash = "sha256:25cc6cc0a5358204b8108ecedc51a9b57b34cc6b8c967cc2c01a4e00d8a67da2"}, 475 | ] 476 | 477 | [package.dependencies] 478 | coverage = {version = ">=7.5", extras = ["toml"]} 479 | pluggy = ">=1.2" 480 | pytest = ">=6.2.5" 481 | 482 | [package.extras] 483 | testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] 484 | 485 | [[package]] 486 | name = "python-dateutil" 487 | version = "2.9.0.post0" 488 | description = "Extensions to the standard Python datetime module" 489 | optional = false 490 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" 491 | files = [ 492 | {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, 493 | {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, 494 | ] 495 | 496 | [package.dependencies] 497 | six = ">=1.5" 498 | 499 | [[package]] 500 | name = "pytz" 501 | version = "2025.2" 502 | description = "World timezone definitions, modern and historical" 503 | optional = false 504 | python-versions = "*" 505 | files = [ 506 | {file = "pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00"}, 507 | {file = "pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3"}, 508 | ] 509 | 510 | [[package]] 511 | name = "rich" 512 | version = "14.1.0" 513 | description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" 514 | optional = false 515 | python-versions = ">=3.8.0" 516 | files = [ 517 | {file = "rich-14.1.0-py3-none-any.whl", hash = "sha256:536f5f1785986d6dbdea3c75205c473f970777b4a0d6c6dd1b696aa05a3fa04f"}, 518 | {file = "rich-14.1.0.tar.gz", hash = "sha256:e497a48b844b0320d45007cdebfeaeed8db2a4f4bcf49f15e455cfc4af11eaa8"}, 519 | ] 520 | 521 | [package.dependencies] 522 | markdown-it-py = ">=2.2.0" 523 | pygments = ">=2.13.0,<3.0.0" 524 | 525 | [package.extras] 526 | jupyter = ["ipywidgets (>=7.5.1,<9)"] 527 | 528 | [[package]] 529 | name = "ruff" 530 | version = "0.6.9" 531 | description = "An extremely fast Python linter and code formatter, written in Rust." 532 | optional = false 533 | python-versions = ">=3.7" 534 | files = [ 535 | {file = "ruff-0.6.9-py3-none-linux_armv6l.whl", hash = "sha256:064df58d84ccc0ac0fcd63bc3090b251d90e2a372558c0f057c3f75ed73e1ccd"}, 536 | {file = "ruff-0.6.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:140d4b5c9f5fc7a7b074908a78ab8d384dd7f6510402267bc76c37195c02a7ec"}, 537 | {file = "ruff-0.6.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:53fd8ca5e82bdee8da7f506d7b03a261f24cd43d090ea9db9a1dc59d9313914c"}, 538 | {file = "ruff-0.6.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645d7d8761f915e48a00d4ecc3686969761df69fb561dd914a773c1a8266e14e"}, 539 | {file = "ruff-0.6.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eae02b700763e3847595b9d2891488989cac00214da7f845f4bcf2989007d577"}, 540 | {file = "ruff-0.6.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d5ccc9e58112441de8ad4b29dcb7a86dc25c5f770e3c06a9d57e0e5eba48829"}, 541 | {file = "ruff-0.6.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:417b81aa1c9b60b2f8edc463c58363075412866ae4e2b9ab0f690dc1e87ac1b5"}, 542 | {file = "ruff-0.6.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c866b631f5fbce896a74a6e4383407ba7507b815ccc52bcedabb6810fdb3ef7"}, 543 | {file = "ruff-0.6.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7b118afbb3202f5911486ad52da86d1d52305b59e7ef2031cea3425142b97d6f"}, 544 | {file = "ruff-0.6.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a67267654edc23c97335586774790cde402fb6bbdb3c2314f1fc087dee320bfa"}, 545 | {file = "ruff-0.6.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3ef0cc774b00fec123f635ce5c547dac263f6ee9fb9cc83437c5904183b55ceb"}, 546 | {file = "ruff-0.6.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:12edd2af0c60fa61ff31cefb90aef4288ac4d372b4962c2864aeea3a1a2460c0"}, 547 | {file = "ruff-0.6.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:55bb01caeaf3a60b2b2bba07308a02fca6ab56233302406ed5245180a05c5625"}, 548 | {file = "ruff-0.6.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:925d26471fa24b0ce5a6cdfab1bb526fb4159952385f386bdcc643813d472039"}, 549 | {file = "ruff-0.6.9-py3-none-win32.whl", hash = "sha256:eb61ec9bdb2506cffd492e05ac40e5bc6284873aceb605503d8494180d6fc84d"}, 550 | {file = "ruff-0.6.9-py3-none-win_amd64.whl", hash = "sha256:785d31851c1ae91f45b3d8fe23b8ae4b5170089021fbb42402d811135f0b7117"}, 551 | {file = "ruff-0.6.9-py3-none-win_arm64.whl", hash = "sha256:a9641e31476d601f83cd602608739a0840e348bda93fec9f1ee816f8b6798b93"}, 552 | {file = "ruff-0.6.9.tar.gz", hash = "sha256:b076ef717a8e5bc819514ee1d602bbdca5b4420ae13a9cf61a0c0a4f53a2baa2"}, 553 | ] 554 | 555 | [[package]] 556 | name = "six" 557 | version = "1.17.0" 558 | description = "Python 2 and 3 compatibility utilities" 559 | optional = false 560 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" 561 | files = [ 562 | {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, 563 | {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, 564 | ] 565 | 566 | [[package]] 567 | name = "toml" 568 | version = "0.10.2" 569 | description = "Python Library for Tom's Obvious, Minimal Language" 570 | optional = false 571 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 572 | files = [ 573 | {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, 574 | {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, 575 | ] 576 | 577 | [[package]] 578 | name = "tomli" 579 | version = "2.2.1" 580 | description = "A lil' TOML parser" 581 | optional = false 582 | python-versions = ">=3.8" 583 | files = [ 584 | {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, 585 | {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, 586 | {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, 587 | {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, 588 | {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, 589 | {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, 590 | {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, 591 | {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, 592 | {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, 593 | {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, 594 | {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, 595 | {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, 596 | {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, 597 | {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, 598 | {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, 599 | {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, 600 | {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, 601 | {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, 602 | {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, 603 | {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, 604 | {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, 605 | {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, 606 | {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, 607 | {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, 608 | {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, 609 | {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, 610 | {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, 611 | {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, 612 | {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, 613 | {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, 614 | {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, 615 | {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, 616 | ] 617 | 618 | [[package]] 619 | name = "typing-extensions" 620 | version = "4.15.0" 621 | description = "Backported and Experimental Type Hints for Python 3.9+" 622 | optional = false 623 | python-versions = ">=3.9" 624 | files = [ 625 | {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, 626 | {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, 627 | ] 628 | 629 | [[package]] 630 | name = "tzdata" 631 | version = "2025.2" 632 | description = "Provider of IANA time zone data" 633 | optional = false 634 | python-versions = ">=2" 635 | files = [ 636 | {file = "tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8"}, 637 | {file = "tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9"}, 638 | ] 639 | 640 | [metadata] 641 | lock-version = "2.0" 642 | python-versions = "^3.9" 643 | content-hash = "5e4172f628a13210a3cfd07758d5662621686d5a1495a886d60087f87266e086" 644 | --------------------------------------------------------------------------------