├── tests ├── data │ ├── empty_config.ini │ ├── config_auto_color.ini │ ├── config_disable_color.ini │ ├── config_enable_color.ini │ ├── error_config_2.ini │ ├── error_config_1.ini │ ├── config_2.ini │ └── config_1.ini ├── m.py ├── test_disbale_color.py ├── test_container.py ├── interactive_test.py ├── conftest.py ├── test_search.py ├── test_slots.py ├── test_buggy_attrs.py ├── test_filters.py ├── test_user_config.py └── test_pdir_format.py ├── images ├── colors.png ├── search.gif ├── repr_str.png └── presentation_v2.gif ├── pdir ├── __init__.py ├── constants.py ├── color.py ├── _internal_utils.py ├── format.py ├── configuration.py ├── api.py └── attr_category.py ├── Makefile ├── tox.ini ├── HISTORY.md ├── .gitignore ├── LICENSE ├── .github └── workflows │ └── ci.yml ├── pyproject.toml ├── README.md ├── annotate.json └── pdm.lock /tests/data/empty_config.ini: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /images/colors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laike9m/pdir2/HEAD/images/colors.png -------------------------------------------------------------------------------- /images/search.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laike9m/pdir2/HEAD/images/search.gif -------------------------------------------------------------------------------- /tests/data/config_auto_color.ini: -------------------------------------------------------------------------------- 1 | [global] 2 | enable-colorful-output = auto 3 | -------------------------------------------------------------------------------- /tests/data/config_disable_color.ini: -------------------------------------------------------------------------------- 1 | [global] 2 | enable-colorful-output = False 3 | -------------------------------------------------------------------------------- /tests/data/config_enable_color.ini: -------------------------------------------------------------------------------- 1 | [global] 2 | enable-colorful-output = True 3 | -------------------------------------------------------------------------------- /images/repr_str.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laike9m/pdir2/HEAD/images/repr_str.png -------------------------------------------------------------------------------- /tests/data/error_config_2.ini: -------------------------------------------------------------------------------- 1 | [global] 2 | doc-color = blue 3 | attribute-color = 42 4 | -------------------------------------------------------------------------------- /tests/data/error_config_1.ini: -------------------------------------------------------------------------------- 1 | [global] 2 | attribute-color = red 3 | doc-color1 = blue 4 | -------------------------------------------------------------------------------- /images/presentation_v2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laike9m/pdir2/HEAD/images/presentation_v2.gif -------------------------------------------------------------------------------- /tests/data/config_2.ini: -------------------------------------------------------------------------------- 1 | [global] 2 | uniform-color = white 3 | doc-color = black 4 | attribute-color = red 5 | -------------------------------------------------------------------------------- /tests/data/config_1.ini: -------------------------------------------------------------------------------- 1 | [global] 2 | doc-color = white 3 | category-color = bright yellow 4 | comma-color = bright green 5 | -------------------------------------------------------------------------------- /pdir/__init__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from .api import PrettyDir 3 | 4 | __author__ = 'laike9m ' 5 | 6 | sys.modules[__name__] = PrettyDir # type: ignore 7 | -------------------------------------------------------------------------------- /tests/m.py: -------------------------------------------------------------------------------- 1 | a = 1 2 | b = 2 3 | 4 | 5 | class OOO: 6 | """OOO today.""" 7 | 8 | pass 9 | 10 | 11 | def func(): 12 | """This is a function""" 13 | pass 14 | -------------------------------------------------------------------------------- /tests/test_disbale_color.py: -------------------------------------------------------------------------------- 1 | from pdir.color import _ColorDisabled 2 | 3 | 4 | def test_color_disabled(): 5 | c = _ColorDisabled() 6 | assert c.wrap_text("foobar") == "foobar" 7 | 8 | d = _ColorDisabled() 9 | assert c == d 10 | assert c is not d 11 | -------------------------------------------------------------------------------- /pdir/constants.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | dummy_obj = object() 4 | 5 | 6 | # repl 7 | class ReplType(Enum): 8 | PYTHON = 'python' 9 | IPYTHON = 'ipython' 10 | PTPYTHON = 'ptpython' 11 | BPYTHON = 'bpython' 12 | 13 | 14 | # descriptor 15 | GETTER = 'getter' 16 | SETTER = 'setter' 17 | DELETER = 'deleter' 18 | 19 | 20 | class _ClassWithSlot: 21 | __slots__ = ['a'] 22 | 23 | 24 | SLOT_TYPE = type(_ClassWithSlot.a) # type: ignore 25 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: format dry_publish publist debug 2 | 3 | # Install packages for development. 4 | install_dev_packages: 5 | pip install pytest tox black flake8 pytest-annotate mypy pytest-mypy 6 | 7 | install: 8 | python2 setup.py install 9 | python3 setup.py install 10 | 11 | format: 12 | black --config pyproject.toml . 13 | 14 | publish_to_test: 15 | rm -rf dist/ 16 | pdm build 17 | pdm run twine upload --repository testpypi dist/* # Assuming .pypirc exists. 18 | 19 | publish: 20 | rm -rf dist/ 21 | pdm build 22 | pdm run twine upload --repository pypi dist/* # Assuming .pypirc exists. 23 | 24 | debug: 25 | pytest --pdb -s tests 26 | -------------------------------------------------------------------------------- /tests/test_container.py: -------------------------------------------------------------------------------- 1 | import pdir 2 | 3 | 4 | def test_acting_like_a_list(): 5 | dadada = 1 6 | cadada = 1 7 | vadada = 1 8 | apple1 = 1 9 | xapple2 = 1 10 | result, correct = pdir(), dir() 11 | assert len(correct) == len(result) 12 | 13 | for x, y in zip(correct, result): 14 | assert x == y 15 | 16 | 17 | def test_acting_like_a_list_when_search(): 18 | dadada = 1 19 | cadada = 1 20 | vadada = 1 21 | apple1 = 1 22 | xapple2 = 1 23 | result = pdir().s('apple') 24 | assert len(result) == 2 25 | assert list(result) == ['apple1', 'xapple2'] 26 | 27 | 28 | def test_attr_order(): 29 | dir_attrs = dir(None) 30 | pdir_attrs = list(pdir(None)) 31 | assert dir_attrs == pdir_attrs 32 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = python3.10,python3.11,python3.12,python3.13,python3.14,extra,mypy 3 | isolated_build = True 4 | 5 | [gh-actions] 6 | python = 7 | 3.10: python3.10 8 | 3.11: python3.11 9 | 3.12: python3.12 10 | 3.13: python3.13 11 | 3.14: python3.14 12 | 13 | [testenv] 14 | commands_pre= 15 | pip install pandas 16 | commands= 17 | pytest -s -vv {posargs} {toxinidir}/tests/ 18 | 19 | [testenv:extra] 20 | changedir={toxinidir}/tests/ 21 | setenv= 22 | TERM=linux 23 | TERMINFO=/etc/terminfo 24 | commands= 25 | ptpython interactive_test.py --interactive 26 | bpython -i interactive_test.py 27 | ipython interactive_test.py 28 | 29 | [testenv:mypy] 30 | commands = pytest -s --mypy {toxinidir}/tests/ \ 31 | --ignore={toxinidir}/tests/interactive_test.py 32 | -------------------------------------------------------------------------------- /HISTORY.md: -------------------------------------------------------------------------------- 1 | Release History 2 | =============== 3 | 4 | 0.3.1(2018-10-25) 5 | ----------------- 6 | * Add support for `__slots__` (#44, #45) 7 | * Seperate `@staticmethod` with other descriptors(#38, #42) 8 | * Add `__post_init__` support 9 | 10 | Special thanks to @liwt31 for his great contribution. 11 | 12 | 0.3.0(2018-02-10) 13 | ----------------- 14 | * Add support for various filters (#37) 15 | 16 | 0.2.0(2017-04-04) 17 | ----------------- 18 | * Add support for color customization. (#14) 19 | 20 | 0.1.0(2017-03-16) 21 | ------------------ 22 | * Add support for ipython, ptpython and bpython (#4) 23 | 24 | 0.0.2(2017-03-11) 25 | --------- 26 | 27 | ### API Changes (Backward-Compatible) 28 | 29 | * Added a `case_sensitive` parameter into the `search` function (#5) 30 | 31 | ### Bugfixes 32 | * Error calling pdir(pandas.DataFrame) (#1) 33 | * Methods are now considered functions (#6) 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | bin/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | 25 | # Installer logs 26 | pip-log.txt 27 | pip-delete-this-directory.txt 28 | 29 | # Unit test / coverage reports 30 | htmlcov/ 31 | .tox/ 32 | .coverage 33 | .cache 34 | nosetests.xml 35 | coverage.xml 36 | .pytest_cache/ 37 | 38 | # Translations 39 | *.mo 40 | 41 | # Mr Developer 42 | .mr.developer.cfg 43 | .project 44 | .pydevproject 45 | .idea 46 | .vscode 47 | 48 | # Rope 49 | .ropeproject 50 | 51 | # Django stuff: 52 | *.log 53 | *.pot 54 | 55 | # Sphinx documentation 56 | docs/_build/ 57 | 58 | # pyenv 59 | .python-version 60 | 61 | # pip editable src 62 | src/ 63 | 64 | # mypy 65 | .mypy_cache/ 66 | 67 | # pdm 68 | .pdm.toml 69 | __pypackages__/ 70 | .pdm-python 71 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 laike9m 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /tests/interactive_test.py: -------------------------------------------------------------------------------- 1 | def interactive_test(): 2 | """ 3 | This function runs pdir2 in bpython, ipython, ptpython. 4 | Note that giving the right output does not mean pdir2 works correctly, 5 | because print(string) is not equivalent to repr it in a REPL. 6 | To ensure everything truly works, manually verification is necessary. 7 | """ 8 | import pdir 9 | from pdir._internal_utils import _get_repl_type 10 | from pdir.constants import ReplType 11 | 12 | print('Environment: ' + _get_repl_type().value) 13 | import requests 14 | 15 | print('\nShould show result of pdir(requests):') 16 | print(pdir(requests)) 17 | # if any('bpython' in key for key in sys.modules): 18 | if _get_repl_type() == ReplType.BPYTHON: 19 | import sys 20 | 21 | # exit() in bpython interactive mode leads to a ValueError. 22 | # So I defined an exception hook to silent it. 23 | # sys.exit(0) is to make tox believe there's no error. 24 | def deal_with_exception_when_exit(a, b, c): 25 | sys.exit(0) 26 | 27 | sys.excepthook = deal_with_exception_when_exit 28 | exit() 29 | else: 30 | exit() 31 | 32 | 33 | if __name__ in ('__main__', '__console__'): 34 | interactive_test() 35 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | pull_request: 5 | paths-ignore: 6 | - "images/**" 7 | - "*.md" 8 | push: 9 | branches: 10 | - master 11 | paths-ignore: 12 | - "images/**" 13 | - "*.md" 14 | workflow_dispatch: 15 | 16 | jobs: 17 | Testing: 18 | runs-on: ${{ matrix.os }} 19 | strategy: 20 | matrix: 21 | python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] 22 | os: [ubuntu-latest, macOS-latest, windows-latest] 23 | 24 | steps: 25 | - uses: actions/checkout@v4 26 | - name: Set up PDM 27 | uses: pdm-project/setup-pdm@v4 28 | with: 29 | python-version: ${{ matrix.python-version }} 30 | 31 | - name: Cache pypackages 32 | uses: actions/cache@v4 33 | with: 34 | path: __pypackages__ 35 | key: pypackages-${{ matrix.os }}-${{ matrix.python-version }}-${{ hashFiles('pdm.lock') }} 36 | restore-keys: | 37 | pypackages-${{ matrix.os }}-${{ matrix.python-version }}- 38 | 39 | - name: Install dependencies 40 | run: pdm install -v 41 | # On Windows, interactive test doesn't work, so exclude it. 42 | 43 | - name: Run tests 44 | run: pdm run tox -v 45 | 46 | - name: Interactive tests 47 | if: runner.os != 'Windows' 48 | run: pdm run tox -eextra -v 49 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pytest 3 | from unittest.mock import patch 4 | from sys import modules 5 | 6 | PDIR2_CONFIG_FILE = "PDIR2_CONFIG_FILE" 7 | 8 | 9 | def remove_module_cache(): 10 | """ 11 | There are some global settings which are initialized when pdir firstly 12 | import, then after that, no matter how you change the config or mock 13 | ``isatty()`` functions, those global values (settings, mostly), will 14 | not change. 15 | 16 | So in order to make some of our patches or test configurations work, we 17 | need to clear the import cache. So that when we ``import pdir`` in test 18 | cases, those global values will be initialized again due to the lack of 19 | cache. 20 | 21 | more detail: https://www.kawabangga.com/posts/4706 (Chinese) 22 | """ 23 | imported_modules = modules.keys() 24 | pdir_modules = [m for m in imported_modules if m.startswith('pdir')] 25 | for module in pdir_modules: 26 | try: 27 | del modules[module] 28 | except KeyError: 29 | pass 30 | 31 | 32 | @pytest.fixture 33 | def clean_cached_modules(): 34 | remove_module_cache() 35 | 36 | DEFAULT_CONFIG_FILE = os.path.join(os.path.expanduser('~'), '.pdir2config') 37 | yield DEFAULT_CONFIG_FILE 38 | if PDIR2_CONFIG_FILE in os.environ: 39 | if os.path.exists(os.environ[PDIR2_CONFIG_FILE]): 40 | os.remove(os.environ[PDIR2_CONFIG_FILE]) 41 | del os.environ[PDIR2_CONFIG_FILE] 42 | if os.path.exists(DEFAULT_CONFIG_FILE): 43 | os.remove(DEFAULT_CONFIG_FILE) 44 | 45 | 46 | @pytest.fixture(scope="session") 47 | def fake_tty(): 48 | with patch("sys.stdout.isatty") as faketty: 49 | faketty.return_value = True 50 | remove_module_cache() 51 | yield 52 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "pdir2" 3 | version = "1.1.2" 4 | authors = [{ name = "laike9m", email = "laike9m@gmail.com" }] 5 | dependencies = ['colorama;platform_system=="Windows"', 'typing-extensions==4.*'] 6 | requires-python = ">=3.10" 7 | license = { text = "MIT" } 8 | description = "Pretty dir printing with joy" 9 | readme = "README.md" 10 | classifiers = [ 11 | 'Intended Audience :: Developers', 12 | 'License :: OSI Approved :: MIT License', 13 | 'Operating System :: MacOS :: MacOS X', 14 | 'Operating System :: Microsoft :: Windows', 15 | 'Operating System :: POSIX', 16 | 'Programming Language :: Python', 17 | 'Programming Language :: Python :: 3', 18 | 'Programming Language :: Python :: 3.10', 19 | 'Programming Language :: Python :: 3.11', 20 | 'Programming Language :: Python :: 3.12', 21 | 'Programming Language :: Python :: 3.13', 22 | 'Programming Language :: Python :: 3.14', 23 | 'Topic :: Software Development :: Libraries :: Python Modules', 24 | 'Programming Language :: Python :: Implementation :: PyPy', 25 | 'Programming Language :: Python :: Implementation :: CPython', 26 | ] 27 | 28 | [project.urls] 29 | Funding = "https://github.com/sponsors/laike9m" 30 | "Bug Tracker" = "https://github.com/laike9m/pdir2/issues" 31 | homepage = "https://github.com/laike9m/pdir2" 32 | repository = "https://github.com/laike9m/pdir2" 33 | 34 | [tool.pdm.dev-dependencies] 35 | dev = [ 36 | "pytest==7.*", 37 | "tox==4.*", 38 | "tox-pdm==0.5.*", 39 | "ptpython==3.0.*", 40 | "bpython>=0.24", 41 | "ipython==7.16.*", 42 | "pytest-mypy==0.10.*", 43 | "hypothesis==6.21.*", 44 | "tox-gh-actions==3.*", 45 | "mypy>=1.4", 46 | "twine>=4.0.2", 47 | ] 48 | 49 | [build-system] 50 | requires = ["pdm-pep517"] 51 | build-backend = "pdm.pep517.api" 52 | 53 | [tool.black] 54 | skip-string-normalization = true 55 | 56 | [[tool.mypy.overrides]] 57 | module = ["pytest"] 58 | ignore_missing_imports = true 59 | -------------------------------------------------------------------------------- /tests/test_search.py: -------------------------------------------------------------------------------- 1 | def test_search_without_argument(fake_tty): 2 | import pdir 3 | 4 | foo = 1 5 | bar = 1 6 | baz = 1 7 | apple1 = 1 8 | xapple2 = 1 9 | result, result2 = pdir().s('apple'), pdir().search('apple') 10 | assert repr(result) == ( 11 | '\x1b[0;33mproperty:\x1b[0m\n' 12 | ' \x1b[0;36mapple1\x1b[0m\x1b[1;30m,' 13 | ' \x1b[0m\x1b[0;36mxapple2\x1b[0m' 14 | ) 15 | assert repr(result2) == ( 16 | '\x1b[0;33mproperty:\x1b[0m\n' 17 | ' \x1b[0;36mapple1\x1b[0m\x1b[1;30m,' 18 | ' \x1b[0m\x1b[0;36mxapple2\x1b[0m' 19 | ) 20 | 21 | 22 | def test_search_with_argument(fake_tty): 23 | import pdir 24 | import sys 25 | 26 | class T: 27 | pass 28 | 29 | result, result2 = pdir(T).s('attr'), pdir(T).search('attr') 30 | result3, result4 = pdir(T).s('Attr'), pdir(T).search('Attr') 31 | 32 | if sys.version_info >= (3, 13): 33 | expected = '\n'.join( 34 | [ 35 | '\x1b[0;33mspecial attribute:\x1b[0m', 36 | ' \x1b[0;36m__static_attributes__\x1b[0m', 37 | '\x1b[0;33mattribute access:\x1b[0m', 38 | ( 39 | ' \x1b[0;36m__delattr__\x1b[0m\x1b[1;30m, ' 40 | '\x1b[0m\x1b[0;36m__getattribute__\x1b[0m\x1b[1;30m, ' 41 | '\x1b[0m\x1b[0;36m__setattr__\x1b[0m' 42 | ), 43 | ] 44 | ) 45 | else: 46 | expected = '\n'.join( 47 | [ 48 | '\x1b[0;33mattribute access:\x1b[0m', 49 | ( 50 | ' \x1b[0;36m__delattr__\x1b[0m\x1b[1;30m, ' 51 | '\x1b[0m\x1b[0;36m__getattribute__\x1b[0m\x1b[1;30m, ' 52 | '\x1b[0m\x1b[0;36m__setattr__\x1b[0m' 53 | ), 54 | ] 55 | ) 56 | assert repr(result) == expected 57 | assert repr(result2) == expected 58 | assert repr(result3) == expected 59 | assert repr(result4) == expected 60 | 61 | # Case sensitive 62 | result5, result6 = pdir(T).s('Attr', True), pdir(T).search('Attr', True) 63 | assert repr(result5) == '' 64 | assert repr(result6) == '' 65 | -------------------------------------------------------------------------------- /pdir/color.py: -------------------------------------------------------------------------------- 1 | from ._internal_utils import is_bpython 2 | from typing_extensions import Protocol 3 | 4 | 5 | class _Renderable(Protocol): 6 | def wrap_text(self, text: str) -> str: 7 | pass 8 | 9 | def __eq__(self, other: object) -> bool: 10 | pass 11 | 12 | 13 | class _Color(_Renderable): 14 | def __init__(self, color_code: int, bright: bool = False) -> None: 15 | self.color_code = str(color_code) 16 | self.intensity = '1' if bright else '0' 17 | 18 | def wrap_text(self, text: str) -> str: 19 | if not is_bpython(): 20 | return f'\033[{self.intensity};{self.color_code}m{text}\033[0m' 21 | 22 | colored_text = f'\033[{self.color_code}m{text}\033[0m' 23 | if self.intensity == '0': 24 | return colored_text 25 | else: 26 | return '\033[1m' + colored_text 27 | 28 | def __eq__(self, other: object) -> bool: # type: ignore 29 | # __eq__ should work with any objects. 30 | # https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides 31 | if not isinstance(other, _Color): 32 | return False 33 | 34 | return self.color_code == other.color_code 35 | 36 | def __repr__(self): 37 | return f'\033[{self.color_code}m{"color"}\033[0m' 38 | 39 | 40 | class _ColorDisabled(_Renderable): 41 | def wrap_text(self, text: str) -> str: 42 | return text 43 | 44 | def __eq__(self, other: object) -> bool: 45 | if isinstance(other, _ColorDisabled): 46 | return True 47 | return False 48 | 49 | 50 | COLORS = { 51 | 'black': _Color(30), 52 | 'bright black': _Color(30, True), 53 | 'grey': _Color(30, True), 54 | 'red': _Color(31), 55 | 'bright red': _Color(31, True), 56 | 'green': _Color(32), 57 | 'bright green': _Color(32, True), 58 | 'yellow': _Color(33), 59 | 'bright yellow': _Color(33, True), 60 | 'blue': _Color(34), 61 | 'bright blue': _Color(34, True), 62 | 'magenta': _Color(35), 63 | 'bright magenta': _Color(35, True), 64 | 'cyan': _Color(36), 65 | 'bright cyan': _Color(36, True), 66 | 'white': _Color(37), 67 | 'bright white': _Color(37, True), 68 | } 69 | COLOR_DISABLED = _ColorDisabled() 70 | -------------------------------------------------------------------------------- /pdir/_internal_utils.py: -------------------------------------------------------------------------------- 1 | import inspect 2 | import sys 3 | from typing import Any 4 | 5 | from .constants import SLOT_TYPE, ReplType 6 | 7 | 8 | def get_attr_from_dict(inspected_obj: Any, attr_name: str) -> Any: 9 | """Ensures we get descriptor object instead of its return value.""" 10 | if inspect.isclass(inspected_obj): 11 | obj_list = [inspected_obj] + list(inspected_obj.__mro__) 12 | else: 13 | obj_list = [inspected_obj] + list(inspected_obj.__class__.__mro__) 14 | for obj in obj_list: 15 | if hasattr(obj, '__dict__') and attr_name in obj.__dict__: 16 | return obj.__dict__[attr_name] 17 | # This happens when user-defined __dir__ returns something that's not 18 | # in any __dict__. See test_override_dir. 19 | # Returns attr_name so that it's treated as a normal property. 20 | return attr_name 21 | 22 | 23 | def is_slotted_attr(child_obj: Any, attr_name: str) -> bool: 24 | return any( 25 | isinstance(getattr(obj, attr_name, None), SLOT_TYPE) 26 | for obj in list(child_obj.__class__.__mro__) 27 | ) 28 | 29 | 30 | def _get_repl_type() -> ReplType: 31 | if any(ReplType.PTPYTHON.value in key for key in sys.modules): 32 | return ReplType.PTPYTHON 33 | if any(ReplType.BPYTHON.value in key for key in sys.modules): 34 | return ReplType.BPYTHON 35 | try: 36 | __IPYTHON__ # type: ignore 37 | return ReplType.IPYTHON 38 | except NameError: 39 | return ReplType.PYTHON 40 | 41 | 42 | def is_bpython() -> bool: 43 | return _get_repl_type() == ReplType.BPYTHON 44 | 45 | 46 | def is_ptpython() -> bool: 47 | return _get_repl_type() == ReplType.PTPYTHON 48 | 49 | 50 | def get_first_sentence_of_docstring(obj: Any) -> str: 51 | """Attempt to get the first sentence from obj's docstring. 52 | 53 | There might be more than one sentence or some non-ending dots 54 | in docstring, so it's better to parse by `. ` rather than `.`. 55 | If no dots are found, original docstring will be returned. 56 | """ 57 | docstring = get_docstring_from_obj(obj) 58 | if not docstring: 59 | return '' 60 | 61 | joined = ' '.join(docstring.split('\n')) + ' ' 62 | try: 63 | first_sentence_end_pos = joined.index('. ') 64 | except ValueError: 65 | return joined.strip() 66 | 67 | return joined[: first_sentence_end_pos + 1] 68 | 69 | 70 | def get_docstring_from_obj(obj: Any) -> str: 71 | """ 72 | SystemError may occur on jpype objects, 73 | see https://github.com/laike9m/pdir2/pull/57. 74 | """ 75 | try: 76 | return inspect.getdoc(obj) or '' 77 | except Exception: 78 | return '' 79 | -------------------------------------------------------------------------------- /tests/test_slots.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test classes with __slots__ 3 | """ 4 | 5 | from typing import List 6 | import pdir 7 | from pdir.attr_category import AttrCategory, category_match 8 | 9 | 10 | BASE = 'base' 11 | DERIVE = 'derive' 12 | 13 | 14 | class BaseNoSlot: 15 | pass 16 | 17 | 18 | class BaseEmptySlot: 19 | __slots__: List[str] = [] 20 | 21 | 22 | class BaseSlot: 23 | __slots__: List[str] = [BASE] 24 | 25 | 26 | class DeriveNoSlotBaseEmpty(BaseEmptySlot): 27 | pass 28 | 29 | 30 | class DeriveNoSlotBaseSlot(BaseSlot): 31 | pass 32 | 33 | 34 | class DeriveEmptySlotBaseNo(BaseNoSlot): 35 | __slots__: List[str] = [] 36 | 37 | 38 | class DeriveEmptySlotBaseEmpty(BaseEmptySlot): 39 | __slots__: List[str] = [] 40 | 41 | 42 | class DeriveEmptySlotBaseSlot(BaseSlot): 43 | __slots__: List[str] = [] 44 | 45 | 46 | class DeriveSlotBaseNo(BaseNoSlot): 47 | __slots__ = [DERIVE] 48 | 49 | 50 | class DeriveSlotBaseEmpty(BaseEmptySlot): 51 | __slots__ = [DERIVE] 52 | 53 | 54 | class DeriveSlotBaseSlot(BaseSlot): 55 | __slots__ = [DERIVE] 56 | 57 | 58 | def test_not_set(): 59 | expected_res = [ # class type empty slot attr num 60 | (DeriveNoSlotBaseEmpty, 0), 61 | (DeriveNoSlotBaseSlot, 1), 62 | (DeriveEmptySlotBaseNo, 0), 63 | (DeriveEmptySlotBaseEmpty, 0), 64 | (DeriveEmptySlotBaseSlot, 1), 65 | (DeriveSlotBaseNo, 1), 66 | (DeriveSlotBaseEmpty, 1), 67 | (DeriveSlotBaseSlot, 2), 68 | ] 69 | for c_type, attr_num in expected_res: 70 | attr_count = 0 71 | for attr in pdir(c_type()).pattrs: 72 | if attr.name in [BASE, DERIVE]: 73 | attr_count += 1 74 | assert category_match(attr.category, AttrCategory.DESCRIPTOR) 75 | assert category_match(attr.category, AttrCategory.SLOT) 76 | assert attr_count == attr_num 77 | 78 | 79 | def test_set_derive(): 80 | c_types = [DeriveSlotBaseNo, DeriveSlotBaseEmpty, DeriveSlotBaseSlot] 81 | for c_type in c_types: 82 | instance = c_type() 83 | instance.derive = 'foo' 84 | for attr in pdir(instance).pattrs: 85 | if attr.name == DERIVE: 86 | assert category_match(attr.category, AttrCategory.DESCRIPTOR) 87 | assert category_match(attr.category, AttrCategory.SLOT) 88 | break 89 | else: 90 | # No derive attribute found 91 | assert False 92 | 93 | 94 | def test_set_base(): 95 | c_types = [DeriveNoSlotBaseSlot, DeriveEmptySlotBaseSlot, DeriveSlotBaseSlot] 96 | for c_type in c_types: 97 | instance = c_type() 98 | instance.base = 'foo' 99 | for attr in pdir(instance).pattrs: 100 | if attr.name == BASE: 101 | assert category_match(attr.category, AttrCategory.DESCRIPTOR) 102 | assert category_match(attr.category, AttrCategory.SLOT) 103 | break 104 | else: 105 | # No base attribute found 106 | assert False 107 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pdir2: Pretty dir() printing with joy 2 | 3 | ![Build status](https://github.com/laike9m/pdir2/actions/workflows/ci.yml/badge.svg) 4 | [![Supported Python versions](https://img.shields.io/pypi/pyversions/pdir2.svg)](https://pypi.python.org/pypi/pdir2/) 5 | ![PyPI Version](https://img.shields.io/pypi/v/pdir2.svg) 6 | Code style: black 7 | 8 | Have you ever dreamed of a better output of `dir()`? I do. So I created this. 9 | 10 | ![](https://github.com/laike9m/pdir2/raw/master/images/presentation_v2.gif) 11 | 12 | ## Features 13 | 14 | - Attributes are grouped by types/functionalities, with beautiful colors. 15 | 16 | - Support color customization, [here's how](https://github.com/laike9m/pdir2/wiki/User-Configuration). 17 | 18 | - Support all platforms including Windows(Thanks to [colorama](https://github.com/tartley/colorama)). 19 | 20 | - Support [ipython](https://github.com/ipython/ipython), [ptpython](https://github.com/jonathanslenders/ptpython), [bpython](https://www.bpython-interpreter.org/) and [Jupyter Notebook](http://jupyter.org/)! See [wiki](https://github.com/laike9m/pdir2/wiki/REPL-Support) for details. 21 | 22 | - The return value of `pdir()` can still be used as a list of names. 23 | 24 | - ✨ Attribute searching 25 | 26 | You can search for certain names with `.s()` or `.search()`: 27 | 28 | ![](https://github.com/laike9m/pdir2/raw/master/images/search.gif) 29 | 30 | Search is case-insensitive by default. 31 | `search(name, case_sensitive=True)` does case-sensitive searching. 32 | 33 | - :star2: Attribute filtering 34 | 35 | `properties`: Find properties/variables defined in the inspected object. 36 | 37 | `methods`: Find methods/functions defined in the inspected object. 38 | 39 | `public`: Find public attributes. 40 | 41 | `own`: Find attributes that are not inherited from parent classes. 42 | 43 | These filters **can be chained!** Order does **NOT** matter. 44 | 45 | For example, use `pdir(obj).public.own.methods` to find all public own methods. 46 | 47 | You can also call `search` on the returned results. 48 | 49 | See a [complete example](https://github.com/laike9m/pdir2/wiki/Attribute-Filtering). 50 | 51 | ## Install 52 | 53 | ### Generic 54 | 55 | pip install pdir2 56 | 57 | About the name. I wanted to call it "pdir", but there's already one with this 58 | name on pypi. Mine is better, of course. 59 | 60 | ### Fedora 61 | 62 | dnf install python3-pdir2 63 | 64 | ## Automatic Import 65 | 66 | As a better alternative of `dir()`, it's more convenient to automatically import 67 | pdir2 when launching REPL. Luckily, Python provides a way to do this. In you `.bashrc`(or `.zshrc`), add this line: 68 | 69 | export PYTHONSTARTUP=$HOME/.pythonstartup 70 | 71 | Then, create `.pythonstartup` in your home folder. Add one line: 72 | 73 | import pdir 74 | 75 | Next time you launch REPL, `pdir()` is already there, Hooray! 76 | 77 | ## Development 78 | 79 | 1. Set up development environment 80 | 81 | - **PDM**: pdir2 uses [PDM](https://pdm.fming.dev/latest/) to manage dependencies, so you want to make sure it's installed. 82 | - **pyenv**: Since you need to test pdir2 on multiple Python versions, [pyenv](https://github.com/pyenv/pyenv) is highly recommended. Make sure you have Python 3.10, 3.11, 3.12, 3.13, and 3.14 installed. 83 | 84 | 2. Install dev dependencies 85 | 86 | Simply run `pdm install`. 87 | 88 | If you want to work on a specific Python version, run `pdm use [PYTHON_VERSION]` first to switch PDM to that version (e.g. `pdm use 3.9` if you want to debug a Python 3.9 specific issue). 89 | 90 | 91 | 3. Run tests 92 | 93 | Run `pdm run tox` 94 | 95 | The guide may be incomplete. Please file bugs if you encounter any issues. 96 | -------------------------------------------------------------------------------- /pdir/format.py: -------------------------------------------------------------------------------- 1 | """ 2 | Defines how attr is organized and displayed. 3 | """ 4 | from collections import namedtuple 5 | from collections.abc import Iterable 6 | from itertools import groupby 7 | from typing import List 8 | 9 | from . import api # noqa: F401, '.api' imported but unused 10 | from .attr_category import AttrCategory 11 | from .configuration import attribute_color, category_color, comma, doc_color, slot_tag 12 | 13 | 14 | def format_pattrs(pattrs: List["api.PrettyAttribute"]) -> str: 15 | """Generates repr string given a list of pattrs.""" 16 | pattrs.sort( 17 | key=lambda x: ( 18 | _FORMATTER[x.display_group].display_index, 19 | x.display_group, 20 | x.name, 21 | ) 22 | ) 23 | output = [ 24 | _FORMATTER[display_group].formatter(display_group, grouped_pattrs) 25 | for display_group, grouped_pattrs in groupby(pattrs, lambda x: x.display_group) 26 | ] 27 | 28 | return "\n".join(output) 29 | 30 | 31 | def _format_single_line(category: AttrCategory, pattrs: Iterable) -> str: 32 | category_line = category_color.wrap_text(str(category) + ":") 33 | output_text = [] 34 | for pattr in pattrs: 35 | single_attr = attribute_color.wrap_text(pattr.name) 36 | output_text.append(single_attr + slot_tag if pattr.slotted else single_attr) 37 | return f"{category_line}\n {comma.join(output_text)}" 38 | 39 | 40 | def _format_multiline_with_doc(category: AttrCategory, pattrs: Iterable) -> str: 41 | category_line = category_color.wrap_text(str(category) + ":") + "\n" 42 | output_text = [] 43 | for pattr in pattrs: 44 | name = attribute_color.wrap_text(pattr.name) 45 | if pattr.slotted: 46 | name += slot_tag 47 | name += attribute_color.wrap_text(": ") 48 | doc = doc_color.wrap_text(pattr.doc) 49 | output_text.append(f" {name}{doc}") 50 | return category_line + "\n".join(output_text) 51 | 52 | 53 | def _format_descriptor(category: AttrCategory, attrs: Iterable) -> str: 54 | return _format_multiline_with_doc(category, attrs) 55 | 56 | 57 | _AttributeGroupFormatter = namedtuple( 58 | "_AttributeGroupFormatter", ["display_index", "formatter"] 59 | ) 60 | 61 | _single_line = _AttributeGroupFormatter(display_index=0, formatter=_format_single_line) 62 | _descriptor = _AttributeGroupFormatter(display_index=1, formatter=_format_descriptor) 63 | _multiline_with_doc = _AttributeGroupFormatter( 64 | display_index=2, formatter=_format_multiline_with_doc 65 | ) 66 | 67 | _FORMATTER = { 68 | AttrCategory.SLOT: _single_line, 69 | AttrCategory.FUNCTION: _multiline_with_doc, 70 | AttrCategory.CLASS: _multiline_with_doc, 71 | AttrCategory.EXCEPTION: _multiline_with_doc, 72 | AttrCategory.PROPERTY: _single_line, 73 | # Attribute 74 | AttrCategory.MODULE_ATTRIBUTE: _single_line, 75 | AttrCategory.SPECIAL_ATTRIBUTE: _single_line, 76 | # Function 77 | AttrCategory.MAGIC: _multiline_with_doc, 78 | AttrCategory.ARITHMETIC: _single_line, 79 | AttrCategory.ITER: _single_line, 80 | AttrCategory.CONTEXT_MANAGER: _single_line, 81 | AttrCategory.OBJECT_CUSTOMIZATION: _single_line, 82 | AttrCategory.RICH_COMPARISON: _single_line, 83 | AttrCategory.ATTRIBUTE_ACCESS: _single_line, 84 | AttrCategory.DESCRIPTOR: _descriptor, 85 | AttrCategory.DESCRIPTOR_CLASS: _single_line, 86 | AttrCategory.STATIC_METHOD: _descriptor, 87 | AttrCategory.CLASS_CUSTOMIZATION: _single_line, 88 | AttrCategory.CONTAINER: _single_line, 89 | AttrCategory.COROUTINE: _single_line, 90 | AttrCategory.COPY: _single_line, 91 | AttrCategory.PICKLE: _single_line, 92 | AttrCategory.ABSTRACT_CLASS: _single_line, 93 | AttrCategory.PATTERN_MATCHING: _single_line, 94 | AttrCategory.TYPING: _single_line, 95 | AttrCategory.DECORATOR: _single_line, 96 | AttrCategory.BUFFER: _single_line, 97 | } 98 | -------------------------------------------------------------------------------- /tests/test_buggy_attrs.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test attrs that previously caused bugs. 3 | """ 4 | 5 | import pytest 6 | import pdir 7 | from pdir.attr_category import AttrCategory, category_match 8 | 9 | 10 | def test_dataframe(): 11 | pandas = pytest.importorskip("pandas") 12 | result = pdir(pandas.DataFrame) 13 | for attr in result.pattrs: 14 | if attr.name in ('columns', 'index'): 15 | assert category_match(attr.category, AttrCategory.PROPERTY) 16 | 17 | 18 | def test_type(): 19 | result = pdir(type) 20 | for attr in result.pattrs: 21 | if attr.name == '__abstractmethods__': 22 | assert category_match(attr.category, AttrCategory.ABSTRACT_CLASS) 23 | return 24 | 25 | 26 | def test_list(): 27 | result = pdir(list) 28 | for attr in result.pattrs: 29 | if attr.name == 'append': 30 | assert category_match(attr.category, AttrCategory.FUNCTION) 31 | return 32 | 33 | 34 | class D: 35 | """this is D""" 36 | 37 | def __init__(self): 38 | pass 39 | 40 | def __get__(self, instance, type=None): 41 | pass 42 | 43 | def __set__(self, instance, value): 44 | pass 45 | 46 | def __delete__(self, obj): 47 | pass 48 | 49 | 50 | class RevealAccess: 51 | """this is R""" 52 | 53 | def __init__(self, initval=None, name='var'): 54 | self.val = initval 55 | self.name = name 56 | 57 | def __get__(self, obj, objtype): 58 | print('Retrieving', self.name) 59 | return self.val 60 | 61 | def __set__(self, obj, val): 62 | print('Updating', self.name) 63 | self.val = val 64 | 65 | def __delete__(self, obj): 66 | pass 67 | 68 | 69 | def test_descriptor(): 70 | class T: 71 | r = RevealAccess(10, 'var ' r'') 72 | 73 | def __init__(self): 74 | self.d = D() 75 | 76 | @property 77 | def p(self): 78 | 'this is p' 79 | return 1 80 | 81 | @p.setter 82 | def p(self): 83 | pass 84 | 85 | @p.deleter 86 | def p(self): 87 | pass 88 | 89 | t = T() 90 | pattrs = pdir(t).pattrs 91 | for pattr in pattrs: 92 | if pattr.name == 'd': 93 | assert category_match(pattr.category, AttrCategory.DESCRIPTOR) 94 | assert pattr.doc == ('class D with getter, setter, deleter, ' 'this is D') 95 | if pattr.name == 'r': 96 | assert category_match(pattr.category, AttrCategory.DESCRIPTOR) 97 | assert pattr.doc == ( 98 | 'class RevealAccess with getter, setter, ' 'deleter, this is R' 99 | ) 100 | if pattr.name == 'p': 101 | assert category_match(pattr.category, AttrCategory.DESCRIPTOR) 102 | assert pattr.doc == ('@property with getter, setter, ' 'deleter, this is p') 103 | 104 | 105 | def test_override_dir(): 106 | # In the class attrs in `__dir__()` can not be found in `__dict__` 107 | class ClassWithUserDefinedDir: 108 | def __dir__(self): 109 | return ['foo'] 110 | 111 | inst = ClassWithUserDefinedDir() 112 | pattrs = pdir(inst).pattrs 113 | assert ('foo' in pdir(inst)) == ('foo' in dir(inst)) 114 | assert ('foo' in [pattr.name for pattr in pattrs]) == ('foo' in dir(inst)) 115 | 116 | 117 | def test_get_attribute_fail(): 118 | """ "Tests if get_online_doc returns '' when __doc__ access throws an exception.""" 119 | 120 | class DocAttributeFail: 121 | """Fails when __doc__ atribute is accessed.""" 122 | 123 | def __getattribute__(self, name): 124 | if name == '__doc__': 125 | raise Exception('failed successfully') 126 | else: 127 | return super().__getattribute__(name) 128 | 129 | class DocFailContainer: 130 | """Holds attributes that fail when __doc__ is accessed.""" 131 | 132 | dac1 = DocAttributeFail() 133 | 134 | def __init__(self): 135 | self.dac2 = DocAttributeFail() 136 | 137 | for pattr in pdir(DocFailContainer()).pattrs: 138 | if pattr.name in ['dac1', 'dac2']: 139 | assert pattr.get_oneline_doc() == '' 140 | -------------------------------------------------------------------------------- /pdir/configuration.py: -------------------------------------------------------------------------------- 1 | """Configuration management setup 2 | """ 3 | 4 | import os 5 | import sys 6 | from configparser import ConfigParser 7 | from os.path import expanduser 8 | 9 | from .color import COLORS, COLOR_DISABLED 10 | 11 | # User Configuration 12 | _DEFAULT_CONFIG_FILE = expanduser('~/.pdir2config') 13 | _DEFAULT = 'global' 14 | _UNIFORM_COLOR = 'uniform-color' 15 | _COLORFUL_OUTPUT = 'enable-colorful-output' 16 | TRUTHY_TERMS = frozenset({'True', 'Y', '1', 'true'}) 17 | VALID_CONFIG_KEYS = frozenset( 18 | { 19 | 'category-color', 20 | 'attribute-color', 21 | 'comma-color', 22 | 'doc-color', 23 | 'slot-color', 24 | } 25 | ) 26 | 27 | 28 | class Configuration: 29 | _uniform_color = None 30 | _enable_colorful_output = None 31 | _category_color = COLORS['yellow'] 32 | _attribute_color = COLORS['cyan'] 33 | _comma_color = COLORS['grey'] 34 | _doc_color = COLORS['grey'] 35 | _slot_color = COLORS['magenta'] 36 | 37 | def __init__(self): 38 | self._configparser = ConfigParser() 39 | self._load() 40 | 41 | @property 42 | def enable_colorful_output(self): 43 | return self._enable_colorful_output 44 | 45 | @property 46 | def uniform_color(self): 47 | return self._uniform_color 48 | 49 | @property 50 | def category_color(self): 51 | return self._category_color 52 | 53 | @property 54 | def attribute_color(self): 55 | return self._attribute_color 56 | 57 | @property 58 | def comma_color(self): 59 | return self._comma_color 60 | 61 | @property 62 | def doc_color(self): 63 | return self._doc_color 64 | 65 | @property 66 | def slot_color(self): 67 | return self._slot_color 68 | 69 | def _load(self): 70 | config_file = os.environ.get('PDIR2_CONFIG_FILE', _DEFAULT_CONFIG_FILE) 71 | config_file = os.path.expanduser(config_file) 72 | if not os.path.exists(config_file): 73 | if config_file == _DEFAULT_CONFIG_FILE: 74 | # Only raise exception if user set CONFIG_FILE_ENV. 75 | return 76 | else: 77 | raise OSError('Config file not exist: %s' % config_file) 78 | 79 | self._configparser.read(config_file) 80 | if not self._configparser.has_section(_DEFAULT): 81 | return 82 | user_config_dict = dict(self._configparser.items(_DEFAULT)) 83 | 84 | for item, color in user_config_dict.items(): 85 | if item == _COLORFUL_OUTPUT: 86 | self._enable_colorful_output = user_config_dict.get(_COLORFUL_OUTPUT) 87 | continue 88 | # UNIFORM_COLOR suppresses other settings. 89 | if item == _UNIFORM_COLOR: 90 | self._uniform_color = COLORS[user_config_dict[_UNIFORM_COLOR]] 91 | return 92 | # then the color settings 93 | if item not in VALID_CONFIG_KEYS: 94 | raise ValueError('Invalid key: %s' % item) 95 | if color not in set(COLORS.keys()): 96 | raise ValueError('Invalid color value: %s' % color) 97 | # item uses "-", e.g. "doc-color" 98 | self.__setattr__('_' + item.replace('-', '_'), COLORS[color]) 99 | 100 | 101 | _cfg = Configuration() 102 | 103 | 104 | def should_enable_colorful_output() -> bool: 105 | """When set, environ suppresses config file.""" 106 | environ_set = os.getenv("PDIR2_NOCOLOR") 107 | if environ_set and environ_set in TRUTHY_TERMS: 108 | return False 109 | 110 | if ( 111 | _cfg.enable_colorful_output is None or _cfg.enable_colorful_output == "auto" 112 | ): # Not set, default to "auto" 113 | return sys.stdout.isatty() 114 | 115 | return _cfg.enable_colorful_output == "True" 116 | 117 | 118 | if should_enable_colorful_output(): 119 | if _cfg.uniform_color: 120 | category_color = attribute_color = doc_color = _cfg.uniform_color 121 | comma = _cfg.uniform_color.wrap_text(', ') 122 | slot_tag = _cfg.uniform_color.wrap_text('(slotted)') 123 | else: 124 | category_color = _cfg.category_color 125 | attribute_color = _cfg.attribute_color 126 | doc_color = _cfg.doc_color 127 | comma = _cfg.comma_color.wrap_text(', ') 128 | slot_tag = _cfg.slot_color.wrap_text('(slotted)') 129 | else: 130 | category_color = attribute_color = doc_color = COLOR_DISABLED 131 | comma = ', ' 132 | slot_tag = '(slotted)' 133 | -------------------------------------------------------------------------------- /tests/test_filters.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests attribute filter's behaviors. 3 | """ 4 | 5 | import collections 6 | import sys 7 | import pdir 8 | 9 | 10 | # https://github.com/python/cpython/blob/da2bf9f66d0c95b988c5d87646d168f65499b316/Lib/unittest/case.py#L1164-L1195 11 | def check_items_equality(first, second): 12 | """A simplified version of the unittest.assertEqual method.""" 13 | first_seq, second_seq = list(first), list(second) 14 | first = collections.Counter(first_seq) 15 | second = collections.Counter(second_seq) 16 | assert first == second 17 | 18 | 19 | class Base: 20 | base_class_variable = 1 21 | 22 | def __init__(self): 23 | self.base_instance_variable = 2 24 | 25 | def base_method(self): 26 | pass 27 | 28 | 29 | class DerivedClass(Base): 30 | derived_class_variable = 1 31 | 32 | def __init__(self): 33 | self.derived_instance_variable = 2 34 | super().__init__() 35 | 36 | def derived_method(self): 37 | pass 38 | 39 | 40 | inst = DerivedClass() 41 | 42 | 43 | def test_properties(): 44 | extra_items = ['__firstlineno__', '__static_attributes__'] if sys.version_info >= (3, 13) else [] 45 | check_items_equality( 46 | [p.name for p in pdir(inst).properties.pattrs], 47 | [ 48 | 'base_class_variable', 49 | 'base_instance_variable', 50 | 'derived_class_variable', 51 | 'derived_instance_variable', 52 | '__class__', 53 | '__dict__', 54 | '__doc__', 55 | '__module__', 56 | '__weakref__', 57 | ] 58 | + extra_items, 59 | ) 60 | 61 | 62 | def test_methods(): 63 | extra_items = ['__getstate__'] if sys.version_info >= (3, 11) else [] 64 | check_items_equality( 65 | [p.name for p in pdir(inst).methods.pattrs], 66 | [ 67 | '__subclasshook__', 68 | '__delattr__', 69 | '__dir__', 70 | '__getattribute__', 71 | '__setattr__', 72 | '__init_subclass__', 73 | 'base_method', 74 | 'derived_method', 75 | '__format__', 76 | '__hash__', 77 | '__init__', 78 | '__new__', 79 | '__repr__', 80 | '__sizeof__', 81 | '__str__', 82 | '__reduce__', 83 | '__reduce_ex__', 84 | '__eq__', 85 | '__ge__', 86 | '__gt__', 87 | '__le__', 88 | '__lt__', 89 | '__ne__', 90 | ] 91 | + extra_items, 92 | ) 93 | 94 | 95 | def test_public(): 96 | check_items_equality( 97 | [p.name for p in pdir(inst).public.pattrs], 98 | [ 99 | 'base_method', 100 | 'derived_method', 101 | 'base_class_variable', 102 | 'base_instance_variable', 103 | 'derived_class_variable', 104 | 'derived_instance_variable', 105 | ], 106 | ) 107 | 108 | 109 | def test_own(): 110 | extra_items = ['__firstlineno__', '__static_attributes__'] if sys.version_info >= (3, 13) else [] 111 | check_items_equality( 112 | [p.name for p in pdir(inst).own.pattrs], 113 | [ 114 | 'derived_method', 115 | '__init__', 116 | 'base_instance_variable', 117 | 'derived_class_variable', 118 | 'derived_instance_variable', 119 | '__doc__', 120 | '__module__', 121 | ] 122 | + extra_items, 123 | ) 124 | 125 | 126 | def test_chained_filters(): 127 | check_items_equality( 128 | [p.name for p in pdir(inst).public.own.properties.pattrs], 129 | [ 130 | 'base_instance_variable', 131 | 'derived_class_variable', 132 | 'derived_instance_variable', 133 | ], 134 | ) 135 | 136 | 137 | def test_order_of_chained_filters(): 138 | check_items_equality( 139 | [p.name for p in pdir(inst).own.properties.public.pattrs], 140 | [ 141 | 'base_instance_variable', 142 | 'derived_class_variable', 143 | 'derived_instance_variable', 144 | ], 145 | ) 146 | check_items_equality( 147 | [p.name for p in pdir(inst).properties.public.own.pattrs], 148 | [ 149 | 'base_instance_variable', 150 | 'derived_class_variable', 151 | 'derived_instance_variable', 152 | ], 153 | ) 154 | 155 | 156 | def test_filters_with_search(): 157 | def test_chained_filters(): 158 | check_items_equality( 159 | [ 160 | p.name 161 | for p in pdir(inst).public.own.properties.search('derived_in').pattrs 162 | ], 163 | ['derived_instance_variable'], 164 | ) 165 | -------------------------------------------------------------------------------- /tests/test_user_config.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test user configuration. 3 | """ 4 | 5 | import os 6 | import shutil 7 | 8 | import pytest 9 | 10 | 11 | def test_default_env_without_config(fake_tty, clean_cached_modules): 12 | import pdir 13 | 14 | pdir() 15 | 16 | 17 | def test_set_env_without_config(fake_tty, clean_cached_modules): 18 | os.environ['PDIR2_CONFIG_FILE'] = 'aaa' 19 | with pytest.raises(OSError, match='Config file not exist: aaa'): 20 | import pdir 21 | 22 | pdir() 23 | 24 | 25 | def test_read_config(fake_tty, clean_cached_modules): 26 | # 'clean' is the DEFAULT_CONFIG_FILE yielded from fixture. 27 | shutil.copyfile('tests/data/config_1.ini', clean_cached_modules) 28 | from pdir.format import doc_color, category_color, attribute_color, comma 29 | from pdir.color import COLORS 30 | 31 | assert doc_color == COLORS['white'] 32 | assert category_color == COLORS['bright yellow'] 33 | assert comma == '\033[1;32m, \033[0m' 34 | assert attribute_color == COLORS['cyan'] 35 | 36 | 37 | def test_config_disable_color_tty(fake_tty, clean_cached_modules): 38 | # 'clean' is the DEFAULT_CONFIG_FILE yielded from fixture. 39 | shutil.copyfile('tests/data/config_disable_color.ini', clean_cached_modules) 40 | from pdir.format import doc_color, category_color, attribute_color, comma 41 | from pdir.color import COLOR_DISABLED 42 | 43 | assert doc_color == COLOR_DISABLED 44 | assert category_color == COLOR_DISABLED 45 | assert comma == ', ' 46 | assert attribute_color == COLOR_DISABLED 47 | 48 | 49 | def test_config_auto_color_tty(fake_tty, clean_cached_modules): 50 | # 'clean' is the DEFAULT_CONFIG_FILE yielded from fixture. 51 | shutil.copyfile('tests/data/config_auto_color.ini', clean_cached_modules) 52 | from pdir.format import doc_color 53 | from pdir.color import COLORS 54 | 55 | assert doc_color == COLORS['grey'] 56 | 57 | 58 | def test_config_enable_color_not_tty(clean_cached_modules): 59 | # 'clean' is the DEFAULT_CONFIG_FILE yielded from fixture. 60 | shutil.copyfile('tests/data/config_enable_color.ini', clean_cached_modules) 61 | from pdir.format import doc_color 62 | from pdir.color import COLORS 63 | 64 | assert doc_color == COLORS['grey'] 65 | 66 | 67 | def test_env_disable_color_even_config_set(fake_tty, clean_cached_modules): 68 | shutil.copyfile('tests/data/config_enable_color.ini', clean_cached_modules) 69 | os.environ['PDIR2_NOCOLOR'] = "true" 70 | from pdir.format import doc_color, category_color, attribute_color, comma 71 | from pdir.color import COLOR_DISABLED 72 | 73 | assert doc_color == COLOR_DISABLED 74 | assert category_color == COLOR_DISABLED 75 | assert comma == ', ' 76 | assert attribute_color == COLOR_DISABLED 77 | 78 | del os.environ['PDIR2_NOCOLOR'] 79 | 80 | 81 | def test_read_config_from_custom_location(fake_tty, clean_cached_modules): 82 | os.environ['PDIR2_CONFIG_FILE'] = os.path.join(os.path.expanduser('~'), '.myconfig') 83 | shutil.copyfile('tests/data/config_1.ini', os.environ['PDIR2_CONFIG_FILE']) 84 | from pdir.format import doc_color, category_color, attribute_color, comma 85 | from pdir.color import COLORS 86 | 87 | assert doc_color == COLORS['white'] 88 | assert category_color == COLORS['bright yellow'] 89 | assert comma == '\033[1;32m, \033[0m' 90 | assert attribute_color == COLORS['cyan'] 91 | 92 | 93 | def test_uniform_color(fake_tty, clean_cached_modules): 94 | shutil.copyfile('tests/data/config_2.ini', clean_cached_modules) 95 | from pdir.format import doc_color, category_color, attribute_color, comma 96 | from pdir.color import COLORS 97 | 98 | assert doc_color == COLORS['white'] 99 | assert category_color == COLORS['white'] 100 | assert comma == '\033[0;37m, \033[0m' 101 | assert attribute_color == COLORS['white'] 102 | 103 | 104 | def test_empty_config(fake_tty, clean_cached_modules): 105 | shutil.copyfile('tests/data/empty_config.ini', clean_cached_modules) 106 | from pdir.format import doc_color, category_color, attribute_color, comma 107 | from pdir.color import COLORS 108 | 109 | assert doc_color == COLORS['grey'] 110 | assert category_color == COLORS['yellow'] 111 | assert comma == '\033[1;30m, \033[0m' 112 | assert attribute_color == COLORS['cyan'] 113 | 114 | 115 | def test_invalid_config_1(clean_cached_modules): 116 | shutil.copyfile('tests/data/error_config_1.ini', clean_cached_modules) 117 | with pytest.raises(ValueError, match='Invalid key: doc-color1'): 118 | import pdir 119 | 120 | pdir() 121 | 122 | 123 | def test_invalid_config_2(clean_cached_modules): 124 | shutil.copyfile('tests/data/error_config_2.ini', clean_cached_modules) 125 | with pytest.raises(ValueError, match='Invalid color value: 42'): 126 | import pdir 127 | 128 | pdir() 129 | -------------------------------------------------------------------------------- /pdir/api.py: -------------------------------------------------------------------------------- 1 | """ 2 | Convention: 3 | "attr" means the original attribute object. 4 | "pattr" means class PrettyAttribute instance. 5 | """ 6 | 7 | 8 | import platform 9 | from sys import _getframe 10 | from typing import Any, List, Optional, Tuple 11 | 12 | from . import format 13 | from ._internal_utils import ( 14 | get_attr_from_dict, 15 | get_first_sentence_of_docstring, 16 | is_ptpython, 17 | ) 18 | from .attr_category import AttrCategory, category_match, get_attr_category 19 | from .constants import DELETER, GETTER, SETTER, dummy_obj 20 | 21 | if platform.system() == 'Windows': 22 | from colorama import init # type: ignore 23 | 24 | init() # To support Windows. 25 | 26 | 27 | class PrettyDir: 28 | """Class that provides pretty dir and search API.""" 29 | 30 | def __init__( 31 | self, obj: Any = dummy_obj, pattrs: Optional[List['PrettyAttribute']] = None 32 | ) -> None: 33 | """ 34 | Args: 35 | obj: The object to inspect. 36 | pattrs: Used when returning search result. 37 | """ 38 | self.obj = obj 39 | if pattrs is None: 40 | if obj is dummy_obj: 41 | # User is calling dir() without arguments. 42 | attrs = _getframe(1).f_locals 43 | self.dir_result = sorted(list(attrs.keys())) 44 | else: 45 | self.dir_result = dir(self.obj) 46 | attrs = { 47 | name: get_attr_from_dict(self.obj, name) for name in self.dir_result 48 | } 49 | self.pattrs = [ 50 | PrettyAttribute(name, get_attr_category(name, attr, obj), attr) 51 | for name, attr in attrs.items() 52 | ] 53 | else: 54 | self.pattrs = pattrs 55 | self.dir_result = sorted([p.name for p in pattrs]) 56 | 57 | def __repr__(self) -> str: 58 | if not is_ptpython(): 59 | return format.format_pattrs(self.pattrs) 60 | 61 | print(format.format_pattrs(self.pattrs), end='') 62 | return '' 63 | 64 | def __len__(self) -> int: 65 | return len(self.dir_result) 66 | 67 | def __getitem__(self, index: int) -> str: 68 | return self.dir_result[index] 69 | 70 | def index(self, value): 71 | return self.dir_result.index(value) 72 | 73 | def search(self, term: str, case_sensitive: bool = False) -> 'PrettyDir': 74 | """Searches for names that match some pattern. 75 | 76 | Args: 77 | term: String used to match names. A name is returned if it matches 78 | the whole search term. 79 | case_sensitive: Boolean to match case or not, default is False 80 | (case insensitive). 81 | 82 | Return: 83 | A PrettyDir object with matched names. 84 | """ 85 | if case_sensitive: 86 | return PrettyDir( 87 | self.obj, [pattr for pattr in self.pattrs if term in pattr.name] 88 | ) 89 | term = term.lower() 90 | return PrettyDir( 91 | self.obj, [pattr for pattr in self.pattrs if term in pattr.name.lower()] 92 | ) 93 | 94 | s = search 95 | 96 | # Below methods "methods", "public", "own" can be chained when necessary. 97 | # That is, for listing all public methods that are not inherited, 98 | # use pdir(obj).public.own.methods 99 | # The order should not affect results. 100 | 101 | @property 102 | def properties(self) -> 'PrettyDir': 103 | """Returns all properties of the inspected object. 104 | 105 | Note that "properties" can mean "variables". 106 | """ 107 | return PrettyDir( 108 | self.obj, 109 | [ 110 | pattr 111 | for pattr in self.pattrs 112 | if category_match(pattr.category, AttrCategory.PROPERTY) 113 | ], 114 | ) 115 | 116 | @property 117 | def methods(self) -> 'PrettyDir': 118 | """Returns all methods of the inspected object. 119 | 120 | Note that "methods" can mean "functions" when inspecting a module. 121 | """ 122 | return PrettyDir( 123 | self.obj, 124 | [ 125 | pattr 126 | for pattr in self.pattrs 127 | if category_match(pattr.category, AttrCategory.FUNCTION) 128 | ], 129 | ) 130 | 131 | @property 132 | def public(self) -> 'PrettyDir': 133 | """Returns public attributes of the inspected object.""" 134 | return PrettyDir( 135 | self.obj, [pattr for pattr in self.pattrs if not pattr.name.startswith('_')] 136 | ) 137 | 138 | @property 139 | def own(self) -> 'PrettyDir': 140 | """Returns attributes that are not inhterited from parent classes. 141 | 142 | Now we only use a simple judgement, it is expected that many attributes 143 | not get returned, especially invoked on a module. 144 | 145 | For instance, there's no way to distinguish between properties that 146 | are initialized in instance class's __init__ and parent class's 147 | __init__(assuming super() is called). So we'll just leave it. 148 | """ 149 | return PrettyDir( 150 | self.obj, 151 | [ 152 | pattr 153 | for pattr in self.pattrs 154 | if pattr.name in type(self.obj).__dict__ 155 | or pattr.name in self.obj.__dict__ 156 | ], 157 | ) 158 | 159 | 160 | class PrettyAttribute: 161 | def __init__( 162 | self, name: str, category: Tuple[AttrCategory, ...], attr_obj: Any 163 | ) -> None: 164 | self.name = name 165 | self.category = category 166 | # Names are grouped by their category. When multiple categories exist, 167 | # pick the largest one which usually represents a more detailed 168 | # category. 169 | self.display_group = max(category) 170 | self.attr_obj = attr_obj 171 | self.doc = self.get_oneline_doc() 172 | # single category can not be a bare slot 173 | self.slotted = AttrCategory.SLOT in self.category 174 | 175 | def __repr__(self): 176 | return f'{self.name}: {self.category}' 177 | 178 | def get_oneline_doc(self) -> str: 179 | """ 180 | Doc doesn't necessarily mean doctring. It could be anything that 181 | should be put after the attr's name as an explanation. 182 | """ 183 | attr = self.attr_obj 184 | doc = get_first_sentence_of_docstring(attr) 185 | if self.display_group == AttrCategory.DESCRIPTOR: 186 | if isinstance(attr, property): 187 | doc_list = ['@property with getter'] 188 | if attr.fset: 189 | doc_list.append(SETTER) 190 | if attr.fdel: 191 | doc_list.append(DELETER) 192 | else: 193 | doc_list = ['class %s' % attr.__class__.__name__] 194 | if hasattr(attr, '__get__'): 195 | doc_list.append(GETTER) 196 | if hasattr(attr, '__set__'): 197 | doc_list.append(SETTER) 198 | if hasattr(attr, '__delete__'): 199 | doc_list.append(DELETER) 200 | doc_list[0] = ' '.join([doc_list[0], 'with', doc_list.pop(1)]) 201 | if doc: 202 | doc_list.append(doc) 203 | return ', '.join(doc_list) 204 | 205 | return doc 206 | -------------------------------------------------------------------------------- /tests/test_pdir_format.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import pytest 3 | 4 | 5 | def test_formatter_integrity(fake_tty): 6 | from pdir.attr_category import AttrCategory 7 | from pdir.format import _FORMATTER 8 | 9 | for ac in AttrCategory: 10 | assert ac in _FORMATTER 11 | 12 | 13 | def test_pdir_module(fake_tty): 14 | import pdir 15 | import m 16 | 17 | result = pdir(m) 18 | expected = '\n'.join( 19 | [ 20 | '\x1b[0;33mproperty:\x1b[0m', 21 | ( 22 | ' \x1b[0;36m__builtins__\x1b[0m\x1b[1;30m, ' 23 | '\x1b[0m\x1b[0;36ma\x1b[0m\x1b[1;30m, ' 24 | '\x1b[0m\x1b[0;36mb\x1b[0m' 25 | ), 26 | '\x1b[0;33mmodule attribute:\x1b[0m', 27 | ( 28 | ' \x1b[0;36m__cached__\x1b[0m\x1b[1;30m, ' 29 | '\x1b[0m\x1b[0;36m__file__\x1b[0m\x1b[1;30m, ' 30 | '\x1b[0m\x1b[0;36m__loader__\x1b[0m\x1b[1;30m, ' 31 | '\x1b[0m\x1b[0;36m__name__\x1b[0m\x1b[1;30m, ' 32 | '\x1b[0m\x1b[0;36m__package__\x1b[0m\x1b[1;30m, ' 33 | '\x1b[0m\x1b[0;36m__spec__\x1b[0m' 34 | ), 35 | '\x1b[0;33mspecial attribute:\x1b[0m', 36 | ' \x1b[0;36m__doc__\x1b[0m', 37 | '\x1b[0;33mclass:\x1b[0m', 38 | ' \x1b[0;36mOOO\x1b[0m\x1b[0;36m: ' 39 | '\x1b[0m\x1b[1;30mOOO today.\x1b[0m', 40 | '\x1b[0;33mfunction:\x1b[0m', 41 | ( 42 | ' \x1b[0;36mfunc\x1b[0m\x1b[0;36m: ' 43 | '\x1b[0m\x1b[1;30mThis is a function\x1b[0m' 44 | ), 45 | ] 46 | ) 47 | assert repr(result) == expected 48 | print(result) 49 | del m 50 | 51 | 52 | def test_pdir_object(fake_tty): 53 | import pdir 54 | 55 | class T: 56 | def what(self): 57 | """doc line""" 58 | pass 59 | 60 | result = pdir(T()) 61 | print(result) # TODO: add real test. 62 | 63 | 64 | def test_dir_without_argument(fake_tty): 65 | import pdir 66 | 67 | a = 1 68 | b = 2 69 | 70 | def whatever(): 71 | """One line doc.""" 72 | pass 73 | 74 | result = pdir() 75 | assert repr(result) == '\n'.join( 76 | [ 77 | '\x1b[0;33mproperty:\x1b[0m', 78 | ( 79 | ' \x1b[0;36ma\x1b[0m\x1b[1;30m, \x1b[0m\x1b[0;36mb\x1b[0m' 80 | '\x1b[1;30m, \x1b[0m\x1b[0;36mfake_tty\x1b[0m' 81 | ), 82 | '\x1b[0;33mclass:\x1b[0m', 83 | ( 84 | ' \x1b[0;36mpdir\x1b[0m\x1b[0;36m: \x1b[0m\x1b[1;30mClass ' 85 | 'that provides pretty dir and search API.\x1b[0m' 86 | ), 87 | '\x1b[0;33mfunction:\x1b[0m', 88 | ( 89 | ' \x1b[0;36mwhatever\x1b[0m\x1b[0;36m: ' 90 | '\x1b[0m\x1b[1;30mOne line doc.\x1b[0m' 91 | ), 92 | ] 93 | ) 94 | print(result) 95 | 96 | 97 | def test_slots(fake_tty): 98 | import pdir 99 | 100 | class A: 101 | __slots__ = ['__mul__', '__hash__', 'a', 'b'] 102 | 103 | a = A() 104 | result = pdir(a) 105 | 106 | special_attrs = ( 107 | ' \x1b[0;36m__class__\x1b[0m\x1b[1;30m, ' 108 | '\x1b[0m\x1b[0;36m__doc__\x1b[0m\x1b[1;30m, ' 109 | ) 110 | if sys.version_info >= (3, 13): 111 | special_attrs += '\x1b[0m\x1b[0;36m__firstlineno__\x1b[0m\x1b[1;30m, ' 112 | special_attrs += ( 113 | '\x1b[0m\x1b[0;36m__module__\x1b[0m\x1b[1;30m, ' 114 | '\x1b[0m\x1b[0;36m__slots__\x1b[0m' 115 | ) 116 | if sys.version_info >= (3, 13): 117 | special_attrs += '\x1b[1;30m, \x1b[0m\x1b[0;36m__static_attributes__\x1b[0m' 118 | 119 | expected = '\n'.join( 120 | [ 121 | '\x1b[0;33mspecial attribute:\x1b[0m', 122 | special_attrs, 123 | '\x1b[0;33mabstract class:\x1b[0m', 124 | ' \x1b[0;36m__subclasshook__\x1b[0m', 125 | '\x1b[0;33marithmetic:\x1b[0m', 126 | ' \x1b[0;36m__mul__\x1b[0m\x1b[0;35m(slotted)\x1b[0m', 127 | '\x1b[0;33mobject customization:\x1b[0m', 128 | ( 129 | ' \x1b[0;36m__format__\x1b[0m\x1b[1;30m, ' 130 | '\x1b[0m\x1b[0;36m__hash__\x1b[0m' 131 | '\x1b[0;35m(slotted)\x1b[0m\x1b[1;30m, ' 132 | '\x1b[0m\x1b[0;36m__init__\x1b[0m\x1b[1;30m, ' 133 | '\x1b[0m\x1b[0;36m__new__\x1b[0m\x1b[1;30m, ' 134 | '\x1b[0m\x1b[0;36m__repr__\x1b[0m\x1b[1;30m, ' 135 | '\x1b[0m\x1b[0;36m__sizeof__\x1b[0m\x1b[1;30m, ' 136 | '\x1b[0m\x1b[0;36m__str__\x1b[0m' 137 | ), 138 | '\x1b[0;33mrich comparison:\x1b[0m', 139 | ( 140 | ' \x1b[0;36m__eq__\x1b[0m\x1b[1;30m, ' 141 | '\x1b[0m\x1b[0;36m__ge__\x1b[0m\x1b[1;30m, ' 142 | '\x1b[0m\x1b[0;36m__gt__\x1b[0m\x1b[1;30m, ' 143 | '\x1b[0m\x1b[0;36m__le__\x1b[0m\x1b[1;30m, ' 144 | '\x1b[0m\x1b[0;36m__lt__\x1b[0m\x1b[1;30m, ' 145 | '\x1b[0m\x1b[0;36m__ne__\x1b[0m' 146 | ), 147 | '\x1b[0;33mattribute access:\x1b[0m', 148 | ( 149 | ' \x1b[0;36m__delattr__\x1b[0m\x1b[1;30m, ' 150 | '\x1b[0m\x1b[0;36m__dir__\x1b[0m\x1b[1;30m, ' 151 | '\x1b[0m\x1b[0;36m__getattribute__\x1b[0m\x1b[1;30m, ' 152 | '\x1b[0m\x1b[0;36m__setattr__\x1b[0m' 153 | ), 154 | '\x1b[0;33mclass customization:\x1b[0m', 155 | ' \x1b[0;36m__init_subclass__\x1b[0m', 156 | '\x1b[0;33mpickle:\x1b[0m', 157 | ( 158 | ( 159 | ' \x1b[0;36m__getstate__\x1b[0m\x1b[1;30m, ' 160 | '\x1b[0m\x1b[0;36m__reduce__\x1b[0m\x1b[1;30m, ' 161 | '\x1b[0m\x1b[0;36m__reduce_ex__\x1b[0m' 162 | ) 163 | if sys.version_info >= (3, 11) 164 | else ( 165 | ' \x1b[0;36m__reduce__\x1b[0m\x1b[1;30m, ' 166 | '\x1b[0m\x1b[0;36m__reduce_ex__\x1b[0m' 167 | ) 168 | ), 169 | '\x1b[0;33mdescriptor:\x1b[0m', 170 | ( 171 | ' \x1b[0;36ma\x1b[0m' 172 | '\x1b[0;35m(slotted)\x1b[0m\x1b[0;36m: ' 173 | '\x1b[0m\x1b[1;30mclass member_descriptor with ' 174 | 'getter, setter, deleter\x1b[0m' 175 | ), 176 | ( 177 | ' \x1b[0;36mb\x1b[0m' 178 | '\x1b[0;35m(slotted)\x1b[0m\x1b[0;36m: ' 179 | '\x1b[0m\x1b[1;30mclass member_descriptor with ' 180 | 'getter, setter, deleter\x1b[0m' 181 | ), 182 | ] 183 | ) 184 | assert repr(result) == expected 185 | 186 | 187 | @pytest.mark.parametrize( 188 | 'docstring, first_line', 189 | [ 190 | ('', ''), 191 | ('Foobar', 'Foobar'), 192 | ('Foobar.', 'Foobar.'), 193 | ('Foo\nbar', 'Foo bar'), 194 | ('Foo\nbar.', 'Foo bar.'), 195 | ('Return nothing.\nNo exceptions.', 'Return nothing.'), 196 | ('Return a.b as\nresult', 'Return a.b as result'), 197 | ], 198 | ) 199 | def test_get_first_line_of_docstring(docstring, first_line, fake_tty): 200 | from pdir._internal_utils import get_first_sentence_of_docstring 201 | 202 | CustomClass = type('CustomClass', (object,), {}) 203 | setattr(CustomClass, '__doc__', docstring) 204 | assert get_first_sentence_of_docstring(CustomClass) == first_line 205 | -------------------------------------------------------------------------------- /pdir/attr_category.py: -------------------------------------------------------------------------------- 1 | import collections.abc 2 | import functools 3 | import inspect 4 | from enum import IntEnum, auto 5 | 6 | from ._internal_utils import is_slotted_attr 7 | 8 | from typing import Any 9 | from typing import Tuple 10 | from typing import Union 11 | 12 | 13 | # Detailed category should have larger values than general category. 14 | class AttrCategory(IntEnum): 15 | # Slot category: orthogonal to all other categories. 16 | SLOT = auto() 17 | # Basic category. 18 | CLASS = auto() 19 | # Often represents the internal function that's invoked: add -> __add__. 20 | FUNCTION = auto() 21 | EXCEPTION = auto() 22 | PROPERTY = auto() 23 | 24 | # Detailed category. 25 | MODULE_ATTRIBUTE = auto() 26 | SPECIAL_ATTRIBUTE = auto() 27 | ABSTRACT_CLASS = auto() 28 | MAGIC = auto() 29 | ARITHMETIC = auto() 30 | ITER = auto() 31 | CONTEXT_MANAGER = auto() 32 | OBJECT_CUSTOMIZATION = auto() 33 | RICH_COMPARISON = auto() 34 | ATTRIBUTE_ACCESS = auto() 35 | # TODO: We should probably call it "user-defined descriptor", cause pretty much 36 | # everything inside a class is a "descriptor". 37 | DESCRIPTOR = auto() 38 | DESCRIPTOR_CLASS = auto() 39 | STATIC_METHOD = auto() 40 | CLASS_CUSTOMIZATION = auto() 41 | CONTAINER = auto() 42 | COROUTINE = auto() 43 | COPY = auto() 44 | PICKLE = auto() 45 | PATTERN_MATCHING = auto() 46 | TYPING = auto() 47 | DECORATOR = auto() 48 | BUFFER = auto() 49 | 50 | def __str__(self) -> str: 51 | """ 52 | e.g. RICH_COMPARISON -> rich comparison 53 | """ 54 | return " ".join(self.name.split("_")).lower() 55 | 56 | 57 | def _always_true(obj: type) -> bool: 58 | return True 59 | 60 | 61 | def category_match( 62 | pattr_category: Union[Tuple[AttrCategory, ...], AttrCategory], 63 | target_category: AttrCategory, 64 | ) -> bool: 65 | if pattr_category == target_category: 66 | return True 67 | return isinstance(pattr_category, tuple) and target_category in pattr_category 68 | 69 | 70 | # Names that belong to different categories in different conditions. 71 | ATTR_MAP_CONDITIONAL = { 72 | "__reversed__": lambda obj: (AttrCategory.ITER, AttrCategory.FUNCTION) 73 | if isinstance(obj, collections.abc.Iterator) 74 | else (AttrCategory.CONTAINER, AttrCategory.FUNCTION), 75 | "__iter__": lambda obj: (AttrCategory.ITER, AttrCategory.FUNCTION) 76 | if isinstance(obj, collections.abc.Iterator) 77 | else (AttrCategory.CONTAINER, AttrCategory.FUNCTION), 78 | "__name__": lambda obj: (AttrCategory.MODULE_ATTRIBUTE, AttrCategory.PROPERTY) 79 | if inspect.ismodule(obj) 80 | else (AttrCategory.SPECIAL_ATTRIBUTE, AttrCategory.PROPERTY), 81 | } 82 | 83 | ATTR_MAP = { 84 | "__doc__": (AttrCategory.SPECIAL_ATTRIBUTE, AttrCategory.PROPERTY), 85 | "__qualname__": (AttrCategory.SPECIAL_ATTRIBUTE, AttrCategory.PROPERTY), 86 | "__module__": (AttrCategory.SPECIAL_ATTRIBUTE, AttrCategory.PROPERTY), 87 | "__defaults__": (AttrCategory.SPECIAL_ATTRIBUTE, AttrCategory.PROPERTY), 88 | "__code__": (AttrCategory.SPECIAL_ATTRIBUTE, AttrCategory.PROPERTY), 89 | "__globals__": (AttrCategory.SPECIAL_ATTRIBUTE, AttrCategory.PROPERTY), 90 | "__dict__": (AttrCategory.SPECIAL_ATTRIBUTE, AttrCategory.PROPERTY), 91 | "__closure__": (AttrCategory.SPECIAL_ATTRIBUTE, AttrCategory.PROPERTY), 92 | "__annotations__": (AttrCategory.SPECIAL_ATTRIBUTE, AttrCategory.PROPERTY), 93 | "__kwdefaults__": (AttrCategory.SPECIAL_ATTRIBUTE, AttrCategory.PROPERTY), 94 | "__func__": (AttrCategory.SPECIAL_ATTRIBUTE, AttrCategory.PROPERTY), 95 | "__self__": (AttrCategory.SPECIAL_ATTRIBUTE, AttrCategory.PROPERTY), 96 | "__bases__": (AttrCategory.SPECIAL_ATTRIBUTE, AttrCategory.PROPERTY), 97 | "__class__": (AttrCategory.SPECIAL_ATTRIBUTE, AttrCategory.PROPERTY), 98 | "__objclass__": (AttrCategory.SPECIAL_ATTRIBUTE, AttrCategory.PROPERTY), 99 | "__slots__": (AttrCategory.SPECIAL_ATTRIBUTE, AttrCategory.PROPERTY), 100 | "__weakref__": (AttrCategory.SPECIAL_ATTRIBUTE, AttrCategory.PROPERTY), 101 | "__excepthook__": (AttrCategory.SPECIAL_ATTRIBUTE, AttrCategory.PROPERTY), 102 | "__mro__": (AttrCategory.SPECIAL_ATTRIBUTE, AttrCategory.PROPERTY), 103 | "__static_attributes__": (AttrCategory.SPECIAL_ATTRIBUTE, AttrCategory.PROPERTY), 104 | "__firstlineno__": (AttrCategory.SPECIAL_ATTRIBUTE, AttrCategory.PROPERTY), 105 | "__subclasses__": (AttrCategory.SPECIAL_ATTRIBUTE, AttrCategory.FUNCTION), 106 | "__next__": (AttrCategory.ITER, AttrCategory.FUNCTION), 107 | "__enter__": (AttrCategory.CONTEXT_MANAGER, AttrCategory.FUNCTION), 108 | "__exit__": (AttrCategory.CONTEXT_MANAGER, AttrCategory.FUNCTION), 109 | "__loader__": (AttrCategory.MODULE_ATTRIBUTE, AttrCategory.PROPERTY), 110 | "__package__": (AttrCategory.MODULE_ATTRIBUTE, AttrCategory.PROPERTY), 111 | "__spec__": (AttrCategory.MODULE_ATTRIBUTE, AttrCategory.PROPERTY), 112 | "__path__": (AttrCategory.MODULE_ATTRIBUTE, AttrCategory.PROPERTY), 113 | "__file__": (AttrCategory.MODULE_ATTRIBUTE, AttrCategory.PROPERTY), 114 | "__cached__": (AttrCategory.MODULE_ATTRIBUTE, AttrCategory.PROPERTY), 115 | "__all__": (AttrCategory.MODULE_ATTRIBUTE, AttrCategory.PROPERTY), 116 | "__abs__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 117 | "__add__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 118 | "__and__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 119 | "__complex__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 120 | "__divmod__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 121 | "__float__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 122 | "__floordiv__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 123 | "__iadd__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 124 | "__iand__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 125 | "__ifloordiv__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 126 | "__ilshift__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 127 | "__imatmul__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 128 | "__imod__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 129 | "__imul__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 130 | "__int__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 131 | "__invert__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 132 | "__ior__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 133 | "__ipow__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 134 | "__irshift__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 135 | "__isub__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 136 | "__itruediv__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 137 | "__ixor__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 138 | "__lshift__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 139 | "__matmul__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 140 | "__mod__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 141 | "__mul__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 142 | "__neg__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 143 | "__or__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 144 | "__pos__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 145 | "__pow__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 146 | "__radd__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 147 | "__rand__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 148 | "__rdivmod__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 149 | "__rfloordiv__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 150 | "__rlshift__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 151 | "__rmatmul__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 152 | "__rmod__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 153 | "__rmul__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 154 | "__ror__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 155 | "__round__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 156 | "__rpow__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 157 | "__rrshift__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 158 | "__rshift__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 159 | "__rsub__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 160 | "__rtruediv__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 161 | "__rxor__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 162 | "__sub__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 163 | "__truediv__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 164 | "__xor__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 165 | "__ceil__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 166 | "__floor__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 167 | "__trunc__": (AttrCategory.ARITHMETIC, AttrCategory.FUNCTION), 168 | "__init__": (AttrCategory.OBJECT_CUSTOMIZATION, AttrCategory.FUNCTION), 169 | "__post_init__": (AttrCategory.OBJECT_CUSTOMIZATION, AttrCategory.FUNCTION), 170 | "__new__": (AttrCategory.OBJECT_CUSTOMIZATION, AttrCategory.FUNCTION), 171 | "__del__": (AttrCategory.OBJECT_CUSTOMIZATION, AttrCategory.FUNCTION), 172 | "__repr__": (AttrCategory.OBJECT_CUSTOMIZATION, AttrCategory.FUNCTION), 173 | "__str__": (AttrCategory.OBJECT_CUSTOMIZATION, AttrCategory.FUNCTION), 174 | "__bytes__": (AttrCategory.OBJECT_CUSTOMIZATION, AttrCategory.FUNCTION), 175 | "__format__": (AttrCategory.OBJECT_CUSTOMIZATION, AttrCategory.FUNCTION), 176 | "__hash__": (AttrCategory.OBJECT_CUSTOMIZATION, AttrCategory.FUNCTION), 177 | "__bool__": (AttrCategory.OBJECT_CUSTOMIZATION, AttrCategory.FUNCTION), 178 | "__sizeof__": (AttrCategory.OBJECT_CUSTOMIZATION, AttrCategory.FUNCTION), 179 | "__lt__": (AttrCategory.RICH_COMPARISON, AttrCategory.FUNCTION), 180 | "__le__": (AttrCategory.RICH_COMPARISON, AttrCategory.FUNCTION), 181 | "__eq__": (AttrCategory.RICH_COMPARISON, AttrCategory.FUNCTION), 182 | "__ne__": (AttrCategory.RICH_COMPARISON, AttrCategory.FUNCTION), 183 | "__gt__": (AttrCategory.RICH_COMPARISON, AttrCategory.FUNCTION), 184 | "__ge__": (AttrCategory.RICH_COMPARISON, AttrCategory.FUNCTION), 185 | "__getattr__": (AttrCategory.ATTRIBUTE_ACCESS, AttrCategory.FUNCTION), 186 | "__getattribute__": (AttrCategory.ATTRIBUTE_ACCESS, AttrCategory.FUNCTION), 187 | "__setattr__": (AttrCategory.ATTRIBUTE_ACCESS, AttrCategory.FUNCTION), 188 | "__delattr__": (AttrCategory.ATTRIBUTE_ACCESS, AttrCategory.FUNCTION), 189 | "__dir__": (AttrCategory.ATTRIBUTE_ACCESS, AttrCategory.FUNCTION), 190 | "__get__": (AttrCategory.DESCRIPTOR_CLASS, AttrCategory.FUNCTION), 191 | "__set__": (AttrCategory.DESCRIPTOR_CLASS, AttrCategory.FUNCTION), 192 | "__delete__": (AttrCategory.DESCRIPTOR_CLASS, AttrCategory.FUNCTION), 193 | "__set_name__": (AttrCategory.DESCRIPTOR_CLASS, AttrCategory.FUNCTION), 194 | "__init_subclass__": (AttrCategory.CLASS_CUSTOMIZATION, AttrCategory.FUNCTION), 195 | "__prepare__": (AttrCategory.CLASS_CUSTOMIZATION, AttrCategory.FUNCTION), 196 | "__instancecheck__": (AttrCategory.CLASS_CUSTOMIZATION, AttrCategory.FUNCTION), 197 | "__subclasscheck__": (AttrCategory.CLASS_CUSTOMIZATION, AttrCategory.FUNCTION), 198 | "__subclasshook__": (AttrCategory.ABSTRACT_CLASS, AttrCategory.FUNCTION), 199 | "__isabstractmethod__": (AttrCategory.ABSTRACT_CLASS, AttrCategory.FUNCTION), 200 | "__abstractmethods__": (AttrCategory.ABSTRACT_CLASS, AttrCategory.PROPERTY), 201 | "__len__": (AttrCategory.CONTAINER, AttrCategory.FUNCTION), 202 | "__length_hint__": (AttrCategory.CONTAINER, AttrCategory.FUNCTION), 203 | "__getitem__": (AttrCategory.CONTAINER, AttrCategory.FUNCTION), 204 | "__missing__": (AttrCategory.CONTAINER, AttrCategory.FUNCTION), 205 | "__setitem__": (AttrCategory.CONTAINER, AttrCategory.FUNCTION), 206 | "__delitem__": (AttrCategory.CONTAINER, AttrCategory.FUNCTION), 207 | "__contains__": (AttrCategory.CONTAINER, AttrCategory.FUNCTION), 208 | "__await__": (AttrCategory.COROUTINE, AttrCategory.FUNCTION), 209 | "__aiter__": (AttrCategory.COROUTINE, AttrCategory.FUNCTION), 210 | "__anext__": (AttrCategory.COROUTINE, AttrCategory.FUNCTION), 211 | "__aenter__": (AttrCategory.COROUTINE, AttrCategory.FUNCTION), 212 | "__aexit__": (AttrCategory.COROUTINE, AttrCategory.FUNCTION), 213 | "__index__": (AttrCategory.MAGIC, AttrCategory.FUNCTION), 214 | "__call__": (AttrCategory.MAGIC, AttrCategory.FUNCTION), 215 | "__copy__": (AttrCategory.COPY, AttrCategory.FUNCTION), 216 | "__replace__": (AttrCategory.COPY, AttrCategory.FUNCTION), 217 | "__deepcopy__": (AttrCategory.COPY, AttrCategory.FUNCTION), 218 | "__getnewargs_ex__": (AttrCategory.PICKLE, AttrCategory.FUNCTION), 219 | "__getnewargs__": (AttrCategory.PICKLE, AttrCategory.FUNCTION), 220 | "__getstate__": (AttrCategory.PICKLE, AttrCategory.FUNCTION), 221 | "__setstate__": (AttrCategory.PICKLE, AttrCategory.FUNCTION), 222 | "__reduce__": (AttrCategory.PICKLE, AttrCategory.FUNCTION), 223 | "__reduce_ex__": (AttrCategory.PICKLE, AttrCategory.FUNCTION), 224 | "__match_args__": (AttrCategory.PATTERN_MATCHING, AttrCategory.PROPERTY), 225 | "__origin__": (AttrCategory.TYPING, AttrCategory.PROPERTY), 226 | "__args__": (AttrCategory.TYPING, AttrCategory.PROPERTY), 227 | "__parameters__": (AttrCategory.TYPING, AttrCategory.PROPERTY), 228 | "__class_getitem__": (AttrCategory.TYPING, AttrCategory.FUNCTION), 229 | "__final__": (AttrCategory.TYPING, AttrCategory.PROPERTY), 230 | "__orig_bases__": (AttrCategory.TYPING, AttrCategory.PROPERTY), 231 | "__type_params__": (AttrCategory.TYPING, AttrCategory.PROPERTY), 232 | "__wrapped__": (AttrCategory.DECORATOR, AttrCategory.PROPERTY), 233 | "__buffer__": (AttrCategory.BUFFER, AttrCategory.FUNCTION), 234 | "__release_buffer__": (AttrCategory.BUFFER, AttrCategory.FUNCTION), 235 | } 236 | 237 | 238 | def attr_category_postprocess(get_attr_category_func): 239 | """Unifies attr_category to a tuple, add AttrCategory.SLOT if needed.""" 240 | 241 | @functools.wraps(get_attr_category_func) 242 | def wrapped(name: str, attr: Any, obj: Any) -> Tuple[AttrCategory, ...]: 243 | category = get_attr_category_func(name, attr, obj) 244 | category = list(category) if isinstance(category, tuple) else [category] 245 | if is_slotted_attr(obj, name): 246 | # Refactoring all tuples to lists is not easy 247 | # and pleasant. Maybe do this in future if necessary 248 | category.append(AttrCategory.SLOT) 249 | return tuple(category) 250 | 251 | return wrapped 252 | 253 | 254 | @attr_category_postprocess 255 | def get_attr_category( 256 | name: str, attr: Any, obj: Any 257 | ) -> Union[Tuple[AttrCategory, ...], AttrCategory]: 258 | def is_descriptor(obj: Any) -> bool: 259 | return ( 260 | hasattr(obj, "__get__") 261 | or hasattr(obj, "__set__") 262 | or hasattr(obj, "__delete__") 263 | ) 264 | 265 | method_descriptor = type(list.append) 266 | 267 | if name in ATTR_MAP_CONDITIONAL: 268 | return ATTR_MAP_CONDITIONAL[name](obj) 269 | 270 | if name in ATTR_MAP: 271 | return ATTR_MAP[name] 272 | 273 | if inspect.isclass(attr): 274 | return ( 275 | AttrCategory.EXCEPTION 276 | if issubclass(attr, Exception) 277 | else AttrCategory.CLASS 278 | ) 279 | elif ( 280 | inspect.isfunction(attr) 281 | or inspect.ismethod(attr) 282 | or inspect.isbuiltin(attr) 283 | or isinstance(attr, method_descriptor) 284 | ): 285 | # Technically, method_descriptor is descriptor, but since they 286 | # act as functions, let's treat them as functions. 287 | return AttrCategory.FUNCTION 288 | elif isinstance(attr, staticmethod): 289 | return ( 290 | AttrCategory.DESCRIPTOR, 291 | AttrCategory.STATIC_METHOD, 292 | AttrCategory.FUNCTION, 293 | ) 294 | elif is_descriptor(attr): 295 | # Maybe add getsetdescriptor memberdescriptor in the future. 296 | return AttrCategory.DESCRIPTOR, AttrCategory.PROPERTY 297 | else: 298 | # attr that is neither function nor class is a normal variable, 299 | # and it's classified to property. 300 | return AttrCategory.PROPERTY 301 | -------------------------------------------------------------------------------- /annotate.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "path": "pdir/_internal_utils.py", 4 | "line": 9, 5 | "func_name": "get_attr_from_dict", 6 | "type_comments": [ 7 | "(type, str) -> Dict[int, str]", 8 | "(type, str) -> Dict[str, int]", 9 | "(type, str) -> property", 10 | "(type, str) -> wrapper_descriptor", 11 | "(type, str) -> int", 12 | "(type, str) -> getset_descriptor", 13 | "(type, str) -> function", 14 | "(type, str) -> member_descriptor", 15 | ], 16 | "samples": 116, 17 | }, 18 | { 19 | "path": "pdir/_internal_utils.py", 20 | "line": 25, 21 | "func_name": "is_slotted_attr", 22 | "type_comments": [ 23 | "(type, str) -> bool", 24 | "(object, str) -> bool", 25 | "(None, str) -> bool", 26 | "(test_filters.DerivedClass, str) -> bool", 27 | "(module, str) -> bool", 28 | "(test_pdir_format.T, str) -> bool", 29 | "(test_buggy_attrs.ClassWithUserDefinedDir, str) -> bool", 30 | "(test_buggy_attrs.T, str) -> bool", 31 | ], 32 | "samples": 136, 33 | }, 34 | { 35 | "path": "pdir/_internal_utils.py", 36 | "line": 32, 37 | "func_name": "_get_repl_type", 38 | "type_comments": ["() -> pdir.constants.ReplType"], 39 | "samples": 44, 40 | }, 41 | { 42 | "path": "pdir/_internal_utils.py", 43 | "line": 44, 44 | "func_name": "is_bpython", 45 | "type_comments": ["() -> bool"], 46 | "samples": 44, 47 | }, 48 | { 49 | "path": "pdir/_internal_utils.py", 50 | "line": 48, 51 | "func_name": "is_ptpython", 52 | "type_comments": ["() -> bool"], 53 | "samples": 15, 54 | }, 55 | { 56 | "path": "pdir/api.py", 57 | "line": 28, 58 | "func_name": "PrettyDir", 59 | "type_comments": ["() -> None"], 60 | "samples": 4, 61 | }, 62 | { 63 | "path": "pdir/api.py", 64 | "line": 31, 65 | "func_name": "PrettyDir.__init__", 66 | "type_comments": [ 67 | "(object, None) -> None", 68 | "(type, None) -> None", 69 | "(test_buggy_attrs.ClassWithUserDefinedDir, None) -> None", 70 | "(test_buggy_attrs.T, None) -> None", 71 | "(object, List[pdir.api.PrettyAttribute]) -> None", 72 | "(None, None) -> None", 73 | "(test_filters.DerivedClass, None) -> None", 74 | "(test_filters.DerivedClass, List[pdir.api.PrettyAttribute]) -> None", 75 | ], 76 | "samples": 53, 77 | }, 78 | { 79 | "path": "pdir/api.py", 80 | "line": 58, 81 | "func_name": "PrettyDir.__repr__", 82 | "type_comments": ["() -> str"], 83 | "samples": 15, 84 | }, 85 | { 86 | "path": "pdir/api.py", 87 | "line": 65, 88 | "func_name": "PrettyDir.__len__", 89 | "type_comments": ["() -> int"], 90 | "samples": 4, 91 | }, 92 | { 93 | "path": "pdir/api.py", 94 | "line": 68, 95 | "func_name": "PrettyDir.__getitem__", 96 | "type_comments": [ 97 | "(int) -> pyannotate_runtime.collect_types.NoReturnType", 98 | "(int) -> str", 99 | ], 100 | "samples": 14, 101 | }, 102 | { 103 | "path": "pdir/api.py", 104 | "line": 74, 105 | "func_name": "PrettyDir.search", 106 | "type_comments": ["(str, bool) -> pdir.api.PrettyDir"], 107 | "samples": 8, 108 | }, 109 | { 110 | "path": "pdir/api.py", 111 | "line": 103, 112 | "func_name": "properties", 113 | "type_comments": ["() -> pdir.api.PrettyDir"], 114 | "samples": 4, 115 | }, 116 | { 117 | "path": "pdir/api.py", 118 | "line": 118, 119 | "func_name": "methods", 120 | "type_comments": ["() -> pdir.api.PrettyDir"], 121 | "samples": 1, 122 | }, 123 | { 124 | "path": "pdir/api.py", 125 | "line": 133, 126 | "func_name": "public", 127 | "type_comments": ["() -> pdir.api.PrettyDir"], 128 | "samples": 4, 129 | }, 130 | { 131 | "path": "pdir/api.py", 132 | "line": 140, 133 | "func_name": "own", 134 | "type_comments": ["() -> pdir.api.PrettyDir"], 135 | "samples": 4, 136 | }, 137 | { 138 | "path": "pdir/api.py", 139 | "line": 162, 140 | "func_name": "PrettyAttribute", 141 | "type_comments": ["() -> None"], 142 | "samples": 4, 143 | }, 144 | { 145 | "path": "pdir/api.py", 146 | "line": 163, 147 | "func_name": "PrettyAttribute.__init__", 148 | "type_comments": [ 149 | "(str, Tuple[pdir.attr_category.AttrCategory], int) -> None", 150 | "(str, Tuple[pdir.attr_category.AttrCategory, pdir.attr_category.AttrCategory], property) -> None", 151 | "(str, Tuple[pdir.attr_category.AttrCategory], Dict[int, str]) -> None", 152 | "(str, Tuple[pdir.attr_category.AttrCategory], Dict[str, int]) -> None", 153 | "(str, Tuple[pdir.attr_category.AttrCategory, pdir.attr_category.AttrCategory], function) -> None", 154 | "(str, Tuple[pdir.attr_category.AttrCategory], function) -> None", 155 | "(str, Tuple[pdir.attr_category.AttrCategory, pdir.attr_category.AttrCategory], getset_descriptor) -> None", 156 | "(str, Tuple[pdir.attr_category.AttrCategory, pdir.attr_category.AttrCategory], member_descriptor) -> None", 157 | ], 158 | "samples": 136, 159 | }, 160 | { 161 | "path": "pdir/api.py", 162 | "line": 183, 163 | "func_name": "PrettyAttribute.get_oneline_doc", 164 | "type_comments": ["() -> str"], 165 | "samples": 136, 166 | }, 167 | { 168 | "path": "pdir/attr_category.py", 169 | "line": 46, 170 | "func_name": "AttrCategory.__str__", 171 | "type_comments": ["() -> str"], 172 | "samples": 30, 173 | }, 174 | { 175 | "path": "pdir/attr_category.py", 176 | "line": 57, 177 | "func_name": "category_match", 178 | "type_comments": [ 179 | "(Tuple[pdir.attr_category.AttrCategory], pdir.attr_category.AttrCategory) -> bool", 180 | "(Tuple[pdir.attr_category.AttrCategory, pdir.attr_category.AttrCategory, pdir.attr_category.AttrCategory], pdir.attr_category.AttrCategory) -> bool", 181 | "(Tuple[pdir.attr_category.AttrCategory, pdir.attr_category.AttrCategory], pdir.attr_category.AttrCategory) -> bool", 182 | ], 183 | "samples": 41, 184 | }, 185 | { 186 | "path": "pdir/attr_category.py", 187 | "line": 218, 188 | "func_name": "wrapped", 189 | "type_comments": [ 190 | "(str, property, type) -> Tuple[pdir.attr_category.AttrCategory, pdir.attr_category.AttrCategory]", 191 | "(str, function, type) -> Tuple[pdir.attr_category.AttrCategory, pdir.attr_category.AttrCategory]", 192 | "(str, getset_descriptor, type) -> Tuple[pdir.attr_category.AttrCategory, pdir.attr_category.AttrCategory]", 193 | "(str, member_descriptor, type) -> Tuple[pdir.attr_category.AttrCategory, pdir.attr_category.AttrCategory]", 194 | "(str, Dict[str, int], type) -> Tuple[pdir.attr_category.AttrCategory]", 195 | "(str, int, type) -> Tuple[pdir.attr_category.AttrCategory]", 196 | "(str, Dict[int, str], type) -> Tuple[pdir.attr_category.AttrCategory]", 197 | "(str, function, type) -> Tuple[pdir.attr_category.AttrCategory]", 198 | ], 199 | "samples": 136, 200 | }, 201 | { 202 | "path": "pdir/attr_category.py", 203 | "line": 233, 204 | "func_name": "get_attr_category", 205 | "type_comments": [ 206 | "(str, property, type) -> Tuple[pdir.attr_category.AttrCategory, pdir.attr_category.AttrCategory]", 207 | "(str, function, type) -> Tuple[pdir.attr_category.AttrCategory, pdir.attr_category.AttrCategory]", 208 | "(str, getset_descriptor, type) -> Tuple[pdir.attr_category.AttrCategory, pdir.attr_category.AttrCategory]", 209 | "(str, member_descriptor, type) -> Tuple[pdir.attr_category.AttrCategory, pdir.attr_category.AttrCategory]", 210 | "(str, Dict[str, int], type) -> pdir.attr_category.AttrCategory", 211 | "(str, int, type) -> pdir.attr_category.AttrCategory", 212 | "(str, Dict[int, str], type) -> pdir.attr_category.AttrCategory", 213 | "(str, function, type) -> pdir.attr_category.AttrCategory", 214 | ], 215 | "samples": 136, 216 | }, 217 | { 218 | "path": "pdir/attr_category.py", 219 | "line": 237, 220 | "func_name": "is_descriptor", 221 | "type_comments": [ 222 | "(property) -> bool", 223 | "(int) -> bool", 224 | "(member_descriptor) -> bool", 225 | "(test_buggy_attrs.D) -> bool", 226 | "(test_buggy_attrs.RevealAccess) -> bool", 227 | "(str) -> bool", 228 | "(Dict[int, str]) -> bool", 229 | "(Dict[str, int]) -> bool", 230 | ], 231 | "samples": 77, 232 | }, 233 | { 234 | "path": "pdir/color.py", 235 | "line": 4, 236 | "func_name": "_Color", 237 | "type_comments": ["() -> None"], 238 | "samples": 7, 239 | }, 240 | { 241 | "path": "pdir/color.py", 242 | "line": 5, 243 | "func_name": "_Color.__init__", 244 | "type_comments": ["(int, bool) -> None"], 245 | "samples": 35, 246 | }, 247 | { 248 | "path": "pdir/color.py", 249 | "line": 9, 250 | "func_name": "_Color.wrap_text", 251 | "type_comments": ["(str) -> str"], 252 | "samples": 44, 253 | }, 254 | { 255 | "path": "pdir/color.py", 256 | "line": 19, 257 | "func_name": "_Color.__eq__", 258 | "type_comments": ["(pdir.color._Color) -> bool"], 259 | "samples": 12, 260 | }, 261 | { 262 | "path": "pdir/configuration.py", 263 | "line": 26, 264 | "func_name": "Configuration", 265 | "type_comments": ["() -> None"], 266 | "samples": 7, 267 | }, 268 | { 269 | "path": "pdir/configuration.py", 270 | "line": 35, 271 | "func_name": "Configuration.__init__", 272 | "type_comments": [ 273 | "() -> pyannotate_runtime.collect_types.NoReturnType", 274 | "() -> None", 275 | ], 276 | "samples": 7, 277 | }, 278 | { 279 | "path": "pdir/configuration.py", 280 | "line": 39, 281 | "func_name": "uniform_color", 282 | "type_comments": ["() -> pdir.color._Color", "() -> None"], 283 | "samples": 7, 284 | }, 285 | { 286 | "path": "pdir/configuration.py", 287 | "line": 43, 288 | "func_name": "category_color", 289 | "type_comments": [ 290 | "() -> pdir.color._Color", 291 | "() -> pdir.color._Color", 292 | "() -> pdir.color._Color", 293 | ], 294 | "samples": 3, 295 | }, 296 | { 297 | "path": "pdir/configuration.py", 298 | "line": 47, 299 | "func_name": "attribute_color", 300 | "type_comments": [ 301 | "() -> pdir.color._Color", 302 | "() -> pdir.color._Color", 303 | "() -> pdir.color._Color", 304 | ], 305 | "samples": 3, 306 | }, 307 | { 308 | "path": "pdir/configuration.py", 309 | "line": 51, 310 | "func_name": "comma_color", 311 | "type_comments": [ 312 | "() -> pdir.color._Color", 313 | "() -> pdir.color._Color", 314 | "() -> pdir.color._Color", 315 | ], 316 | "samples": 3, 317 | }, 318 | { 319 | "path": "pdir/configuration.py", 320 | "line": 55, 321 | "func_name": "doc_color", 322 | "type_comments": [ 323 | "() -> pdir.color._Color", 324 | "() -> pdir.color._Color", 325 | "() -> pdir.color._Color", 326 | ], 327 | "samples": 3, 328 | }, 329 | { 330 | "path": "pdir/configuration.py", 331 | "line": 59, 332 | "func_name": "slot_color", 333 | "type_comments": [ 334 | "() -> pdir.color._Color", 335 | "() -> pdir.color._Color", 336 | "() -> pdir.color._Color", 337 | ], 338 | "samples": 3, 339 | }, 340 | { 341 | "path": "pdir/configuration.py", 342 | "line": 63, 343 | "func_name": "Configuration._load", 344 | "type_comments": [ 345 | "() -> pyannotate_runtime.collect_types.NoReturnType", 346 | "() -> None", 347 | ], 348 | "samples": 7, 349 | }, 350 | { 351 | "path": "pdir/constants.py", 352 | "line": 7, 353 | "func_name": "ReplType", 354 | "type_comments": ["() -> None"], 355 | "samples": 7, 356 | }, 357 | { 358 | "path": "pdir/constants.py", 359 | "line": 20, 360 | "func_name": "_ClassWithSlot", 361 | "type_comments": ["() -> None"], 362 | "samples": 7, 363 | }, 364 | { 365 | "path": "pdir/format.py", 366 | "line": 14, 367 | "func_name": "format_pattrs", 368 | "type_comments": ["(List) -> str", "(List[pdir.api.PrettyAttribute]) -> str"], 369 | "samples": 15, 370 | }, 371 | { 372 | "path": "pdir/format.py", 373 | "line": 32, 374 | "func_name": "_format_single_line", 375 | "type_comments": [ 376 | "(pdir.attr_category.AttrCategory, itertools._grouper) -> str" 377 | ], 378 | "samples": 28, 379 | }, 380 | { 381 | "path": "pdir/format.py", 382 | "line": 41, 383 | "func_name": "_format_multiline_with_doc", 384 | "type_comments": [ 385 | "(pdir.attr_category.AttrCategory, itertools._grouper) -> str" 386 | ], 387 | "samples": 8, 388 | }, 389 | { 390 | "path": "pdir/format.py", 391 | "line": 54, 392 | "func_name": "_format_descriptor", 393 | "type_comments": [ 394 | "(pdir.attr_category.AttrCategory, itertools._grouper) -> str" 395 | ], 396 | "samples": 1, 397 | }, 398 | { 399 | "path": "tests/m.py", 400 | "line": 5, 401 | "func_name": "OOO", 402 | "type_comments": ["() -> None"], 403 | "samples": 1, 404 | }, 405 | { 406 | "path": "tests/test_buggy_attrs.py", 407 | "line": 9, 408 | "func_name": "test_dataframe", 409 | "type_comments": ["() -> None"], 410 | "samples": 1, 411 | }, 412 | { 413 | "path": "tests/test_buggy_attrs.py", 414 | "line": 18, 415 | "func_name": "test_type", 416 | "type_comments": ["() -> None"], 417 | "samples": 1, 418 | }, 419 | { 420 | "path": "tests/test_buggy_attrs.py", 421 | "line": 26, 422 | "func_name": "test_list", 423 | "type_comments": ["() -> None"], 424 | "samples": 1, 425 | }, 426 | { 427 | "path": "tests/test_buggy_attrs.py", 428 | "line": 37, 429 | "func_name": "D.__init__", 430 | "type_comments": ["() -> None"], 431 | "samples": 1, 432 | }, 433 | { 434 | "path": "tests/test_buggy_attrs.py", 435 | "line": 53, 436 | "func_name": "RevealAccess.__init__", 437 | "type_comments": ["(int, str) -> None"], 438 | "samples": 1, 439 | }, 440 | { 441 | "path": "tests/test_buggy_attrs.py", 442 | "line": 57, 443 | "func_name": "RevealAccess.__get__", 444 | "type_comments": ["(None, type) -> int"], 445 | "samples": 1, 446 | }, 447 | { 448 | "path": "tests/test_buggy_attrs.py", 449 | "line": 69, 450 | "func_name": "test_descriptor", 451 | "type_comments": ["() -> None"], 452 | "samples": 1, 453 | }, 454 | { 455 | "path": "tests/test_buggy_attrs.py", 456 | "line": 70, 457 | "func_name": "T", 458 | "type_comments": ["() -> None"], 459 | "samples": 1, 460 | }, 461 | { 462 | "path": "tests/test_buggy_attrs.py", 463 | "line": 73, 464 | "func_name": "T.__init__", 465 | "type_comments": ["() -> None"], 466 | "samples": 1, 467 | }, 468 | { 469 | "path": "tests/test_buggy_attrs.py", 470 | "line": 105, 471 | "func_name": "test_override_dir", 472 | "type_comments": ["() -> None"], 473 | "samples": 1, 474 | }, 475 | { 476 | "path": "tests/test_buggy_attrs.py", 477 | "line": 108, 478 | "func_name": "ClassWithUserDefinedDir", 479 | "type_comments": ["() -> None"], 480 | "samples": 1, 481 | }, 482 | { 483 | "path": "tests/test_buggy_attrs.py", 484 | "line": 109, 485 | "func_name": "ClassWithUserDefinedDir.__dir__", 486 | "type_comments": ["() -> List[str]"], 487 | "samples": 4, 488 | }, 489 | { 490 | "path": "tests/test_container.py", 491 | "line": 4, 492 | "func_name": "test_acting_like_a_list", 493 | "type_comments": ["() -> None"], 494 | "samples": 1, 495 | }, 496 | { 497 | "path": "tests/test_container.py", 498 | "line": 17, 499 | "func_name": "test_acting_like_a_list_when_search", 500 | "type_comments": ["() -> None"], 501 | "samples": 1, 502 | }, 503 | { 504 | "path": "tests/test_container.py", 505 | "line": 28, 506 | "func_name": "test_attr_order", 507 | "type_comments": ["() -> None"], 508 | "samples": 1, 509 | }, 510 | { 511 | "path": "tests/test_filters.py", 512 | "line": 12, 513 | "func_name": "items_equal", 514 | "type_comments": ["(List[str], List[str]) -> bool"], 515 | "samples": 7, 516 | }, 517 | { 518 | "path": "tests/test_filters.py", 519 | "line": 45, 520 | "func_name": "test_properties", 521 | "type_comments": ["() -> None"], 522 | "samples": 1, 523 | }, 524 | { 525 | "path": "tests/test_filters.py", 526 | "line": 62, 527 | "func_name": "test_methods", 528 | "type_comments": ["() -> None"], 529 | "samples": 1, 530 | }, 531 | { 532 | "path": "tests/test_filters.py", 533 | "line": 115, 534 | "func_name": "test_public", 535 | "type_comments": ["() -> None"], 536 | "samples": 1, 537 | }, 538 | { 539 | "path": "tests/test_filters.py", 540 | "line": 129, 541 | "func_name": "test_own", 542 | "type_comments": ["() -> None"], 543 | "samples": 1, 544 | }, 545 | { 546 | "path": "tests/test_filters.py", 547 | "line": 144, 548 | "func_name": "test_chained_filters", 549 | "type_comments": ["() -> None"], 550 | "samples": 1, 551 | }, 552 | { 553 | "path": "tests/test_filters.py", 554 | "line": 155, 555 | "func_name": "test_order_of_chained_filters", 556 | "type_comments": ["() -> None"], 557 | "samples": 1, 558 | }, 559 | { 560 | "path": "tests/test_filters.py", 561 | "line": 174, 562 | "func_name": "test_filters_with_search", 563 | "type_comments": ["() -> None"], 564 | "samples": 1, 565 | }, 566 | { 567 | "path": "tests/test_pdir_format.py", 568 | "line": 7, 569 | "func_name": "test_pdir_module", 570 | "type_comments": ["() -> None"], 571 | "samples": 1, 572 | }, 573 | { 574 | "path": "tests/test_pdir_format.py", 575 | "line": 73, 576 | "func_name": "test_pdir_object", 577 | "type_comments": ["() -> None"], 578 | "samples": 1, 579 | }, 580 | { 581 | "path": "tests/test_pdir_format.py", 582 | "line": 74, 583 | "func_name": "T", 584 | "type_comments": ["() -> None"], 585 | "samples": 1, 586 | }, 587 | { 588 | "path": "tests/test_pdir_format.py", 589 | "line": 83, 590 | "func_name": "test_pdir_class", 591 | "type_comments": ["() -> None"], 592 | "samples": 1, 593 | }, 594 | { 595 | "path": "tests/test_pdir_format.py", 596 | "line": 90, 597 | "func_name": "T", 598 | "type_comments": ["() -> None"], 599 | "samples": 1, 600 | }, 601 | { 602 | "path": "tests/test_pdir_format.py", 603 | "line": 182, 604 | "func_name": "test_dir_without_argument", 605 | "type_comments": ["() -> None"], 606 | "samples": 1, 607 | }, 608 | { 609 | "path": "tests/test_pdir_format.py", 610 | "line": 203, 611 | "func_name": "test_slots", 612 | "type_comments": ["() -> None"], 613 | "samples": 1, 614 | }, 615 | { 616 | "path": "tests/test_pdir_format.py", 617 | "line": 204, 618 | "func_name": "A", 619 | "type_comments": ["() -> None"], 620 | "samples": 1, 621 | }, 622 | { 623 | "path": "tests/test_search.py", 624 | "line": 4, 625 | "func_name": "test_search_without_argument", 626 | "type_comments": ["() -> None"], 627 | "samples": 1, 628 | }, 629 | { 630 | "path": "tests/test_search.py", 631 | "line": 23, 632 | "func_name": "test_search_with_argument", 633 | "type_comments": ["() -> None"], 634 | "samples": 1, 635 | }, 636 | { 637 | "path": "tests/test_search.py", 638 | "line": 24, 639 | "func_name": "T", 640 | "type_comments": ["() -> None"], 641 | "samples": 1, 642 | }, 643 | { 644 | "path": "tests/test_slots.py", 645 | "line": 59, 646 | "func_name": "test_not_set", 647 | "type_comments": ["() -> None"], 648 | "samples": 1, 649 | }, 650 | { 651 | "path": "tests/test_slots.py", 652 | "line": 80, 653 | "func_name": "test_set_derive", 654 | "type_comments": ["() -> None"], 655 | "samples": 1, 656 | }, 657 | { 658 | "path": "tests/test_slots.py", 659 | "line": 95, 660 | "func_name": "test_set_base", 661 | "type_comments": ["() -> None"], 662 | "samples": 1, 663 | }, 664 | { 665 | "path": "tests/test_user_config.py", 666 | "line": 38, 667 | "func_name": "test_default_env_without_config", 668 | "type_comments": ["(str) -> None"], 669 | "samples": 1, 670 | }, 671 | { 672 | "path": "tests/test_user_config.py", 673 | "line": 44, 674 | "func_name": "test_set_env_without_config", 675 | "type_comments": ["(str) -> None"], 676 | "samples": 1, 677 | }, 678 | { 679 | "path": "tests/test_user_config.py", 680 | "line": 52, 681 | "func_name": "test_read_config", 682 | "type_comments": ["(str) -> None"], 683 | "samples": 1, 684 | }, 685 | { 686 | "path": "tests/test_user_config.py", 687 | "line": 63, 688 | "func_name": "test_read_config_from_custom_location", 689 | "type_comments": ["(str) -> None"], 690 | "samples": 1, 691 | }, 692 | { 693 | "path": "tests/test_user_config.py", 694 | "line": 74, 695 | "func_name": "test_uniform_color", 696 | "type_comments": ["(str) -> None"], 697 | "samples": 1, 698 | }, 699 | { 700 | "path": "tests/test_user_config.py", 701 | "line": 84, 702 | "func_name": "test_empty_config", 703 | "type_comments": ["(str) -> None"], 704 | "samples": 1, 705 | }, 706 | { 707 | "path": "tests/test_user_config.py", 708 | "line": 94, 709 | "func_name": "test_invalid_config_1", 710 | "type_comments": ["(str) -> None"], 711 | "samples": 1, 712 | }, 713 | { 714 | "path": "tests/test_user_config.py", 715 | "line": 102, 716 | "func_name": "test_invalid_config_2", 717 | "type_comments": ["(str) -> None"], 718 | "samples": 1, 719 | }, 720 | ] 721 | -------------------------------------------------------------------------------- /pdm.lock: -------------------------------------------------------------------------------- 1 | # This file is @generated by PDM. 2 | # It is not intended for manual editing. 3 | 4 | [metadata] 5 | groups = ["default", "dev"] 6 | strategy = [] 7 | lock_version = "4.5.0" 8 | content_hash = "sha256:3be35c8e7825a311f8d6f1f0c99a8a03839593430456b20810a7c5e9c50796cc" 9 | 10 | [[metadata.targets]] 11 | requires_python = ">=3.10" 12 | 13 | [[package]] 14 | name = "ansicon" 15 | version = "1.89.0" 16 | summary = "Python wrapper for loading Jason Hood's ANSICON" 17 | files = [ 18 | {file = "ansicon-1.89.0-py2.py3-none-any.whl", hash = "sha256:f1def52d17f65c2c9682cf8370c03f541f410c1752d6a14029f97318e4b9dfec"}, 19 | {file = "ansicon-1.89.0.tar.gz", hash = "sha256:e4d039def5768a47e4afec8e89e83ec3ae5a26bf00ad851f914d1240b444d2b1"}, 20 | ] 21 | 22 | [[package]] 23 | name = "appdirs" 24 | version = "1.4.4" 25 | summary = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." 26 | files = [ 27 | {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, 28 | {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, 29 | ] 30 | 31 | [[package]] 32 | name = "appnope" 33 | version = "0.1.4" 34 | requires_python = ">=3.6" 35 | summary = "Disable App Nap on macOS >= 10.9" 36 | files = [ 37 | {file = "appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c"}, 38 | {file = "appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee"}, 39 | ] 40 | 41 | [[package]] 42 | name = "attrs" 43 | version = "25.4.0" 44 | requires_python = ">=3.9" 45 | summary = "Classes Without Boilerplate" 46 | files = [ 47 | {file = "attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373"}, 48 | {file = "attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11"}, 49 | ] 50 | 51 | [[package]] 52 | name = "backcall" 53 | version = "0.2.0" 54 | summary = "Specifications for callback functions passed in to an API" 55 | files = [ 56 | {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, 57 | {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, 58 | ] 59 | 60 | [[package]] 61 | name = "backports-tarfile" 62 | version = "1.2.0" 63 | requires_python = ">=3.8" 64 | summary = "Backport of CPython tarfile module" 65 | files = [ 66 | {file = "backports.tarfile-1.2.0-py3-none-any.whl", hash = "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34"}, 67 | {file = "backports_tarfile-1.2.0.tar.gz", hash = "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991"}, 68 | ] 69 | 70 | [[package]] 71 | name = "blessed" 72 | version = "1.25.0" 73 | requires_python = ">=3.7" 74 | summary = "Easy, practical library for making terminal apps, by providing an elegant, well-documented interface to Colors, Keyboard input, and screen Positioning capabilities." 75 | dependencies = [ 76 | "jinxed>=1.1.0; platform_system == \"Windows\"", 77 | "wcwidth>=0.1.4", 78 | ] 79 | files = [ 80 | {file = "blessed-1.25.0-py3-none-any.whl", hash = "sha256:e52b9f778b9e10c30b3f17f6b5f5d2208d1e9b53b270f1d94fc61a243fc4708f"}, 81 | {file = "blessed-1.25.0.tar.gz", hash = "sha256:606aebfea69f85915c7ca6a96eb028e0031d30feccc5688e13fd5cec8277b28d"}, 82 | ] 83 | 84 | [[package]] 85 | name = "bpython" 86 | version = "0.26" 87 | requires_python = ">=3.9" 88 | summary = "A fancy curses interface to the Python interactive interpreter" 89 | dependencies = [ 90 | "curtsies>=0.4.0", 91 | "cwcwidth", 92 | "greenlet", 93 | "pygments", 94 | "pyxdg", 95 | "requests", 96 | "typing-extensions; python_version < \"3.11\"", 97 | ] 98 | files = [ 99 | {file = "bpython-0.26-py3-none-any.whl", hash = "sha256:91bdbbe667078677dc6b236493fc03e47a04cd099630a32ca3f72d6d49b71e20"}, 100 | {file = "bpython-0.26.tar.gz", hash = "sha256:f79083e1e3723be9b49c9994ad1dd3a19ccb4d0d4f9a6f5b3a73bef8bc327433"}, 101 | ] 102 | 103 | [[package]] 104 | name = "cachetools" 105 | version = "6.2.2" 106 | requires_python = ">=3.9" 107 | summary = "Extensible memoizing collections and decorators" 108 | files = [ 109 | {file = "cachetools-6.2.2-py3-none-any.whl", hash = "sha256:6c09c98183bf58560c97b2abfcedcbaf6a896a490f534b031b661d3723b45ace"}, 110 | {file = "cachetools-6.2.2.tar.gz", hash = "sha256:8e6d266b25e539df852251cfd6f990b4bc3a141db73b939058d809ebd2590fc6"}, 111 | ] 112 | 113 | [[package]] 114 | name = "certifi" 115 | version = "2025.11.12" 116 | requires_python = ">=3.7" 117 | summary = "Python package for providing Mozilla's CA Bundle." 118 | files = [ 119 | {file = "certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b"}, 120 | {file = "certifi-2025.11.12.tar.gz", hash = "sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316"}, 121 | ] 122 | 123 | [[package]] 124 | name = "cffi" 125 | version = "2.0.0" 126 | requires_python = ">=3.9" 127 | summary = "Foreign Function Interface for Python calling C code." 128 | dependencies = [ 129 | "pycparser; implementation_name != \"PyPy\"", 130 | ] 131 | files = [ 132 | {file = "cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44"}, 133 | {file = "cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49"}, 134 | {file = "cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c"}, 135 | {file = "cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb"}, 136 | {file = "cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0"}, 137 | {file = "cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4"}, 138 | {file = "cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453"}, 139 | {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495"}, 140 | {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5"}, 141 | {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb"}, 142 | {file = "cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a"}, 143 | {file = "cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739"}, 144 | {file = "cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe"}, 145 | {file = "cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c"}, 146 | {file = "cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92"}, 147 | {file = "cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93"}, 148 | {file = "cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5"}, 149 | {file = "cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664"}, 150 | {file = "cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26"}, 151 | {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9"}, 152 | {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414"}, 153 | {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743"}, 154 | {file = "cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5"}, 155 | {file = "cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5"}, 156 | {file = "cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d"}, 157 | {file = "cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d"}, 158 | {file = "cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c"}, 159 | {file = "cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe"}, 160 | {file = "cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062"}, 161 | {file = "cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e"}, 162 | {file = "cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037"}, 163 | {file = "cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba"}, 164 | {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94"}, 165 | {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187"}, 166 | {file = "cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18"}, 167 | {file = "cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5"}, 168 | {file = "cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6"}, 169 | {file = "cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb"}, 170 | {file = "cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca"}, 171 | {file = "cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b"}, 172 | {file = "cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b"}, 173 | {file = "cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2"}, 174 | {file = "cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3"}, 175 | {file = "cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26"}, 176 | {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c"}, 177 | {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b"}, 178 | {file = "cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27"}, 179 | {file = "cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75"}, 180 | {file = "cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91"}, 181 | {file = "cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5"}, 182 | {file = "cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13"}, 183 | {file = "cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b"}, 184 | {file = "cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c"}, 185 | {file = "cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef"}, 186 | {file = "cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775"}, 187 | {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205"}, 188 | {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1"}, 189 | {file = "cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f"}, 190 | {file = "cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25"}, 191 | {file = "cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad"}, 192 | {file = "cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9"}, 193 | {file = "cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d"}, 194 | {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c"}, 195 | {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8"}, 196 | {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc"}, 197 | {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592"}, 198 | {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512"}, 199 | {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4"}, 200 | {file = "cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e"}, 201 | {file = "cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6"}, 202 | {file = "cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9"}, 203 | {file = "cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529"}, 204 | ] 205 | 206 | [[package]] 207 | name = "chardet" 208 | version = "5.2.0" 209 | requires_python = ">=3.7" 210 | summary = "Universal encoding detector for Python 3" 211 | files = [ 212 | {file = "chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"}, 213 | {file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"}, 214 | ] 215 | 216 | [[package]] 217 | name = "charset-normalizer" 218 | version = "3.4.4" 219 | requires_python = ">=3.7" 220 | summary = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." 221 | files = [ 222 | {file = "charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d"}, 223 | {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8"}, 224 | {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad"}, 225 | {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8"}, 226 | {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d"}, 227 | {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313"}, 228 | {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e"}, 229 | {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93"}, 230 | {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0"}, 231 | {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84"}, 232 | {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e"}, 233 | {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db"}, 234 | {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6"}, 235 | {file = "charset_normalizer-3.4.4-cp310-cp310-win32.whl", hash = "sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f"}, 236 | {file = "charset_normalizer-3.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d"}, 237 | {file = "charset_normalizer-3.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69"}, 238 | {file = "charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8"}, 239 | {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0"}, 240 | {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3"}, 241 | {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc"}, 242 | {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897"}, 243 | {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381"}, 244 | {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815"}, 245 | {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0"}, 246 | {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161"}, 247 | {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4"}, 248 | {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89"}, 249 | {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569"}, 250 | {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224"}, 251 | {file = "charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a"}, 252 | {file = "charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016"}, 253 | {file = "charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1"}, 254 | {file = "charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394"}, 255 | {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25"}, 256 | {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef"}, 257 | {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d"}, 258 | {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8"}, 259 | {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86"}, 260 | {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a"}, 261 | {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f"}, 262 | {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc"}, 263 | {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf"}, 264 | {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15"}, 265 | {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9"}, 266 | {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0"}, 267 | {file = "charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26"}, 268 | {file = "charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525"}, 269 | {file = "charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3"}, 270 | {file = "charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794"}, 271 | {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed"}, 272 | {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72"}, 273 | {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328"}, 274 | {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede"}, 275 | {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894"}, 276 | {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1"}, 277 | {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490"}, 278 | {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44"}, 279 | {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133"}, 280 | {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3"}, 281 | {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e"}, 282 | {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc"}, 283 | {file = "charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac"}, 284 | {file = "charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14"}, 285 | {file = "charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2"}, 286 | {file = "charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd"}, 287 | {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb"}, 288 | {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e"}, 289 | {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14"}, 290 | {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191"}, 291 | {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838"}, 292 | {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6"}, 293 | {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e"}, 294 | {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c"}, 295 | {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090"}, 296 | {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152"}, 297 | {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828"}, 298 | {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec"}, 299 | {file = "charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9"}, 300 | {file = "charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c"}, 301 | {file = "charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2"}, 302 | {file = "charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f"}, 303 | {file = "charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a"}, 304 | ] 305 | 306 | [[package]] 307 | name = "colorama" 308 | version = "0.4.6" 309 | requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" 310 | summary = "Cross-platform colored terminal text." 311 | files = [ 312 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, 313 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, 314 | ] 315 | 316 | [[package]] 317 | name = "cryptography" 318 | version = "46.0.3" 319 | requires_python = "!=3.9.0,!=3.9.1,>=3.8" 320 | summary = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." 321 | dependencies = [ 322 | "cffi>=1.14; python_full_version == \"3.8.*\" and platform_python_implementation != \"PyPy\"", 323 | "cffi>=2.0.0; python_full_version >= \"3.9\" and platform_python_implementation != \"PyPy\"", 324 | "typing-extensions>=4.13.2; python_full_version < \"3.11\"", 325 | ] 326 | files = [ 327 | {file = "cryptography-46.0.3-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:109d4ddfadf17e8e7779c39f9b18111a09efb969a301a31e987416a0191ed93a"}, 328 | {file = "cryptography-46.0.3-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:09859af8466b69bc3c27bdf4f5d84a665e0f7ab5088412e9e2ec49758eca5cbc"}, 329 | {file = "cryptography-46.0.3-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:01ca9ff2885f3acc98c29f1860552e37f6d7c7d013d7334ff2a9de43a449315d"}, 330 | {file = "cryptography-46.0.3-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6eae65d4c3d33da080cff9c4ab1f711b15c1d9760809dad6ea763f3812d254cb"}, 331 | {file = "cryptography-46.0.3-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5bf0ed4490068a2e72ac03d786693adeb909981cc596425d09032d372bcc849"}, 332 | {file = "cryptography-46.0.3-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:5ecfccd2329e37e9b7112a888e76d9feca2347f12f37918facbb893d7bb88ee8"}, 333 | {file = "cryptography-46.0.3-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a2c0cd47381a3229c403062f764160d57d4d175e022c1df84e168c6251a22eec"}, 334 | {file = "cryptography-46.0.3-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:549e234ff32571b1f4076ac269fcce7a808d3bf98b76c8dd560e42dbc66d7d91"}, 335 | {file = "cryptography-46.0.3-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:c0a7bb1a68a5d3471880e264621346c48665b3bf1c3759d682fc0864c540bd9e"}, 336 | {file = "cryptography-46.0.3-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:10b01676fc208c3e6feeb25a8b83d81767e8059e1fe86e1dc62d10a3018fa926"}, 337 | {file = "cryptography-46.0.3-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0abf1ffd6e57c67e92af68330d05760b7b7efb243aab8377e583284dbab72c71"}, 338 | {file = "cryptography-46.0.3-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a04bee9ab6a4da801eb9b51f1b708a1b5b5c9eb48c03f74198464c66f0d344ac"}, 339 | {file = "cryptography-46.0.3-cp311-abi3-win32.whl", hash = "sha256:f260d0d41e9b4da1ed1e0f1ce571f97fe370b152ab18778e9e8f67d6af432018"}, 340 | {file = "cryptography-46.0.3-cp311-abi3-win_amd64.whl", hash = "sha256:a9a3008438615669153eb86b26b61e09993921ebdd75385ddd748702c5adfddb"}, 341 | {file = "cryptography-46.0.3-cp311-abi3-win_arm64.whl", hash = "sha256:5d7f93296ee28f68447397bf5198428c9aeeab45705a55d53a6343455dcb2c3c"}, 342 | {file = "cryptography-46.0.3-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:00a5e7e87938e5ff9ff5447ab086a5706a957137e6e433841e9d24f38a065217"}, 343 | {file = "cryptography-46.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c8daeb2d2174beb4575b77482320303f3d39b8e81153da4f0fb08eb5fe86a6c5"}, 344 | {file = "cryptography-46.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:39b6755623145ad5eff1dab323f4eae2a32a77a7abef2c5089a04a3d04366715"}, 345 | {file = "cryptography-46.0.3-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:db391fa7c66df6762ee3f00c95a89e6d428f4d60e7abc8328f4fe155b5ac6e54"}, 346 | {file = "cryptography-46.0.3-cp314-cp314t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:78a97cf6a8839a48c49271cdcbd5cf37ca2c1d6b7fdd86cc864f302b5e9bf459"}, 347 | {file = "cryptography-46.0.3-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:dfb781ff7eaa91a6f7fd41776ec37c5853c795d3b358d4896fdbb5df168af422"}, 348 | {file = "cryptography-46.0.3-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:6f61efb26e76c45c4a227835ddeae96d83624fb0d29eb5df5b96e14ed1a0afb7"}, 349 | {file = "cryptography-46.0.3-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:23b1a8f26e43f47ceb6d6a43115f33a5a37d57df4ea0ca295b780ae8546e8044"}, 350 | {file = "cryptography-46.0.3-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:b419ae593c86b87014b9be7396b385491ad7f320bde96826d0dd174459e54665"}, 351 | {file = "cryptography-46.0.3-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:50fc3343ac490c6b08c0cf0d704e881d0d660be923fd3076db3e932007e726e3"}, 352 | {file = "cryptography-46.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:22d7e97932f511d6b0b04f2bfd818d73dcd5928db509460aaf48384778eb6d20"}, 353 | {file = "cryptography-46.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d55f3dffadd674514ad19451161118fd010988540cee43d8bc20675e775925de"}, 354 | {file = "cryptography-46.0.3-cp314-cp314t-win32.whl", hash = "sha256:8a6e050cb6164d3f830453754094c086ff2d0b2f3a897a1d9820f6139a1f0914"}, 355 | {file = "cryptography-46.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:760f83faa07f8b64e9c33fc963d790a2edb24efb479e3520c14a45741cd9b2db"}, 356 | {file = "cryptography-46.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:516ea134e703e9fe26bcd1277a4b59ad30586ea90c365a87781d7887a646fe21"}, 357 | {file = "cryptography-46.0.3-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:cb3d760a6117f621261d662bccc8ef5bc32ca673e037c83fbe565324f5c46936"}, 358 | {file = "cryptography-46.0.3-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4b7387121ac7d15e550f5cb4a43aef2559ed759c35df7336c402bb8275ac9683"}, 359 | {file = "cryptography-46.0.3-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:15ab9b093e8f09daab0f2159bb7e47532596075139dd74365da52ecc9cb46c5d"}, 360 | {file = "cryptography-46.0.3-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:46acf53b40ea38f9c6c229599a4a13f0d46a6c3fa9ef19fc1a124d62e338dfa0"}, 361 | {file = "cryptography-46.0.3-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10ca84c4668d066a9878890047f03546f3ae0a6b8b39b697457b7757aaf18dbc"}, 362 | {file = "cryptography-46.0.3-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:36e627112085bb3b81b19fed209c05ce2a52ee8b15d161b7c643a7d5a88491f3"}, 363 | {file = "cryptography-46.0.3-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1000713389b75c449a6e979ffc7dcc8ac90b437048766cef052d4d30b8220971"}, 364 | {file = "cryptography-46.0.3-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:b02cf04496f6576afffef5ddd04a0cb7d49cf6be16a9059d793a30b035f6b6ac"}, 365 | {file = "cryptography-46.0.3-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:71e842ec9bc7abf543b47cf86b9a743baa95f4677d22baa4c7d5c69e49e9bc04"}, 366 | {file = "cryptography-46.0.3-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:402b58fc32614f00980b66d6e56a5b4118e6cb362ae8f3fda141ba4689bd4506"}, 367 | {file = "cryptography-46.0.3-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ef639cb3372f69ec44915fafcd6698b6cc78fbe0c2ea41be867f6ed612811963"}, 368 | {file = "cryptography-46.0.3-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3b51b8ca4f1c6453d8829e1eb7299499ca7f313900dd4d89a24b8b87c0a780d4"}, 369 | {file = "cryptography-46.0.3-cp38-abi3-win32.whl", hash = "sha256:6276eb85ef938dc035d59b87c8a7dc559a232f954962520137529d77b18ff1df"}, 370 | {file = "cryptography-46.0.3-cp38-abi3-win_amd64.whl", hash = "sha256:416260257577718c05135c55958b674000baef9a1c7d9e8f306ec60d71db850f"}, 371 | {file = "cryptography-46.0.3-cp38-abi3-win_arm64.whl", hash = "sha256:d89c3468de4cdc4f08a57e214384d0471911a3830fcdaf7a8cc587e42a866372"}, 372 | {file = "cryptography-46.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a23582810fedb8c0bc47524558fb6c56aac3fc252cb306072fd2815da2a47c32"}, 373 | {file = "cryptography-46.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e7aec276d68421f9574040c26e2a7c3771060bc0cff408bae1dcb19d3ab1e63c"}, 374 | {file = "cryptography-46.0.3-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7ce938a99998ed3c8aa7e7272dca1a610401ede816d36d0693907d863b10d9ea"}, 375 | {file = "cryptography-46.0.3-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:191bb60a7be5e6f54e30ba16fdfae78ad3a342a0599eb4193ba88e3f3d6e185b"}, 376 | {file = "cryptography-46.0.3-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c70cc23f12726be8f8bc72e41d5065d77e4515efae3690326764ea1b07845cfb"}, 377 | {file = "cryptography-46.0.3-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:9394673a9f4de09e28b5356e7fff97d778f8abad85c9d5ac4a4b7e25a0de7717"}, 378 | {file = "cryptography-46.0.3-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:94cd0549accc38d1494e1f8de71eca837d0509d0d44bf11d158524b0e12cebf9"}, 379 | {file = "cryptography-46.0.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:6b5063083824e5509fdba180721d55909ffacccc8adbec85268b48439423d78c"}, 380 | {file = "cryptography-46.0.3.tar.gz", hash = "sha256:a8b17438104fed022ce745b362294d9ce35b4c2e45c1d958ad4a4b019285f4a1"}, 381 | ] 382 | 383 | [[package]] 384 | name = "curtsies" 385 | version = "0.4.3" 386 | requires_python = ">=3.10" 387 | summary = "Curses-like terminal wrapper, with colored strings!" 388 | dependencies = [ 389 | "blessed>=1.5", 390 | "cwcwidth", 391 | ] 392 | files = [ 393 | {file = "curtsies-0.4.3-py3-none-any.whl", hash = "sha256:65a1b4d6ff887bd9b0f0836cc6dc68c3a2c65c57f51a62f0ee5df408edee1a99"}, 394 | {file = "curtsies-0.4.3.tar.gz", hash = "sha256:102a0ffbf952124f1be222fd6989da4ec7cce04e49f613009e5f54ad37618825"}, 395 | ] 396 | 397 | [[package]] 398 | name = "cwcwidth" 399 | version = "0.1.11" 400 | requires_python = ">=3.10" 401 | summary = "Python bindings for wc(s)width" 402 | files = [ 403 | {file = "cwcwidth-0.1.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7bf37420fc4894ff21eedb069cd75f38a8f330a5c79501160a7bb21c79163ad9"}, 404 | {file = "cwcwidth-0.1.11-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fd61620714344d529250a6d7b5896f51261b65526c84299691cf062cbf4666ce"}, 405 | {file = "cwcwidth-0.1.11-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ea4a44ce6101a9f47491dae881cb97a31930e9d7ebd77854a2b7ee79674b3859"}, 406 | {file = "cwcwidth-0.1.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d72185b2c20d85b90ef22eeec650c9e48a0652f8787811b806f2d54f1b2bbe39"}, 407 | {file = "cwcwidth-0.1.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e8e32df4db4a6c15770b885795f8e1bb709fc272337d4c0567691130f66ab83a"}, 408 | {file = "cwcwidth-0.1.11-cp310-cp310-win32.whl", hash = "sha256:0be3ab3e9b0b7691dce2c7099b038319cb5bc1384f53ec4c7e84371a92670db4"}, 409 | {file = "cwcwidth-0.1.11-cp310-cp310-win_amd64.whl", hash = "sha256:bdc00d41885d9ec4ef201e7f1c09225f895b63dde2b913bb5a62e9ce805ecf31"}, 410 | {file = "cwcwidth-0.1.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a920e4a8734ee3da9088c9ef57ba38070c51d06131d23650fd02278b2229d72b"}, 411 | {file = "cwcwidth-0.1.11-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0cf261cbf7cbb80f5b9382872bcab2d601c9c0ef3781933945f18d717635f67f"}, 412 | {file = "cwcwidth-0.1.11-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:95cb5d3035601a2224149081d9e42e86e1740aef78ad7d82e6c7eb84e4ac6273"}, 413 | {file = "cwcwidth-0.1.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:57a11d509afeac7f3b565948e9c760caf81d2c158d8fa8d3863b0a344871cd20"}, 414 | {file = "cwcwidth-0.1.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:47827c8d13b24102c3616fb920828330a732e6b3e80dc9d67f3cc2148a7b7e72"}, 415 | {file = "cwcwidth-0.1.11-cp311-cp311-win32.whl", hash = "sha256:11ad90f3d75b99836aae45d509f0ae788379ef0c95c934f6d1941c59c93d9fbf"}, 416 | {file = "cwcwidth-0.1.11-cp311-cp311-win_amd64.whl", hash = "sha256:6c2c7d1d02b6a5d77f049a5e0ebba7917471f74c05c482e8f484194ce3c327b7"}, 417 | {file = "cwcwidth-0.1.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:31684dacd89476ebcc19e3b7317626fd9c5c04511a77d4a03df5f95f39a1daee"}, 418 | {file = "cwcwidth-0.1.11-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0677707bd62906808e1d0a28c53eeeedaf9402d207c8f52688d2be001021c492"}, 419 | {file = "cwcwidth-0.1.11-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39acf51e7295e76e2397bc36f005e0fbbcca7c6863fd1d3b83f6730265e93a42"}, 420 | {file = "cwcwidth-0.1.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4367d307debcebf5253e64953675d66aa2086cf4eb579b29d72608fa99d63460"}, 421 | {file = "cwcwidth-0.1.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ac3a61d915edd746a2052554c42e3d8a4b3089622b1c0bf15dc7ecbf42594d3c"}, 422 | {file = "cwcwidth-0.1.11-cp312-cp312-win32.whl", hash = "sha256:e2ee1b8345522430ddb9c5a854610f99cfe53760aa22cefb85a9ddc4fecd3640"}, 423 | {file = "cwcwidth-0.1.11-cp312-cp312-win_amd64.whl", hash = "sha256:16d26ca8da308edc0683d09e85b134b3753baad14052dd147b31c63bca379118"}, 424 | {file = "cwcwidth-0.1.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cb220310460009a6f5655bb311be9cfe44762a5f7e9a6ea7fe423bd4e3763406"}, 425 | {file = "cwcwidth-0.1.11-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6002380693fd55c0ba6d8f6dca4af9f270aa9dc8f8f00041e015099e80100f8a"}, 426 | {file = "cwcwidth-0.1.11-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:40b77971fe7471d84ebce8c393efb456435091ba6a5f9e2a381a9c169bd13a51"}, 427 | {file = "cwcwidth-0.1.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b14b4f9d947f2ac6f1993c1ac447962d8e8c54d7479ba2d149cbc54ba45f17cb"}, 428 | {file = "cwcwidth-0.1.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f898e6f3b07be5862185a40bd75a3eadaefa4bfd4e12f583b975cd4552b86435"}, 429 | {file = "cwcwidth-0.1.11-cp313-cp313-win32.whl", hash = "sha256:9d30cf5b19e00198dc060d989b8295ece94b67df6719045361f8c8ef93cdd60e"}, 430 | {file = "cwcwidth-0.1.11-cp313-cp313-win_amd64.whl", hash = "sha256:6b448e65ba72c755a258db08b6424ea58f2593fd8046240e0270d37a41f8137a"}, 431 | {file = "cwcwidth-0.1.11-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c65d5c1799e9fa68f6a5e1b164d597cdaf9c00e31230728e1ec07e44565a2ed5"}, 432 | {file = "cwcwidth-0.1.11-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4c5bfcf94647861bae11902b54c6114fa07e4a503252866fd1f4d00411469d71"}, 433 | {file = "cwcwidth-0.1.11-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a06f859c3716ced0572b869adc40c04c2c42326f00cda5e21237c7597f33bdda"}, 434 | {file = "cwcwidth-0.1.11-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9cec169c878817869d1d9b32a0db42771bd5234c177582dfb2bf0632fcb6d140"}, 435 | {file = "cwcwidth-0.1.11-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:01398db710dadece862038f1327bea01a28647e9f4695dbc10423e8ce125c9b9"}, 436 | {file = "cwcwidth-0.1.11-cp314-cp314-win32.whl", hash = "sha256:cbfa87a03a419cf672f2d942b8d4d2d7ad938709d928ad07be9d8bb4f5922034"}, 437 | {file = "cwcwidth-0.1.11-cp314-cp314-win_amd64.whl", hash = "sha256:e8f301dc12e950d27ae66f0753aa01eeb222172bd463f38860c9aa669f0a5467"}, 438 | {file = "cwcwidth-0.1.11.tar.gz", hash = "sha256:594d8855a6319cc3ef36e0b6374fae02e4f4fe17cd87d0debe8b6e00eb186c17"}, 439 | ] 440 | 441 | [[package]] 442 | name = "decorator" 443 | version = "5.2.1" 444 | requires_python = ">=3.8" 445 | summary = "Decorators for Humans" 446 | files = [ 447 | {file = "decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a"}, 448 | {file = "decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360"}, 449 | ] 450 | 451 | [[package]] 452 | name = "distlib" 453 | version = "0.4.0" 454 | summary = "Distribution utilities" 455 | files = [ 456 | {file = "distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16"}, 457 | {file = "distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d"}, 458 | ] 459 | 460 | [[package]] 461 | name = "docutils" 462 | version = "0.22.3" 463 | requires_python = ">=3.9" 464 | summary = "Docutils -- Python Documentation Utilities" 465 | files = [ 466 | {file = "docutils-0.22.3-py3-none-any.whl", hash = "sha256:bd772e4aca73aff037958d44f2be5229ded4c09927fcf8690c577b66234d6ceb"}, 467 | {file = "docutils-0.22.3.tar.gz", hash = "sha256:21486ae730e4ca9f622677b1412b879af1791efcfba517e4c6f60be543fc8cdd"}, 468 | ] 469 | 470 | [[package]] 471 | name = "exceptiongroup" 472 | version = "1.3.1" 473 | requires_python = ">=3.7" 474 | summary = "Backport of PEP 654 (exception groups)" 475 | dependencies = [ 476 | "typing-extensions>=4.6.0; python_version < \"3.13\"", 477 | ] 478 | files = [ 479 | {file = "exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598"}, 480 | {file = "exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219"}, 481 | ] 482 | 483 | [[package]] 484 | name = "filelock" 485 | version = "3.20.0" 486 | requires_python = ">=3.10" 487 | summary = "A platform independent file lock." 488 | files = [ 489 | {file = "filelock-3.20.0-py3-none-any.whl", hash = "sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2"}, 490 | {file = "filelock-3.20.0.tar.gz", hash = "sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4"}, 491 | ] 492 | 493 | [[package]] 494 | name = "greenlet" 495 | version = "3.2.4" 496 | requires_python = ">=3.9" 497 | summary = "Lightweight in-process concurrent programming" 498 | files = [ 499 | {file = "greenlet-3.2.4-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:8c68325b0d0acf8d91dde4e6f930967dd52a5302cd4062932a6b2e7c2969f47c"}, 500 | {file = "greenlet-3.2.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:94385f101946790ae13da500603491f04a76b6e4c059dab271b3ce2e283b2590"}, 501 | {file = "greenlet-3.2.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f10fd42b5ee276335863712fa3da6608e93f70629c631bf77145021600abc23c"}, 502 | {file = "greenlet-3.2.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c8c9e331e58180d0d83c5b7999255721b725913ff6bc6cf39fa2a45841a4fd4b"}, 503 | {file = "greenlet-3.2.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:58b97143c9cc7b86fc458f215bd0932f1757ce649e05b640fea2e79b54cedb31"}, 504 | {file = "greenlet-3.2.4-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c2ca18a03a8cfb5b25bc1cbe20f3d9a4c80d8c3b13ba3df49ac3961af0b1018d"}, 505 | {file = "greenlet-3.2.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9fe0a28a7b952a21e2c062cd5756d34354117796c6d9215a87f55e38d15402c5"}, 506 | {file = "greenlet-3.2.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8854167e06950ca75b898b104b63cc646573aa5fef1353d4508ecdd1ee76254f"}, 507 | {file = "greenlet-3.2.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f47617f698838ba98f4ff4189aef02e7343952df3a615f847bb575c3feb177a7"}, 508 | {file = "greenlet-3.2.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af41be48a4f60429d5cad9d22175217805098a9ef7c40bfef44f7669fb9d74d8"}, 509 | {file = "greenlet-3.2.4-cp310-cp310-win_amd64.whl", hash = "sha256:73f49b5368b5359d04e18d15828eecc1806033db5233397748f4ca813ff1056c"}, 510 | {file = "greenlet-3.2.4-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:96378df1de302bc38e99c3a9aa311967b7dc80ced1dcc6f171e99842987882a2"}, 511 | {file = "greenlet-3.2.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1ee8fae0519a337f2329cb78bd7a8e128ec0f881073d43f023c7b8d4831d5246"}, 512 | {file = "greenlet-3.2.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:94abf90142c2a18151632371140b3dba4dee031633fe614cb592dbb6c9e17bc3"}, 513 | {file = "greenlet-3.2.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:4d1378601b85e2e5171b99be8d2dc85f594c79967599328f95c1dc1a40f1c633"}, 514 | {file = "greenlet-3.2.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0db5594dce18db94f7d1650d7489909b57afde4c580806b8d9203b6e79cdc079"}, 515 | {file = "greenlet-3.2.4-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2523e5246274f54fdadbce8494458a2ebdcdbc7b802318466ac5606d3cded1f8"}, 516 | {file = "greenlet-3.2.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1987de92fec508535687fb807a5cea1560f6196285a4cde35c100b8cd632cc52"}, 517 | {file = "greenlet-3.2.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:55e9c5affaa6775e2c6b67659f3a71684de4c549b3dd9afca3bc773533d284fa"}, 518 | {file = "greenlet-3.2.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c9c6de1940a7d828635fbd254d69db79e54619f165ee7ce32fda763a9cb6a58c"}, 519 | {file = "greenlet-3.2.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03c5136e7be905045160b1b9fdca93dd6727b180feeafda6818e6496434ed8c5"}, 520 | {file = "greenlet-3.2.4-cp311-cp311-win_amd64.whl", hash = "sha256:9c40adce87eaa9ddb593ccb0fa6a07caf34015a29bf8d344811665b573138db9"}, 521 | {file = "greenlet-3.2.4-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3b67ca49f54cede0186854a008109d6ee71f66bd57bb36abd6d0a0267b540cdd"}, 522 | {file = "greenlet-3.2.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ddf9164e7a5b08e9d22511526865780a576f19ddd00d62f8a665949327fde8bb"}, 523 | {file = "greenlet-3.2.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f28588772bb5fb869a8eb331374ec06f24a83a9c25bfa1f38b6993afe9c1e968"}, 524 | {file = "greenlet-3.2.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:5c9320971821a7cb77cfab8d956fa8e39cd07ca44b6070db358ceb7f8797c8c9"}, 525 | {file = "greenlet-3.2.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c60a6d84229b271d44b70fb6e5fa23781abb5d742af7b808ae3f6efd7c9c60f6"}, 526 | {file = "greenlet-3.2.4-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b3812d8d0c9579967815af437d96623f45c0f2ae5f04e366de62a12d83a8fb0"}, 527 | {file = "greenlet-3.2.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:abbf57b5a870d30c4675928c37278493044d7c14378350b3aa5d484fa65575f0"}, 528 | {file = "greenlet-3.2.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:20fb936b4652b6e307b8f347665e2c615540d4b42b3b4c8a321d8286da7e520f"}, 529 | {file = "greenlet-3.2.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ee7a6ec486883397d70eec05059353b8e83eca9168b9f3f9a361971e77e0bcd0"}, 530 | {file = "greenlet-3.2.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:326d234cbf337c9c3def0676412eb7040a35a768efc92504b947b3e9cfc7543d"}, 531 | {file = "greenlet-3.2.4-cp312-cp312-win_amd64.whl", hash = "sha256:a7d4e128405eea3814a12cc2605e0e6aedb4035bf32697f72deca74de4105e02"}, 532 | {file = "greenlet-3.2.4-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:1a921e542453fe531144e91e1feedf12e07351b1cf6c9e8a3325ea600a715a31"}, 533 | {file = "greenlet-3.2.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd3c8e693bff0fff6ba55f140bf390fa92c994083f838fece0f63be121334945"}, 534 | {file = "greenlet-3.2.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:710638eb93b1fa52823aa91bf75326f9ecdfd5e0466f00789246a5280f4ba0fc"}, 535 | {file = "greenlet-3.2.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c5111ccdc9c88f423426df3fd1811bfc40ed66264d35aa373420a34377efc98a"}, 536 | {file = "greenlet-3.2.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d76383238584e9711e20ebe14db6c88ddcedc1829a9ad31a584389463b5aa504"}, 537 | {file = "greenlet-3.2.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23768528f2911bcd7e475210822ffb5254ed10d71f4028387e5a99b4c6699671"}, 538 | {file = "greenlet-3.2.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:00fadb3fedccc447f517ee0d3fd8fe49eae949e1cd0f6a611818f4f6fb7dc83b"}, 539 | {file = "greenlet-3.2.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d25c5091190f2dc0eaa3f950252122edbbadbb682aa7b1ef2f8af0f8c0afefae"}, 540 | {file = "greenlet-3.2.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6e343822feb58ac4d0a1211bd9399de2b3a04963ddeec21530fc426cc121f19b"}, 541 | {file = "greenlet-3.2.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca7f6f1f2649b89ce02f6f229d7c19f680a6238af656f61e0115b24857917929"}, 542 | {file = "greenlet-3.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:554b03b6e73aaabec3745364d6239e9e012d64c68ccd0b8430c64ccc14939a8b"}, 543 | {file = "greenlet-3.2.4-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:49a30d5fda2507ae77be16479bdb62a660fa51b1eb4928b524975b3bde77b3c0"}, 544 | {file = "greenlet-3.2.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:299fd615cd8fc86267b47597123e3f43ad79c9d8a22bebdce535e53550763e2f"}, 545 | {file = "greenlet-3.2.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:c17b6b34111ea72fc5a4e4beec9711d2226285f0386ea83477cbb97c30a3f3a5"}, 546 | {file = "greenlet-3.2.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b4a1870c51720687af7fa3e7cda6d08d801dae660f75a76f3845b642b4da6ee1"}, 547 | {file = "greenlet-3.2.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:061dc4cf2c34852b052a8620d40f36324554bc192be474b9e9770e8c042fd735"}, 548 | {file = "greenlet-3.2.4-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44358b9bf66c8576a9f57a590d5f5d6e72fa4228b763d0e43fee6d3b06d3a337"}, 549 | {file = "greenlet-3.2.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2917bdf657f5859fbf3386b12d68ede4cf1f04c90c3a6bc1f013dd68a22e2269"}, 550 | {file = "greenlet-3.2.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:015d48959d4add5d6c9f6c5210ee3803a830dce46356e3bc326d6776bde54681"}, 551 | {file = "greenlet-3.2.4-cp314-cp314-win_amd64.whl", hash = "sha256:e37ab26028f12dbb0ff65f29a8d3d44a765c61e729647bf2ddfbbed621726f01"}, 552 | {file = "greenlet-3.2.4.tar.gz", hash = "sha256:0dca0d95ff849f9a364385f36ab49f50065d76964944638be9691e1832e9f86d"}, 553 | ] 554 | 555 | [[package]] 556 | name = "hypothesis" 557 | version = "6.21.6" 558 | requires_python = ">=3.6" 559 | summary = "A library for property-based testing" 560 | dependencies = [ 561 | "attrs>=19.2.0", 562 | "sortedcontainers<3.0.0,>=2.1.0", 563 | ] 564 | files = [ 565 | {file = "hypothesis-6.21.6-py3-none-any.whl", hash = "sha256:1a96c67658f0fca00476380c2c7323066e2fb1d45a2b0874dd07fd0643b49b46"}, 566 | {file = "hypothesis-6.21.6.tar.gz", hash = "sha256:29b72005910f2a548d727e5d5accf862a6ae84e49176d748fb6ca040ef657592"}, 567 | ] 568 | 569 | [[package]] 570 | name = "id" 571 | version = "1.5.0" 572 | requires_python = ">=3.8" 573 | summary = "A tool for generating OIDC identities" 574 | dependencies = [ 575 | "requests", 576 | ] 577 | files = [ 578 | {file = "id-1.5.0-py3-none-any.whl", hash = "sha256:f1434e1cef91f2cbb8a4ec64663d5a23b9ed43ef44c4c957d02583d61714c658"}, 579 | {file = "id-1.5.0.tar.gz", hash = "sha256:292cb8a49eacbbdbce97244f47a97b4c62540169c976552e497fd57df0734c1d"}, 580 | ] 581 | 582 | [[package]] 583 | name = "idna" 584 | version = "3.11" 585 | requires_python = ">=3.8" 586 | summary = "Internationalized Domain Names in Applications (IDNA)" 587 | files = [ 588 | {file = "idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea"}, 589 | {file = "idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902"}, 590 | ] 591 | 592 | [[package]] 593 | name = "importlib-metadata" 594 | version = "8.7.0" 595 | requires_python = ">=3.9" 596 | summary = "Read metadata from Python packages" 597 | dependencies = [ 598 | "typing-extensions>=3.6.4; python_version < \"3.8\"", 599 | "zipp>=3.20", 600 | ] 601 | files = [ 602 | {file = "importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd"}, 603 | {file = "importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000"}, 604 | ] 605 | 606 | [[package]] 607 | name = "iniconfig" 608 | version = "2.3.0" 609 | requires_python = ">=3.10" 610 | summary = "brain-dead simple config-ini parsing" 611 | files = [ 612 | {file = "iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12"}, 613 | {file = "iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730"}, 614 | ] 615 | 616 | [[package]] 617 | name = "ipython" 618 | version = "7.16.3" 619 | requires_python = ">=3.6" 620 | summary = "IPython: Productive Interactive Computing" 621 | dependencies = [ 622 | "appnope; sys_platform == \"darwin\"", 623 | "backcall", 624 | "colorama; sys_platform == \"win32\"", 625 | "decorator", 626 | "jedi<=0.17.2,>=0.10", 627 | "pexpect; sys_platform != \"win32\"", 628 | "pickleshare", 629 | "prompt-toolkit!=3.0.0,!=3.0.1,<3.1.0,>=2.0.0", 630 | "pygments", 631 | "setuptools>=18.5", 632 | "traitlets>=4.2", 633 | ] 634 | files = [ 635 | {file = "ipython-7.16.3-py3-none-any.whl", hash = "sha256:c0427ed8bc33ac481faf9d3acf7e84e0010cdaada945e0badd1e2e74cc075833"}, 636 | {file = "ipython-7.16.3.tar.gz", hash = "sha256:5ac47dc9af66fc2f5530c12069390877ae372ac905edca75a92a6e363b5d7caa"}, 637 | ] 638 | 639 | [[package]] 640 | name = "jaraco-classes" 641 | version = "3.4.0" 642 | requires_python = ">=3.8" 643 | summary = "Utility functions for Python class constructs" 644 | dependencies = [ 645 | "more-itertools", 646 | ] 647 | files = [ 648 | {file = "jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790"}, 649 | {file = "jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd"}, 650 | ] 651 | 652 | [[package]] 653 | name = "jaraco-context" 654 | version = "6.0.1" 655 | requires_python = ">=3.8" 656 | summary = "Useful decorators and context managers" 657 | dependencies = [ 658 | "backports-tarfile; python_version < \"3.12\"", 659 | ] 660 | files = [ 661 | {file = "jaraco.context-6.0.1-py3-none-any.whl", hash = "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4"}, 662 | {file = "jaraco_context-6.0.1.tar.gz", hash = "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3"}, 663 | ] 664 | 665 | [[package]] 666 | name = "jaraco-functools" 667 | version = "4.3.0" 668 | requires_python = ">=3.9" 669 | summary = "Functools like those found in stdlib" 670 | dependencies = [ 671 | "more-itertools", 672 | ] 673 | files = [ 674 | {file = "jaraco_functools-4.3.0-py3-none-any.whl", hash = "sha256:227ff8ed6f7b8f62c56deff101545fa7543cf2c8e7b82a7c2116e672f29c26e8"}, 675 | {file = "jaraco_functools-4.3.0.tar.gz", hash = "sha256:cfd13ad0dd2c47a3600b439ef72d8615d482cedcff1632930d6f28924d92f294"}, 676 | ] 677 | 678 | [[package]] 679 | name = "jedi" 680 | version = "0.17.2" 681 | requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 682 | summary = "An autocompletion tool for Python that can be used for text editors." 683 | dependencies = [ 684 | "parso<0.8.0,>=0.7.0", 685 | ] 686 | files = [ 687 | {file = "jedi-0.17.2-py2.py3-none-any.whl", hash = "sha256:98cc583fa0f2f8304968199b01b6b4b94f469a1f4a74c1560506ca2a211378b5"}, 688 | {file = "jedi-0.17.2.tar.gz", hash = "sha256:86ed7d9b750603e4ba582ea8edc678657fb4007894a12bcf6f4bb97892f31d20"}, 689 | ] 690 | 691 | [[package]] 692 | name = "jeepney" 693 | version = "0.9.0" 694 | requires_python = ">=3.7" 695 | summary = "Low-level, pure Python DBus protocol wrapper." 696 | files = [ 697 | {file = "jeepney-0.9.0-py3-none-any.whl", hash = "sha256:97e5714520c16fc0a45695e5365a2e11b81ea79bba796e26f9f1d178cb182683"}, 698 | {file = "jeepney-0.9.0.tar.gz", hash = "sha256:cf0e9e845622b81e4a28df94c40345400256ec608d0e55bb8a3feaa9163f5732"}, 699 | ] 700 | 701 | [[package]] 702 | name = "jinxed" 703 | version = "1.3.0" 704 | summary = "Jinxed Terminal Library" 705 | dependencies = [ 706 | "ansicon; platform_system == \"Windows\"", 707 | ] 708 | files = [ 709 | {file = "jinxed-1.3.0-py2.py3-none-any.whl", hash = "sha256:b993189f39dc2d7504d802152671535b06d380b26d78070559551cbf92df4fc5"}, 710 | {file = "jinxed-1.3.0.tar.gz", hash = "sha256:1593124b18a41b7a3da3b078471442e51dbad3d77b4d4f2b0c26ab6f7d660dbf"}, 711 | ] 712 | 713 | [[package]] 714 | name = "keyring" 715 | version = "25.7.0" 716 | requires_python = ">=3.9" 717 | summary = "Store and access your passwords safely." 718 | dependencies = [ 719 | "SecretStorage>=3.2; sys_platform == \"linux\"", 720 | "importlib-metadata>=4.11.4; python_version < \"3.12\"", 721 | "jaraco-classes", 722 | "jaraco-context", 723 | "jaraco-functools", 724 | "jeepney>=0.4.2; sys_platform == \"linux\"", 725 | "pywin32-ctypes>=0.2.0; sys_platform == \"win32\"", 726 | ] 727 | files = [ 728 | {file = "keyring-25.7.0-py3-none-any.whl", hash = "sha256:be4a0b195f149690c166e850609a477c532ddbfbaed96a404d4e43f8d5e2689f"}, 729 | {file = "keyring-25.7.0.tar.gz", hash = "sha256:fe01bd85eb3f8fb3dd0405defdeac9a5b4f6f0439edbb3149577f244a2e8245b"}, 730 | ] 731 | 732 | [[package]] 733 | name = "librt" 734 | version = "0.6.2" 735 | requires_python = ">=3.9" 736 | summary = "Mypyc runtime library" 737 | files = [ 738 | {file = "librt-0.6.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7a52a08a7e725629c46b599a0773dc824025cf11c55e7a27231ec3975977dd75"}, 739 | {file = "librt-0.6.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1e8fb4770f6bdde38c7f5eb882fd754b4813d3b9ecaa1670e455d6f5dd0f17de"}, 740 | {file = "librt-0.6.2-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5ef044b227ee67e44497080b796a3c6b75bd9b3efe1c4b857503122b15e8e5a6"}, 741 | {file = "librt-0.6.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5b5bb3ce17287b3743a70563318afefb38e7b0f019b7d53cd12fbe9680a51fcf"}, 742 | {file = "librt-0.6.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fa69a9c81e6d0c36339e759583794c17cea4391e1a29d0cba38d311594110a16"}, 743 | {file = "librt-0.6.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7fcbb0495a98ac859e67da5606ea3db4edf54000fb06f8878aa09a1b7b1d202b"}, 744 | {file = "librt-0.6.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c98a4f91a4fced1cf31bfc43a2b09ba35e907a093dc4e503f930313b934eadf7"}, 745 | {file = "librt-0.6.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4d935be27c566cf2c646c198041bbd79023732ceff748dd87ceedc08a049687b"}, 746 | {file = "librt-0.6.2-cp310-cp310-win32.whl", hash = "sha256:cb493736dde178155c07e894962e91377e7ee3afd6d1aa945cf9b065961c948c"}, 747 | {file = "librt-0.6.2-cp310-cp310-win_amd64.whl", hash = "sha256:c7ba7cd0bcbfe3a6ba184ea5ed9fb330a3dd4e7c0958cb426a811bfe28fc9847"}, 748 | {file = "librt-0.6.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aedd015ecf8eb1e4f4d03a9022a8a69205de673b75826dd03fb0ff8c882cd407"}, 749 | {file = "librt-0.6.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa36536067a7029477510be4884ca96bd34a25690c73a3b423109b4f20b16a9a"}, 750 | {file = "librt-0.6.2-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1c6907d657c36f5ed720e9b694d939b2bc872c331cc9c6abd6318294f4309bf9"}, 751 | {file = "librt-0.6.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f12ccd30a488139eb262da6ecc4ffd6f9fc667fd2a87fcb272a78ad5359fb3b7"}, 752 | {file = "librt-0.6.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8ab8de3fa52eef597a441e3ca5aa8b353c752808312b84037b5d8e6a3843b7d9"}, 753 | {file = "librt-0.6.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f7e3a9deec913289eba43d1b4785043ceb5b21c01f38ffb830d7644736311834"}, 754 | {file = "librt-0.6.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e5bcc7c08dcfefca4c2ff4db4fe8218a910d2efe20453cbc5978a76a77d12c9d"}, 755 | {file = "librt-0.6.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f34c116d51b21f511746eb775cca67a1ab832a22e18721ddfb5b45585e9a29fc"}, 756 | {file = "librt-0.6.2-cp311-cp311-win32.whl", hash = "sha256:3a0017a09cbed5f199962c987dec03fe0c073ef893f4d47b28c85b4e864ee890"}, 757 | {file = "librt-0.6.2-cp311-cp311-win_amd64.whl", hash = "sha256:b727311a51a847c0ba7864fb3406aa9839343d5c221be67b4da8d4740892e4a7"}, 758 | {file = "librt-0.6.2-cp311-cp311-win_arm64.whl", hash = "sha256:f20c699c410d4649f6648ad7b8e64e7f97d8e1debcdb856e17530064444a51a5"}, 759 | {file = "librt-0.6.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:29f4e8888de87eb637c1b1c3ca9e97f3d8828e481f5ef0b86bb90ae026215d4c"}, 760 | {file = "librt-0.6.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f5cdacbe18f91741a5f45bb169a92ab5299e0c6a7245798d075885480706c4e5"}, 761 | {file = "librt-0.6.2-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:de0461670334c16b76885d8a93a3c1f1b0259fb7d817cec326193325c24898e0"}, 762 | {file = "librt-0.6.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fcddd735029802e9ab56d482f977ca08920c432382c9382334e7cfa9ad0bb0de"}, 763 | {file = "librt-0.6.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:06c82cf56b3c2fab8e19e7415b6eb1b958356f6e6ee082b0077a582356801185"}, 764 | {file = "librt-0.6.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3a426287d679aebd6dd3000192d054cdd2d90ae7612b51d0f4931b2f37dd1d13"}, 765 | {file = "librt-0.6.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:75fa4126883da85600f4763930e8791949f50ab323fa8fc17fb31185b4fd16af"}, 766 | {file = "librt-0.6.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:73cf76b5814d268d777eca17db45a2bdd9c80f50eab01cf8b642f8bf18497358"}, 767 | {file = "librt-0.6.2-cp312-cp312-win32.whl", hash = "sha256:93cd69497046d67f35e1d00cef099bf32f97c277ff950c406e7e062ccf86852e"}, 768 | {file = "librt-0.6.2-cp312-cp312-win_amd64.whl", hash = "sha256:2ada7182335b25120ec960fbbf22d8f534bb9bb101f248f849bc977bc51165c8"}, 769 | {file = "librt-0.6.2-cp312-cp312-win_arm64.whl", hash = "sha256:e2deaac245f6ce54caf6ccb5dabeadd35950e669f4ed31addd300ff4eaee981c"}, 770 | {file = "librt-0.6.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ad4014a959de1b4c020e0de0b92b637463e80d54fc6f12b8c0a357ef7289190f"}, 771 | {file = "librt-0.6.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1eea7c6633cdd6ee3fd8d1677949c278bd2db9f6f39d2b34affe2d70c8dc0258"}, 772 | {file = "librt-0.6.2-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:28d159adc310be1aba21480d56a6ebc06b98948fb60e15ccc77a77c6a037cd5f"}, 773 | {file = "librt-0.6.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cd85a818a58871a7d3fe3e9821423c06c1d2b5ac6d7ad21f62c28243b858c920"}, 774 | {file = "librt-0.6.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3d58f22191217c6474d1a26269db2347c3862ef9fa379bd0c86bca659fe84145"}, 775 | {file = "librt-0.6.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6408501b01add8913cfdf795ba57bce7095ac2a2ee170de660d4bff8ad589074"}, 776 | {file = "librt-0.6.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fd1d5b3867feeecf3b627178f43b7bb940e0390e81bafab6b681b17112591198"}, 777 | {file = "librt-0.6.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c2920f525b54cd00adbb0e727d5d3ba6292a2d038788529ad8810a3d77acdf0f"}, 778 | {file = "librt-0.6.2-cp313-cp313-win32.whl", hash = "sha256:74213ad49b127da47a22f2c877be216820215880c527f28df726ad5d505f1239"}, 779 | {file = "librt-0.6.2-cp313-cp313-win_amd64.whl", hash = "sha256:778667b8688bbacba06739eb5b0b78d99d2c65a99262dac5ab25eba473b34d5f"}, 780 | {file = "librt-0.6.2-cp313-cp313-win_arm64.whl", hash = "sha256:e787bfcccdf0f25e02310d7f1e2b9bfea714f594cda37a6ce6da84502f14acbf"}, 781 | {file = "librt-0.6.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b32488d018e41668fe174b51552ddd810c85d1c8d86acbf72fb9240b3937f6a4"}, 782 | {file = "librt-0.6.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7fdf4a9a568be5a591691e8f0e68912272b57240592cad3edbb5521ad6bcadb7"}, 783 | {file = "librt-0.6.2-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bacdb6bcaa26d90ab467f4a0646691274735a92d088d7d9040a9b39ebd9abafd"}, 784 | {file = "librt-0.6.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c2554e1b06beb622394b54eda36f22808b4b789dfd421fea6f5031a7de18529b"}, 785 | {file = "librt-0.6.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6569f08ced06fa1a6005c440fb2b6129981084b1d9442c517d5379a4f1b32a9b"}, 786 | {file = "librt-0.6.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:693085d0fd2073260abc57baa309ab90f5ce5510058d0c2c6621988ba633dbe4"}, 787 | {file = "librt-0.6.2-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:2264a99845c8f509b4060f730a51947ca51efcbee9b4c74033c8308290cd992b"}, 788 | {file = "librt-0.6.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:55dc24c5a0f52ec01c8a655e266f75a809b30322443cb9a6372560fd77c9f3ba"}, 789 | {file = "librt-0.6.2-cp314-cp314-win32.whl", hash = "sha256:7b904b5d0ed10b2dac3c65bb3afadc23527d09b0787b6ae548b76d3cf432b402"}, 790 | {file = "librt-0.6.2-cp314-cp314-win_amd64.whl", hash = "sha256:faf0112a7a8fcabd168c69d1bcbabca8767738db3f336caaac5653d91c3d1c0b"}, 791 | {file = "librt-0.6.2-cp314-cp314-win_arm64.whl", hash = "sha256:9c1125d3a89ce640e5a73114ee24f7198bf69c194802c0b4e791d99e7a0929e4"}, 792 | {file = "librt-0.6.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:4f3cbbf8c59fd705be4a0c82b9be204149806483454f37753ac1f8b4ef7c943d"}, 793 | {file = "librt-0.6.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0d0ac917e1b14781a7f478155c63060e86a79261e3765f4f08569225758f5563"}, 794 | {file = "librt-0.6.2-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ec1ccda3ab5d942b0df64634aa5c0d72e73fd2d9be63d0385e48b87929186343"}, 795 | {file = "librt-0.6.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc8a00fd9899e89f2096b130d5697734d6fd82ecf474eb006b836d206dad80b8"}, 796 | {file = "librt-0.6.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22e1c97b3848924f1ff3e5404aee12f1c6a9e17d715f922b4f694c77a1a365d2"}, 797 | {file = "librt-0.6.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:924c11a0d02568dada2463f819caf184ac0c88662e836ccc91001921db543acb"}, 798 | {file = "librt-0.6.2-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:21c9f9440d7464a6783f51f701beaadfff75d48aacf174d94cf4b793b826420b"}, 799 | {file = "librt-0.6.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:4b2d9364f0794b7c92f02d62321f5f0ab9d9061fc812871a8c34f418bdf43964"}, 800 | {file = "librt-0.6.2-cp314-cp314t-win32.whl", hash = "sha256:64451cbf341224e274f6f7e27c09c00a6758c7d4d6176a03e259a12e0befb7d8"}, 801 | {file = "librt-0.6.2-cp314-cp314t-win_amd64.whl", hash = "sha256:dd08422c485df288c5c899d2adbbba15e317fc30f627119c99c2111da1920fb5"}, 802 | {file = "librt-0.6.2-cp314-cp314t-win_arm64.whl", hash = "sha256:de06350dfbf0649c0458e0af95fa516886120d0d11ed4ebbfcb7f67b038ab393"}, 803 | {file = "librt-0.6.2.tar.gz", hash = "sha256:3898faf00cada0bf2a97106936e92fe107ee4fbdf4e5ebd922cfd5ee9f052884"}, 804 | ] 805 | 806 | [[package]] 807 | name = "markdown-it-py" 808 | version = "4.0.0" 809 | requires_python = ">=3.10" 810 | summary = "Python port of markdown-it. Markdown parsing, done right!" 811 | dependencies = [ 812 | "mdurl~=0.1", 813 | ] 814 | files = [ 815 | {file = "markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147"}, 816 | {file = "markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3"}, 817 | ] 818 | 819 | [[package]] 820 | name = "mdurl" 821 | version = "0.1.2" 822 | requires_python = ">=3.7" 823 | summary = "Markdown URL utilities" 824 | files = [ 825 | {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, 826 | {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, 827 | ] 828 | 829 | [[package]] 830 | name = "more-itertools" 831 | version = "10.8.0" 832 | requires_python = ">=3.9" 833 | summary = "More routines for operating on iterables, beyond itertools" 834 | files = [ 835 | {file = "more_itertools-10.8.0-py3-none-any.whl", hash = "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b"}, 836 | {file = "more_itertools-10.8.0.tar.gz", hash = "sha256:f638ddf8a1a0d134181275fb5d58b086ead7c6a72429ad725c67503f13ba30bd"}, 837 | ] 838 | 839 | [[package]] 840 | name = "mypy" 841 | version = "1.19.0" 842 | requires_python = ">=3.9" 843 | summary = "Optional static typing for Python" 844 | dependencies = [ 845 | "librt>=0.6.2", 846 | "mypy-extensions>=1.0.0", 847 | "pathspec>=0.9.0", 848 | "tomli>=1.1.0; python_version < \"3.11\"", 849 | "typing-extensions>=4.6.0", 850 | ] 851 | files = [ 852 | {file = "mypy-1.19.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6148ede033982a8c5ca1143de34c71836a09f105068aaa8b7d5edab2b053e6c8"}, 853 | {file = "mypy-1.19.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a9ac09e52bb0f7fb912f5d2a783345c72441a08ef56ce3e17c1752af36340a39"}, 854 | {file = "mypy-1.19.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:11f7254c15ab3f8ed68f8e8f5cbe88757848df793e31c36aaa4d4f9783fd08ab"}, 855 | {file = "mypy-1.19.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:318ba74f75899b0e78b847d8c50821e4c9637c79d9a59680fc1259f29338cb3e"}, 856 | {file = "mypy-1.19.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cf7d84f497f78b682edd407f14a7b6e1a2212b433eedb054e2081380b7395aa3"}, 857 | {file = "mypy-1.19.0-cp310-cp310-win_amd64.whl", hash = "sha256:c3385246593ac2b97f155a0e9639be906e73534630f663747c71908dfbf26134"}, 858 | {file = "mypy-1.19.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a31e4c28e8ddb042c84c5e977e28a21195d086aaffaf08b016b78e19c9ef8106"}, 859 | {file = "mypy-1.19.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:34ec1ac66d31644f194b7c163d7f8b8434f1b49719d403a5d26c87fff7e913f7"}, 860 | {file = "mypy-1.19.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cb64b0ba5980466a0f3f9990d1c582bcab8db12e29815ecb57f1408d99b4bff7"}, 861 | {file = "mypy-1.19.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:120cffe120cca5c23c03c77f84abc0c14c5d2e03736f6c312480020082f1994b"}, 862 | {file = "mypy-1.19.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7a500ab5c444268a70565e374fc803972bfd1f09545b13418a5174e29883dab7"}, 863 | {file = "mypy-1.19.0-cp311-cp311-win_amd64.whl", hash = "sha256:c14a98bc63fd867530e8ec82f217dae29d0550c86e70debc9667fff1ec83284e"}, 864 | {file = "mypy-1.19.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0fb3115cb8fa7c5f887c8a8d81ccdcb94cff334684980d847e5a62e926910e1d"}, 865 | {file = "mypy-1.19.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3e19e3b897562276bb331074d64c076dbdd3e79213f36eed4e592272dabd760"}, 866 | {file = "mypy-1.19.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b9d491295825182fba01b6ffe2c6fe4e5a49dbf4e2bb4d1217b6ced3b4797bc6"}, 867 | {file = "mypy-1.19.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6016c52ab209919b46169651b362068f632efcd5eb8ef9d1735f6f86da7853b2"}, 868 | {file = "mypy-1.19.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f188dcf16483b3e59f9278c4ed939ec0254aa8a60e8fc100648d9ab5ee95a431"}, 869 | {file = "mypy-1.19.0-cp312-cp312-win_amd64.whl", hash = "sha256:0e3c3d1e1d62e678c339e7ade72746a9e0325de42cd2cccc51616c7b2ed1a018"}, 870 | {file = "mypy-1.19.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7686ed65dbabd24d20066f3115018d2dce030d8fa9db01aa9f0a59b6813e9f9e"}, 871 | {file = "mypy-1.19.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fd4a985b2e32f23bead72e2fb4bbe5d6aceee176be471243bd831d5b2644672d"}, 872 | {file = "mypy-1.19.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fc51a5b864f73a3a182584b1ac75c404396a17eced54341629d8bdcb644a5bba"}, 873 | {file = "mypy-1.19.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:37af5166f9475872034b56c5efdcf65ee25394e9e1d172907b84577120714364"}, 874 | {file = "mypy-1.19.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:510c014b722308c9bd377993bcbf9a07d7e0692e5fa8fc70e639c1eb19fc6bee"}, 875 | {file = "mypy-1.19.0-cp313-cp313-win_amd64.whl", hash = "sha256:cabbee74f29aa9cd3b444ec2f1e4fa5a9d0d746ce7567a6a609e224429781f53"}, 876 | {file = "mypy-1.19.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:f2e36bed3c6d9b5f35d28b63ca4b727cb0228e480826ffc8953d1892ddc8999d"}, 877 | {file = "mypy-1.19.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a18d8abdda14035c5718acb748faec09571432811af129bf0d9e7b2d6699bf18"}, 878 | {file = "mypy-1.19.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f75e60aca3723a23511948539b0d7ed514dda194bc3755eae0bfc7a6b4887aa7"}, 879 | {file = "mypy-1.19.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8f44f2ae3c58421ee05fe609160343c25f70e3967f6e32792b5a78006a9d850f"}, 880 | {file = "mypy-1.19.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:63ea6a00e4bd6822adbfc75b02ab3653a17c02c4347f5bb0cf1d5b9df3a05835"}, 881 | {file = "mypy-1.19.0-cp314-cp314-win_amd64.whl", hash = "sha256:3ad925b14a0bb99821ff6f734553294aa6a3440a8cb082fe1f5b84dfb662afb1"}, 882 | {file = "mypy-1.19.0-py3-none-any.whl", hash = "sha256:0c01c99d626380752e527d5ce8e69ffbba2046eb8a060db0329690849cf9b6f9"}, 883 | {file = "mypy-1.19.0.tar.gz", hash = "sha256:f6b874ca77f733222641e5c46e4711648c4037ea13646fd0cdc814c2eaec2528"}, 884 | ] 885 | 886 | [[package]] 887 | name = "mypy-extensions" 888 | version = "1.1.0" 889 | requires_python = ">=3.8" 890 | summary = "Type system extensions for programs checked with the mypy type checker." 891 | files = [ 892 | {file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"}, 893 | {file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"}, 894 | ] 895 | 896 | [[package]] 897 | name = "nh3" 898 | version = "0.3.2" 899 | requires_python = ">=3.8" 900 | summary = "Python binding to Ammonia HTML sanitizer Rust crate" 901 | files = [ 902 | {file = "nh3-0.3.2-cp314-cp314t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:d18957a90806d943d141cc5e4a0fefa1d77cf0d7a156878bf9a66eed52c9cc7d"}, 903 | {file = "nh3-0.3.2-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45c953e57028c31d473d6b648552d9cab1efe20a42ad139d78e11d8f42a36130"}, 904 | {file = "nh3-0.3.2-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2c9850041b77a9147d6bbd6dbbf13eeec7009eb60b44e83f07fcb2910075bf9b"}, 905 | {file = "nh3-0.3.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:403c11563e50b915d0efdb622866d1d9e4506bce590ef7da57789bf71dd148b5"}, 906 | {file = "nh3-0.3.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:0dca4365db62b2d71ff1620ee4f800c4729849906c5dd504ee1a7b2389558e31"}, 907 | {file = "nh3-0.3.2-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:0fe7ee035dd7b2290715baf29cb27167dddd2ff70ea7d052c958dbd80d323c99"}, 908 | {file = "nh3-0.3.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a40202fd58e49129764f025bbaae77028e420f1d5b3c8e6f6fd3a6490d513868"}, 909 | {file = "nh3-0.3.2-cp314-cp314t-win32.whl", hash = "sha256:1f9ba555a797dbdcd844b89523f29cdc90973d8bd2e836ea6b962cf567cadd93"}, 910 | {file = "nh3-0.3.2-cp314-cp314t-win_amd64.whl", hash = "sha256:dce4248edc427c9b79261f3e6e2b3ecbdd9b88c267012168b4a7b3fc6fd41d13"}, 911 | {file = "nh3-0.3.2-cp314-cp314t-win_arm64.whl", hash = "sha256:019ecbd007536b67fdf76fab411b648fb64e2257ca3262ec80c3425c24028c80"}, 912 | {file = "nh3-0.3.2-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7064ccf5ace75825bd7bf57859daaaf16ed28660c1c6b306b649a9eda4b54b1e"}, 913 | {file = "nh3-0.3.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8745454cdd28bbbc90861b80a0111a195b0e3961b9fa2e672be89eb199fa5d8"}, 914 | {file = "nh3-0.3.2-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72d67c25a84579f4a432c065e8b4274e53b7cf1df8f792cf846abfe2c3090866"}, 915 | {file = "nh3-0.3.2-cp38-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:13398e676a14d6233f372c75f52d5ae74f98210172991f7a3142a736bd92b131"}, 916 | {file = "nh3-0.3.2-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:03d617e5c8aa7331bd2659c654e021caf9bba704b109e7b2b28b039a00949fe5"}, 917 | {file = "nh3-0.3.2-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2f55c4d2d5a207e74eefe4d828067bbb01300e06e2a7436142f915c5928de07"}, 918 | {file = "nh3-0.3.2-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bb18403f02b655a1bbe4e3a4696c2ae1d6ae8f5991f7cacb684b1ae27e6c9f7"}, 919 | {file = "nh3-0.3.2-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6d66f41672eb4060cf87c037f760bdbc6847852ca9ef8e9c5a5da18f090abf87"}, 920 | {file = "nh3-0.3.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f97f8b25cb2681d25e2338148159447e4d689aafdccfcf19e61ff7db3905768a"}, 921 | {file = "nh3-0.3.2-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:2ab70e8c6c7d2ce953d2a58102eefa90c2d0a5ed7aa40c7e29a487bc5e613131"}, 922 | {file = "nh3-0.3.2-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:1710f3901cd6440ca92494ba2eb6dc260f829fa8d9196b659fa10de825610ce0"}, 923 | {file = "nh3-0.3.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:91e9b001101fb4500a2aafe3e7c92928d85242d38bf5ac0aba0b7480da0a4cd6"}, 924 | {file = "nh3-0.3.2-cp38-abi3-win32.whl", hash = "sha256:169db03df90da63286e0560ea0efa9b6f3b59844a9735514a1d47e6bb2c8c61b"}, 925 | {file = "nh3-0.3.2-cp38-abi3-win_amd64.whl", hash = "sha256:562da3dca7a17f9077593214a9781a94b8d76de4f158f8c895e62f09573945fe"}, 926 | {file = "nh3-0.3.2-cp38-abi3-win_arm64.whl", hash = "sha256:cf5964d54edd405e68583114a7cba929468bcd7db5e676ae38ee954de1cfc104"}, 927 | {file = "nh3-0.3.2.tar.gz", hash = "sha256:f394759a06df8b685a4ebfb1874fb67a9cbfd58c64fc5ed587a663c0e63ec376"}, 928 | ] 929 | 930 | [[package]] 931 | name = "packaging" 932 | version = "25.0" 933 | requires_python = ">=3.8" 934 | summary = "Core utilities for Python packages" 935 | files = [ 936 | {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, 937 | {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, 938 | ] 939 | 940 | [[package]] 941 | name = "parso" 942 | version = "0.7.1" 943 | requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 944 | summary = "A Python Parser" 945 | files = [ 946 | {file = "parso-0.7.1-py2.py3-none-any.whl", hash = "sha256:97218d9159b2520ff45eb78028ba8b50d2bc61dcc062a9682666f2dc4bd331ea"}, 947 | {file = "parso-0.7.1.tar.gz", hash = "sha256:caba44724b994a8a5e086460bb212abc5a8bc46951bf4a9a1210745953622eb9"}, 948 | ] 949 | 950 | [[package]] 951 | name = "pathspec" 952 | version = "0.12.1" 953 | requires_python = ">=3.8" 954 | summary = "Utility library for gitignore style pattern matching of file paths." 955 | files = [ 956 | {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, 957 | {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, 958 | ] 959 | 960 | [[package]] 961 | name = "pexpect" 962 | version = "4.9.0" 963 | summary = "Pexpect allows easy control of interactive console applications." 964 | dependencies = [ 965 | "ptyprocess>=0.5", 966 | ] 967 | files = [ 968 | {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, 969 | {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, 970 | ] 971 | 972 | [[package]] 973 | name = "pickleshare" 974 | version = "0.7.5" 975 | summary = "Tiny 'shelve'-like database with concurrency support" 976 | dependencies = [ 977 | "pathlib2; python_version in \"2.6 2.7 3.2 3.3\"", 978 | ] 979 | files = [ 980 | {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"}, 981 | {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, 982 | ] 983 | 984 | [[package]] 985 | name = "platformdirs" 986 | version = "4.5.0" 987 | requires_python = ">=3.10" 988 | summary = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." 989 | files = [ 990 | {file = "platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3"}, 991 | {file = "platformdirs-4.5.0.tar.gz", hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312"}, 992 | ] 993 | 994 | [[package]] 995 | name = "pluggy" 996 | version = "1.6.0" 997 | requires_python = ">=3.9" 998 | summary = "plugin and hook calling mechanisms for python" 999 | files = [ 1000 | {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, 1001 | {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, 1002 | ] 1003 | 1004 | [[package]] 1005 | name = "prompt-toolkit" 1006 | version = "3.0.52" 1007 | requires_python = ">=3.8" 1008 | summary = "Library for building powerful interactive command lines in Python" 1009 | dependencies = [ 1010 | "wcwidth", 1011 | ] 1012 | files = [ 1013 | {file = "prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955"}, 1014 | {file = "prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855"}, 1015 | ] 1016 | 1017 | [[package]] 1018 | name = "ptpython" 1019 | version = "3.0.32" 1020 | requires_python = ">=3.8" 1021 | summary = "Python REPL build on top of prompt_toolkit" 1022 | dependencies = [ 1023 | "appdirs", 1024 | "jedi>=0.16.0", 1025 | "prompt-toolkit<3.1.0,>=3.0.43", 1026 | "pygments", 1027 | ] 1028 | files = [ 1029 | {file = "ptpython-3.0.32-py3-none-any.whl", hash = "sha256:16435d323e5fc0a685d5f4dc5bb4494fb68ac68736689cd1247e1eda9369b616"}, 1030 | {file = "ptpython-3.0.32.tar.gz", hash = "sha256:11651778236de95c582b42737294e50a66ba4a21fa01c0090ea70815af478fe0"}, 1031 | ] 1032 | 1033 | [[package]] 1034 | name = "ptyprocess" 1035 | version = "0.7.0" 1036 | summary = "Run a subprocess in a pseudo terminal" 1037 | files = [ 1038 | {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, 1039 | {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, 1040 | ] 1041 | 1042 | [[package]] 1043 | name = "pycparser" 1044 | version = "2.23" 1045 | requires_python = ">=3.8" 1046 | summary = "C parser in Python" 1047 | files = [ 1048 | {file = "pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934"}, 1049 | {file = "pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2"}, 1050 | ] 1051 | 1052 | [[package]] 1053 | name = "pygments" 1054 | version = "2.19.2" 1055 | requires_python = ">=3.8" 1056 | summary = "Pygments is a syntax highlighting package written in Python." 1057 | files = [ 1058 | {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"}, 1059 | {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"}, 1060 | ] 1061 | 1062 | [[package]] 1063 | name = "pyproject-api" 1064 | version = "1.10.0" 1065 | requires_python = ">=3.10" 1066 | summary = "API to interact with the python pyproject.toml based projects" 1067 | dependencies = [ 1068 | "packaging>=25", 1069 | "tomli>=2.3; python_version < \"3.11\"", 1070 | ] 1071 | files = [ 1072 | {file = "pyproject_api-1.10.0-py3-none-any.whl", hash = "sha256:8757c41a79c0f4ab71b99abed52b97ecf66bd20b04fa59da43b5840bac105a09"}, 1073 | {file = "pyproject_api-1.10.0.tar.gz", hash = "sha256:40c6f2d82eebdc4afee61c773ed208c04c19db4c4a60d97f8d7be3ebc0bbb330"}, 1074 | ] 1075 | 1076 | [[package]] 1077 | name = "pytest" 1078 | version = "7.4.4" 1079 | requires_python = ">=3.7" 1080 | summary = "pytest: simple powerful testing with Python" 1081 | dependencies = [ 1082 | "colorama; sys_platform == \"win32\"", 1083 | "exceptiongroup>=1.0.0rc8; python_version < \"3.11\"", 1084 | "importlib-metadata>=0.12; python_version < \"3.8\"", 1085 | "iniconfig", 1086 | "packaging", 1087 | "pluggy<2.0,>=0.12", 1088 | "tomli>=1.0.0; python_version < \"3.11\"", 1089 | ] 1090 | files = [ 1091 | {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, 1092 | {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, 1093 | ] 1094 | 1095 | [[package]] 1096 | name = "pytest-mypy" 1097 | version = "0.10.3" 1098 | requires_python = ">=3.6" 1099 | summary = "Mypy static type checker plugin for Pytest" 1100 | dependencies = [ 1101 | "attrs>=19.0", 1102 | "filelock>=3.0", 1103 | "mypy>=0.500; python_version < \"3.8\"", 1104 | "mypy>=0.700; python_version >= \"3.8\" and python_version < \"3.9\"", 1105 | "mypy>=0.780; python_version >= \"3.9\" and python_version < \"3.11\"", 1106 | "mypy>=0.900; python_version >= \"3.11\"", 1107 | "pytest>=4.6; python_version >= \"3.6\" and python_version < \"3.10\"", 1108 | "pytest>=6.2; python_version >= \"3.10\"", 1109 | ] 1110 | files = [ 1111 | {file = "pytest-mypy-0.10.3.tar.gz", hash = "sha256:f8458f642323f13a2ca3e2e61509f7767966b527b4d8adccd5032c3e7b4fd3db"}, 1112 | {file = "pytest_mypy-0.10.3-py3-none-any.whl", hash = "sha256:7638d0d3906848fc1810cb2f5cc7fceb4cc5c98524aafcac58f28620e3102053"}, 1113 | ] 1114 | 1115 | [[package]] 1116 | name = "pywin32-ctypes" 1117 | version = "0.2.3" 1118 | requires_python = ">=3.6" 1119 | summary = "A (partial) reimplementation of pywin32 using ctypes/cffi" 1120 | files = [ 1121 | {file = "pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755"}, 1122 | {file = "pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8"}, 1123 | ] 1124 | 1125 | [[package]] 1126 | name = "pyxdg" 1127 | version = "0.28" 1128 | summary = "PyXDG contains implementations of freedesktop.org standards in python." 1129 | files = [ 1130 | {file = "pyxdg-0.28-py2.py3-none-any.whl", hash = "sha256:bdaf595999a0178ecea4052b7f4195569c1ff4d344567bccdc12dfdf02d545ab"}, 1131 | {file = "pyxdg-0.28.tar.gz", hash = "sha256:3267bb3074e934df202af2ee0868575484108581e6f3cb006af1da35395e88b4"}, 1132 | ] 1133 | 1134 | [[package]] 1135 | name = "readme-renderer" 1136 | version = "44.0" 1137 | requires_python = ">=3.9" 1138 | summary = "readme_renderer is a library for rendering readme descriptions for Warehouse" 1139 | dependencies = [ 1140 | "Pygments>=2.5.1", 1141 | "docutils>=0.21.2", 1142 | "nh3>=0.2.14", 1143 | ] 1144 | files = [ 1145 | {file = "readme_renderer-44.0-py3-none-any.whl", hash = "sha256:2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151"}, 1146 | {file = "readme_renderer-44.0.tar.gz", hash = "sha256:8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1"}, 1147 | ] 1148 | 1149 | [[package]] 1150 | name = "requests" 1151 | version = "2.32.5" 1152 | requires_python = ">=3.9" 1153 | summary = "Python HTTP for Humans." 1154 | dependencies = [ 1155 | "certifi>=2017.4.17", 1156 | "charset-normalizer<4,>=2", 1157 | "idna<4,>=2.5", 1158 | "urllib3<3,>=1.21.1", 1159 | ] 1160 | files = [ 1161 | {file = "requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6"}, 1162 | {file = "requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf"}, 1163 | ] 1164 | 1165 | [[package]] 1166 | name = "requests-toolbelt" 1167 | version = "1.0.0" 1168 | requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 1169 | summary = "A utility belt for advanced users of python-requests" 1170 | dependencies = [ 1171 | "requests<3.0.0,>=2.0.1", 1172 | ] 1173 | files = [ 1174 | {file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"}, 1175 | {file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"}, 1176 | ] 1177 | 1178 | [[package]] 1179 | name = "rfc3986" 1180 | version = "2.0.0" 1181 | requires_python = ">=3.7" 1182 | summary = "Validating URI References per RFC 3986" 1183 | files = [ 1184 | {file = "rfc3986-2.0.0-py2.py3-none-any.whl", hash = "sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd"}, 1185 | {file = "rfc3986-2.0.0.tar.gz", hash = "sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c"}, 1186 | ] 1187 | 1188 | [[package]] 1189 | name = "rich" 1190 | version = "14.2.0" 1191 | requires_python = ">=3.8.0" 1192 | summary = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" 1193 | dependencies = [ 1194 | "markdown-it-py>=2.2.0", 1195 | "pygments<3.0.0,>=2.13.0", 1196 | ] 1197 | files = [ 1198 | {file = "rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd"}, 1199 | {file = "rich-14.2.0.tar.gz", hash = "sha256:73ff50c7c0c1c77c8243079283f4edb376f0f6442433aecb8ce7e6d0b92d1fe4"}, 1200 | ] 1201 | 1202 | [[package]] 1203 | name = "secretstorage" 1204 | version = "3.5.0" 1205 | requires_python = ">=3.10" 1206 | summary = "Python bindings to FreeDesktop.org Secret Service API" 1207 | dependencies = [ 1208 | "cryptography>=2.0", 1209 | "jeepney>=0.6", 1210 | ] 1211 | files = [ 1212 | {file = "secretstorage-3.5.0-py3-none-any.whl", hash = "sha256:0ce65888c0725fcb2c5bc0fdb8e5438eece02c523557ea40ce0703c266248137"}, 1213 | {file = "secretstorage-3.5.0.tar.gz", hash = "sha256:f04b8e4689cbce351744d5537bf6b1329c6fc68f91fa666f60a380edddcd11be"}, 1214 | ] 1215 | 1216 | [[package]] 1217 | name = "setuptools" 1218 | version = "80.9.0" 1219 | requires_python = ">=3.9" 1220 | summary = "Easily download, build, install, upgrade, and uninstall Python packages" 1221 | files = [ 1222 | {file = "setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922"}, 1223 | {file = "setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c"}, 1224 | ] 1225 | 1226 | [[package]] 1227 | name = "sortedcontainers" 1228 | version = "2.4.0" 1229 | summary = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" 1230 | files = [ 1231 | {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"}, 1232 | {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, 1233 | ] 1234 | 1235 | [[package]] 1236 | name = "toml" 1237 | version = "0.10.2" 1238 | requires_python = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 1239 | summary = "Python Library for Tom's Obvious, Minimal Language" 1240 | files = [ 1241 | {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, 1242 | {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, 1243 | ] 1244 | 1245 | [[package]] 1246 | name = "tomli" 1247 | version = "2.3.0" 1248 | requires_python = ">=3.8" 1249 | summary = "A lil' TOML parser" 1250 | files = [ 1251 | {file = "tomli-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45"}, 1252 | {file = "tomli-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba"}, 1253 | {file = "tomli-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d1381caf13ab9f300e30dd8feadb3de072aeb86f1d34a8569453ff32a7dea4bf"}, 1254 | {file = "tomli-2.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a0e285d2649b78c0d9027570d4da3425bdb49830a6156121360b3f8511ea3441"}, 1255 | {file = "tomli-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a154a9ae14bfcf5d8917a59b51ffd5a3ac1fd149b71b47a3a104ca4edcfa845"}, 1256 | {file = "tomli-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:74bf8464ff93e413514fefd2be591c3b0b23231a77f901db1eb30d6f712fc42c"}, 1257 | {file = "tomli-2.3.0-cp311-cp311-win32.whl", hash = "sha256:00b5f5d95bbfc7d12f91ad8c593a1659b6387b43f054104cda404be6bda62456"}, 1258 | {file = "tomli-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:4dc4ce8483a5d429ab602f111a93a6ab1ed425eae3122032db7e9acf449451be"}, 1259 | {file = "tomli-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d7d86942e56ded512a594786a5ba0a5e521d02529b3826e7761a05138341a2ac"}, 1260 | {file = "tomli-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:73ee0b47d4dad1c5e996e3cd33b8a76a50167ae5f96a2607cbe8cc773506ab22"}, 1261 | {file = "tomli-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:792262b94d5d0a466afb5bc63c7daa9d75520110971ee269152083270998316f"}, 1262 | {file = "tomli-2.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f195fe57ecceac95a66a75ac24d9d5fbc98ef0962e09b2eddec5d39375aae52"}, 1263 | {file = "tomli-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e31d432427dcbf4d86958c184b9bfd1e96b5b71f8eb17e6d02531f434fd335b8"}, 1264 | {file = "tomli-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b0882799624980785240ab732537fcfc372601015c00f7fc367c55308c186f6"}, 1265 | {file = "tomli-2.3.0-cp312-cp312-win32.whl", hash = "sha256:ff72b71b5d10d22ecb084d345fc26f42b5143c5533db5e2eaba7d2d335358876"}, 1266 | {file = "tomli-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:1cb4ed918939151a03f33d4242ccd0aa5f11b3547d0cf30f7c74a408a5b99878"}, 1267 | {file = "tomli-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5192f562738228945d7b13d4930baffda67b69425a7f0da96d360b0a3888136b"}, 1268 | {file = "tomli-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:be71c93a63d738597996be9528f4abe628d1adf5e6eb11607bc8fe1a510b5dae"}, 1269 | {file = "tomli-2.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4665508bcbac83a31ff8ab08f424b665200c0e1e645d2bd9ab3d3e557b6185b"}, 1270 | {file = "tomli-2.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4021923f97266babc6ccab9f5068642a0095faa0a51a246a6a02fccbb3514eaf"}, 1271 | {file = "tomli-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4ea38c40145a357d513bffad0ed869f13c1773716cf71ccaa83b0fa0cc4e42f"}, 1272 | {file = "tomli-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad805ea85eda330dbad64c7ea7a4556259665bdf9d2672f5dccc740eb9d3ca05"}, 1273 | {file = "tomli-2.3.0-cp313-cp313-win32.whl", hash = "sha256:97d5eec30149fd3294270e889b4234023f2c69747e555a27bd708828353ab606"}, 1274 | {file = "tomli-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0c95ca56fbe89e065c6ead5b593ee64b84a26fca063b5d71a1122bf26e533999"}, 1275 | {file = "tomli-2.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cebc6fe843e0733ee827a282aca4999b596241195f43b4cc371d64fc6639da9e"}, 1276 | {file = "tomli-2.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4c2ef0244c75aba9355561272009d934953817c49f47d768070c3c94355c2aa3"}, 1277 | {file = "tomli-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c22a8bf253bacc0cf11f35ad9808b6cb75ada2631c2d97c971122583b129afbc"}, 1278 | {file = "tomli-2.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0eea8cc5c5e9f89c9b90c4896a8deefc74f518db5927d0e0e8d4a80953d774d0"}, 1279 | {file = "tomli-2.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b74a0e59ec5d15127acdabd75ea17726ac4c5178ae51b85bfe39c4f8a278e879"}, 1280 | {file = "tomli-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b5870b50c9db823c595983571d1296a6ff3e1b88f734a4c8f6fc6188397de005"}, 1281 | {file = "tomli-2.3.0-cp314-cp314-win32.whl", hash = "sha256:feb0dacc61170ed7ab602d3d972a58f14ee3ee60494292d384649a3dc38ef463"}, 1282 | {file = "tomli-2.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:b273fcbd7fc64dc3600c098e39136522650c49bca95df2d11cf3b626422392c8"}, 1283 | {file = "tomli-2.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:940d56ee0410fa17ee1f12b817b37a4d4e4dc4d27340863cc67236c74f582e77"}, 1284 | {file = "tomli-2.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f85209946d1fe94416debbb88d00eb92ce9cd5266775424ff81bc959e001acaf"}, 1285 | {file = "tomli-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a56212bdcce682e56b0aaf79e869ba5d15a6163f88d5451cbde388d48b13f530"}, 1286 | {file = "tomli-2.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5f3ffd1e098dfc032d4d3af5c0ac64f6d286d98bc148698356847b80fa4de1b"}, 1287 | {file = "tomli-2.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5e01decd096b1530d97d5d85cb4dff4af2d8347bd35686654a004f8dea20fc67"}, 1288 | {file = "tomli-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8a35dd0e643bb2610f156cca8db95d213a90015c11fee76c946aa62b7ae7e02f"}, 1289 | {file = "tomli-2.3.0-cp314-cp314t-win32.whl", hash = "sha256:a1f7f282fe248311650081faafa5f4732bdbfef5d45fe3f2e702fbc6f2d496e0"}, 1290 | {file = "tomli-2.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:70a251f8d4ba2d9ac2542eecf008b3c8a9fc5c3f9f02c56a9d7952612be2fdba"}, 1291 | {file = "tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b"}, 1292 | {file = "tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549"}, 1293 | ] 1294 | 1295 | [[package]] 1296 | name = "tox" 1297 | version = "4.32.0" 1298 | requires_python = ">=3.10" 1299 | summary = "tox is a generic virtualenv management and test command line tool" 1300 | dependencies = [ 1301 | "cachetools>=6.2", 1302 | "chardet>=5.2", 1303 | "colorama>=0.4.6", 1304 | "filelock>=3.20", 1305 | "packaging>=25", 1306 | "platformdirs>=4.5", 1307 | "pluggy>=1.6", 1308 | "pyproject-api>=1.9.1", 1309 | "tomli>=2.3; python_version < \"3.11\"", 1310 | "typing-extensions>=4.15; python_version < \"3.11\"", 1311 | "virtualenv>=20.34", 1312 | ] 1313 | files = [ 1314 | {file = "tox-4.32.0-py3-none-any.whl", hash = "sha256:451e81dc02ba8d1ed20efd52ee409641ae4b5d5830e008af10fe8823ef1bd551"}, 1315 | {file = "tox-4.32.0.tar.gz", hash = "sha256:1ad476b5f4d3679455b89a992849ffc3367560bbc7e9495ee8a3963542e7c8ff"}, 1316 | ] 1317 | 1318 | [[package]] 1319 | name = "tox-gh-actions" 1320 | version = "3.5.0" 1321 | requires_python = ">=3.7" 1322 | summary = "Seamless integration of tox into GitHub Actions" 1323 | dependencies = [ 1324 | "tox<5,>=4", 1325 | ] 1326 | files = [ 1327 | {file = "tox_gh_actions-3.5.0-py3-none-any.whl", hash = "sha256:070790114c92f4c94337047515ca5e077ceb269a5cb9366e0a0b3440a024eca1"}, 1328 | {file = "tox_gh_actions-3.5.0.tar.gz", hash = "sha256:cc8e148c4513042e5019973e5672594c3df241b035e7fb550f6f778588110051"}, 1329 | ] 1330 | 1331 | [[package]] 1332 | name = "tox-pdm" 1333 | version = "0.5.0" 1334 | requires_python = ">=3.7" 1335 | summary = "A plugin for tox that utilizes PDM as the package manager and installer" 1336 | dependencies = [ 1337 | "toml>=0.10", 1338 | "tox>=3.18.0", 1339 | ] 1340 | files = [ 1341 | {file = "tox-pdm-0.5.0.tar.gz", hash = "sha256:45531c80c9670e7d9a0109ec5ab0d9add0492db4b41aa4ae0f20b295e4fd60e3"}, 1342 | {file = "tox_pdm-0.5.0-py3-none-any.whl", hash = "sha256:0075ff9ed47ee13dc6e55122e6da121661a5553a633b8dd278013fbee81e4bb4"}, 1343 | ] 1344 | 1345 | [[package]] 1346 | name = "traitlets" 1347 | version = "5.14.3" 1348 | requires_python = ">=3.8" 1349 | summary = "Traitlets Python configuration system" 1350 | files = [ 1351 | {file = "traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"}, 1352 | {file = "traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7"}, 1353 | ] 1354 | 1355 | [[package]] 1356 | name = "twine" 1357 | version = "6.2.0" 1358 | requires_python = ">=3.9" 1359 | summary = "Collection of utilities for publishing packages on PyPI" 1360 | dependencies = [ 1361 | "id", 1362 | "importlib-metadata>=3.6; python_version < \"3.10\"", 1363 | "keyring>=21.2.0; platform_machine != \"ppc64le\" and platform_machine != \"s390x\"", 1364 | "packaging>=24.0", 1365 | "readme-renderer>=35.0", 1366 | "requests-toolbelt!=0.9.0,>=0.8.0", 1367 | "requests>=2.20", 1368 | "rfc3986>=1.4.0", 1369 | "rich>=12.0.0", 1370 | "urllib3>=1.26.0", 1371 | ] 1372 | files = [ 1373 | {file = "twine-6.2.0-py3-none-any.whl", hash = "sha256:418ebf08ccda9a8caaebe414433b0ba5e25eb5e4a927667122fbe8f829f985d8"}, 1374 | {file = "twine-6.2.0.tar.gz", hash = "sha256:e5ed0d2fd70c9959770dce51c8f39c8945c574e18173a7b81802dab51b4b75cf"}, 1375 | ] 1376 | 1377 | [[package]] 1378 | name = "typing-extensions" 1379 | version = "4.15.0" 1380 | requires_python = ">=3.9" 1381 | summary = "Backported and Experimental Type Hints for Python 3.9+" 1382 | files = [ 1383 | {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, 1384 | {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, 1385 | ] 1386 | 1387 | [[package]] 1388 | name = "urllib3" 1389 | version = "2.5.0" 1390 | requires_python = ">=3.9" 1391 | summary = "HTTP library with thread-safe connection pooling, file post, and more." 1392 | files = [ 1393 | {file = "urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc"}, 1394 | {file = "urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760"}, 1395 | ] 1396 | 1397 | [[package]] 1398 | name = "virtualenv" 1399 | version = "20.35.4" 1400 | requires_python = ">=3.8" 1401 | summary = "Virtual Python Environment builder" 1402 | dependencies = [ 1403 | "distlib<1,>=0.3.7", 1404 | "filelock<4,>=3.12.2", 1405 | "importlib-metadata>=6.6; python_version < \"3.8\"", 1406 | "platformdirs<5,>=3.9.1", 1407 | "typing-extensions>=4.13.2; python_version < \"3.11\"", 1408 | ] 1409 | files = [ 1410 | {file = "virtualenv-20.35.4-py3-none-any.whl", hash = "sha256:c21c9cede36c9753eeade68ba7d523529f228a403463376cf821eaae2b650f1b"}, 1411 | {file = "virtualenv-20.35.4.tar.gz", hash = "sha256:643d3914d73d3eeb0c552cbb12d7e82adf0e504dbf86a3182f8771a153a1971c"}, 1412 | ] 1413 | 1414 | [[package]] 1415 | name = "wcwidth" 1416 | version = "0.2.14" 1417 | requires_python = ">=3.6" 1418 | summary = "Measures the displayed width of unicode strings in a terminal" 1419 | files = [ 1420 | {file = "wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1"}, 1421 | {file = "wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605"}, 1422 | ] 1423 | 1424 | [[package]] 1425 | name = "zipp" 1426 | version = "3.23.0" 1427 | requires_python = ">=3.9" 1428 | summary = "Backport of pathlib-compatible object wrapper for zip files" 1429 | files = [ 1430 | {file = "zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e"}, 1431 | {file = "zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166"}, 1432 | ] 1433 | --------------------------------------------------------------------------------