From 241aae830d1932ed5adca9245c7c45af91012ed2 Mon Sep 17 00:00:00 2001 From: ran Date: Sun, 10 Aug 2025 16:48:36 +0800 Subject: [PATCH 1/2] chore: codes format --- .github/workflows/publish.yml | 18 +- .github/workflows/test.yml | 16 +- .pre-commit-config.yaml | 14 +- CONTRIBUTING.md | 4 +- README.md | 36 +-- action_dispatch/__init__.py | 9 +- action_dispatch/action_dispatcher.py | 18 +- action_dispatch/exceptions.py | 8 +- build_package.py | 14 +- pyproject.toml | 4 +- requirements-dev-frozen.txt | 409 --------------------------- requirements-dev-simple.txt | 8 - requirements-dev.txt | 112 ++++++-- requirements-frozen.txt | 3 - requirements.txt | 6 +- tests/README.md | 10 +- tests/main.py | 4 +- tests/test_action_dispatcher.py | 2 +- tests/test_exceptions.py | 2 +- tests/test_integration.py | 13 +- uv.lock | 13 + 21 files changed, 197 insertions(+), 526 deletions(-) delete mode 100644 requirements-dev-frozen.txt delete mode 100644 requirements-dev-simple.txt delete mode 100644 requirements-frozen.txt diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 7058414..91367c1 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -7,23 +7,23 @@ on: jobs: build: runs-on: ubuntu-latest - + steps: - uses: actions/checkout@v4 - + - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.x' - + - name: Install build dependencies run: | python -m pip install --upgrade pip pip install build - + - name: Build package run: python -m build - + - name: Store the distribution packages uses: actions/upload-artifact@v4 with: @@ -40,14 +40,14 @@ jobs: url: https://pypi.org/p/action-dispatch permissions: id-token: write # IMPORTANT: mandatory for trusted publishing - + steps: - name: Download all the dists uses: actions/download-artifact@v4 with: name: python-package-distributions path: dist/ - + - name: Publish to PyPI uses: pypa/gh-action-pypi-publish@release/v1 @@ -60,14 +60,14 @@ jobs: url: https://test.pypi.org/p/action-dispatch permissions: id-token: write # IMPORTANT: mandatory for trusted publishing - + steps: - name: Download all the dists uses: actions/download-artifact@v4 with: name: python-package-distributions path: dist/ - + - name: Publish to TestPyPI uses: pypa/gh-action-pypi-publish@release/v1 with: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8e74262..099fbda 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,40 +13,40 @@ jobs: matrix: os: [ubuntu-latest, windows-latest, macos-latest] python-version: ['3.9', '3.10', '3.11', '3.12'] - + steps: - uses: actions/checkout@v4 - + - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - + - name: Install dependencies run: | python -m pip install --upgrade pip pip install -e ".[dev]" - + - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names flake8 action_dispatch --count --select=E9,F63,F7,F82 --show-source --statistics # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide flake8 action_dispatch --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - + - name: Type check with mypy run: | mypy action_dispatch - + - name: Test with unittest run: | python -m unittest discover tests -v - + - name: Test with coverage run: | coverage run -m unittest discover tests coverage xml - + - name: Upload coverage to Codecov uses: codecov/codecov-action@v3 with: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 78127d9..b678ecc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v6.0.0 hooks: - id: check-yaml - id: end-of-file-fixer @@ -10,26 +10,28 @@ repos: - id: check-json - repo: https://github.com/psf/black - rev: 23.3.0 + rev: 25.1.0 hooks: - id: black language_version: python3 - repo: https://github.com/pycqa/flake8 - rev: 6.0.0 + rev: 7.3.0 hooks: - id: flake8 additional_dependencies: [flake8-docstrings] + args: ["--max-line-length=88", "--extend-ignore=E203,W503,D100,D101,D102,D104,D107,D200,D401"] - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.3.0 + rev: v1.17.1 hooks: - id: mypy - additional_dependencies: [types-all] + additional_dependencies: [types-setuptools, types-requests] args: [--strict, --ignore-missing-imports] + exclude: ^tests/ - repo: https://github.com/pycqa/isort - rev: 5.12.0 + rev: 6.0.1 hooks: - id: isort args: ["--profile", "black"] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4533ca7..99cd1db 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -139,10 +139,10 @@ def test_feature_description(self): """Test that the feature works as expected.""" # Arrange setup_test_data() - + # Act result = perform_action() - + # Assert self.assertEqual(result, expected_value) ``` diff --git a/README.md b/README.md index 09080b6..4745ab0 100644 --- a/README.md +++ b/README.md @@ -9,9 +9,9 @@ A powerful and flexible Python library for multi-dimensional action dispatching. ## Features -**Multi-dimensional Routing** - Dispatch based on multiple context attributes simultaneously -**Dynamic Handler Registration** - Register handlers using decorators or programmatically -**Flexible Context Matching** - Support for exact matches and fallback strategies +**Multi-dimensional Routing** - Dispatch based on multiple context attributes simultaneously +**Dynamic Handler Registration** - Register handlers using decorators or programmatically +**Flexible Context Matching** - Support for exact matches and fallback strategies ## Installation @@ -34,7 +34,7 @@ dispatcher = ActionDispatcher(['role', 'environment']) def admin_create_user(params): return f"Admin creating user: {params.get('username')}" -@dispatcher.handler("create_user", role="manager") +@dispatcher.handler("create_user", role="manager") def manager_create_user(params): return f"Manager creating user: {params.get('username')}" @@ -57,15 +57,15 @@ print(result) # "Admin creating user: john" ```python dispatcher = ActionDispatcher(['role', 'environment', 'feature_flag']) -@dispatcher.handler("process_payment", - role="admin", - environment="production", +@dispatcher.handler("process_payment", + role="admin", + environment="production", feature_flag="new_payment_system") def new_payment_handler(params): return "Processing with new payment system" -@dispatcher.handler("process_payment", - role="admin", +@dispatcher.handler("process_payment", + role="admin", environment="production") def default_payment_handler(params): return "Processing with default system" @@ -132,7 +132,7 @@ def get_users_admin_v2(params): "permissions": ["read", "write", "delete"] } -@api_dispatcher.handler("get_users", role="user", api_version="v2") +@api_dispatcher.handler("get_users", role="user", api_version="v2") def get_users_regular_v2(params): return { "users": get_user_own_data(params['context_object']), @@ -143,7 +143,7 @@ def get_users_regular_v2(params): def api_get_users(request): try: result = api_dispatcher.dispatch( - request.user, + request.user, "get_users", request_id=request.id ) @@ -157,14 +157,14 @@ def api_get_users(request): ```python service_dispatcher = ActionDispatcher(['environment', 'service_version']) -@service_dispatcher.handler("process_order", - environment="production", +@service_dispatcher.handler("process_order", + environment="production", service_version="v2") def process_order_prod_v2(params): # Use production database and new algorithm return production_order_processor.process(params['order_data']) -@service_dispatcher.handler("process_order", +@service_dispatcher.handler("process_order", environment="staging") def process_order_staging(params): # Use staging database with verbose logging @@ -177,8 +177,8 @@ def process_order_staging(params): plugin_dispatcher = ActionDispatcher(['plugin_type', 'version']) # Plugins can register their handlers -@plugin_dispatcher.handler("transform_data", - plugin_type="image_processor", +@plugin_dispatcher.handler("transform_data", + plugin_type="image_processor", version="2.0") def image_transform_v2(params): return enhanced_image_transform(params['data']) @@ -214,7 +214,7 @@ Decorator to register a global handler that works across all contexts. #### `register(action, handler, **kwargs)` Programmatically register a handler. -- `action` (str): Action name +- `action` (str): Action name - `handler` (callable): Handler function - `**kwargs`: Dimension values for routing @@ -276,7 +276,7 @@ python -m unittest tests.test_action_dispatcher.TestActionDispatcher -v # Format code black action_dispatch tests -# Lint code +# Lint code flake8 action_dispatch tests # Type checking diff --git a/action_dispatch/__init__.py b/action_dispatch/__init__.py index 5ce5c8e..a094ea1 100644 --- a/action_dispatch/__init__.py +++ b/action_dispatch/__init__.py @@ -1,8 +1,7 @@ -""" -Action Dispatch - A flexible action dispatching system with multi-dimensional routing capabilities. +"""Action Dispatch - Multi-dimensional routing system. -A powerful Python library that provides dynamic action dispatching based on context dimensions -such as user roles, environments, API versions, and any custom attributes. +A Python library providing dynamic action dispatching based on context +dimensions like user roles, environments, API versions, and custom attributes. Key Features: - Multi-dimensional routing @@ -33,9 +32,9 @@ from .action_dispatcher import ActionDispatcher from .exceptions import ( ActionDispatchError, - InvalidDimensionError, HandlerNotFoundError, InvalidActionError, + InvalidDimensionError, ) __version__ = "0.1.0" diff --git a/action_dispatch/action_dispatcher.py b/action_dispatch/action_dispatcher.py index 8a08eb1..392eb37 100644 --- a/action_dispatch/action_dispatcher.py +++ b/action_dispatch/action_dispatcher.py @@ -1,13 +1,13 @@ -from functools import partial -from collections import defaultdict import warnings -from typing import Any, Callable, Dict, List, Optional, Union +from collections import defaultdict +from functools import partial +from typing import Any, Callable, Optional, Union try: from .exceptions import ( - InvalidDimensionError, HandlerNotFoundError, InvalidActionError, + InvalidDimensionError, ) except ImportError: pass @@ -21,7 +21,8 @@ class ActionDispatcher: def __init__(self, dimensions: Optional[list[str]] = None) -> None: if dimensions is not None and not isinstance(dimensions, list): warnings.warn( - f"ActionDispatcher dimensions should be a list, got {type(dimensions).__name__}. Setting to empty list." + f"ActionDispatcher dimensions should be a list, got " + f"{type(dimensions).__name__}. Setting to empty list." ) self.dimensions = [] else: @@ -44,10 +45,9 @@ def _create_dynamic_methods(self) -> None: def decorator_factory( dimensions: list[str], ) -> Callable[[str], Callable[..., Callable[..., Any]]]: - def decorator( - action: str, **scope_kwargs: Any - ) -> Callable[ - [Callable[[dict[str, Any]], Any]], Callable[[dict[str, Any]], Any] + def decorator(action: str, **scope_kwargs: Any) -> Callable[ + [Callable[[dict[str, Any]], Any]], + Callable[[dict[str, Any]], Any], ]: def wrapper( func: Callable[[dict[str, Any]], Any], diff --git a/action_dispatch/exceptions.py b/action_dispatch/exceptions.py index 0bd57b3..74644c0 100644 --- a/action_dispatch/exceptions.py +++ b/action_dispatch/exceptions.py @@ -12,7 +12,7 @@ class ActionDispatchError(Exception): class InvalidDimensionError(ActionDispatchError): """Raised when an invalid dimension parameter is provided.""" - def __init__(self, dimension, available_dimensions): + def __init__(self, dimension: str, available_dimensions: list[str]) -> None: self.dimension = dimension self.available_dimensions = available_dimensions super().__init__( @@ -24,7 +24,7 @@ def __init__(self, dimension, available_dimensions): class HandlerNotFoundError(ActionDispatchError): """Raised when no handler is found for a given action and rules.""" - def __init__(self, action, rules): + def __init__(self, action: str, rules: dict[str, str]) -> None: self.action = action self.rules = rules super().__init__(f"No handler found for action '{action}' with rules {rules}") @@ -33,5 +33,7 @@ def __init__(self, action, rules): class InvalidActionError(ActionDispatchError): """Raised when an invalid action name is provided.""" - def __init__(self, message="Action name must be provided for dispatching."): + def __init__( + self, message: str = "Action name must be provided for dispatching." + ) -> None: super().__init__(message) diff --git a/build_package.py b/build_package.py index 6239ab5..39eccc9 100644 --- a/build_package.py +++ b/build_package.py @@ -8,11 +8,11 @@ from pathlib import Path -def run_command(cmd, description): +def run_command(cmd: str, description: str) -> bool: """Run a shell command and print status.""" print(f"šŸ”§ {description}...") try: - result = subprocess.run(cmd, shell=True, check=True, capture_output=True, text=True) + subprocess.run(cmd, shell=True, check=True, capture_output=True, text=True) print(f"āœ… {description} completed successfully") return True except subprocess.CalledProcessError as e: @@ -21,27 +21,27 @@ def run_command(cmd, description): return False -def main(): +def main() -> None: """Main build process.""" print("šŸš€ Building action-dispatch package...\n") - + # Change to project root project_root = Path(__file__).parent subprocess.run(f"cd {project_root}", shell=True) - + steps = [ ("uv run python -m unittest discover tests", "Running tests"), ("uv run black action_dispatch tests", "Formatting code"), ("uv run python -m build", "Building package"), ] - + all_passed = True for cmd, description in steps: if not run_command(cmd, description): all_passed = False break print() - + if all_passed: print("šŸŽ‰ Package build completed successfully!") print("\nšŸ“¦ Build artifacts:") diff --git a/pyproject.toml b/pyproject.toml index a75cb6f..449276b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,7 @@ maintainers = [ ] keywords = [ "dispatch", - "routing", + "routing", "action", "handler", "middleware", @@ -49,6 +49,7 @@ dev = [ "coverage>=7.0", "black>=22.0", "flake8>=5.0", + "isort>=5.0", "mypy>=1.0", "pre-commit>=2.20", ] @@ -125,5 +126,6 @@ disallow_untyped_defs = false [dependency-groups] dev = [ "build>=1.2.2.post1", + "isort>=5.0", "twine>=6.1.0", ] diff --git a/requirements-dev-frozen.txt b/requirements-dev-frozen.txt deleted file mode 100644 index a96f85e..0000000 --- a/requirements-dev-frozen.txt +++ /dev/null @@ -1,409 +0,0 @@ -# This file was autogenerated by uv via the following command: -# uv export --format requirements-txt --dev --e . -backports-tarfile==1.2.0 ; python_full_version < '3.12' and platform_machine != 'ppc64le' and platform_machine != 's390x' \ - --hash=sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34 \ - --hash=sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991 - # via jaraco-context -build==1.2.2.post1 \ - --hash=sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5 \ - --hash=sha256:b36993e92ca9375a219c99e606a122ff365a760a2d4bba0caa09bd5278b608b7 -certifi==2025.7.14 \ - --hash=sha256:6b31f564a415d79ee77df69d757bb49a5bb53bd9f756cbbe24394ffd6fc1f4b2 \ - --hash=sha256:8ea99dbdfaaf2ba2f9bac77b9249ef62ec5218e7c2b2e903378ed5fccf765995 - # via requests -cffi==1.17.1 ; platform_machine != 'ppc64le' and platform_machine != 's390x' and platform_python_implementation != 'PyPy' and sys_platform == 'linux' \ - --hash=sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8 \ - --hash=sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1 \ - --hash=sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36 \ - --hash=sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824 \ - --hash=sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8 \ - --hash=sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17 \ - --hash=sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc \ - --hash=sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3 \ - --hash=sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed \ - --hash=sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702 \ - --hash=sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1 \ - --hash=sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8 \ - --hash=sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6 \ - --hash=sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d \ - --hash=sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e \ - --hash=sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be \ - --hash=sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c \ - --hash=sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683 \ - --hash=sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9 \ - --hash=sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595 \ - --hash=sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0 \ - --hash=sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41 \ - --hash=sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6 \ - --hash=sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6 \ - --hash=sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3 \ - --hash=sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93 \ - --hash=sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e \ - --hash=sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4 \ - --hash=sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964 \ - --hash=sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576 \ - --hash=sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3 \ - --hash=sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3 \ - --hash=sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff \ - --hash=sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5 \ - --hash=sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd \ - --hash=sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f \ - --hash=sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5 \ - --hash=sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9 \ - --hash=sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382 \ - --hash=sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a \ - --hash=sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4 \ - --hash=sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99 \ - --hash=sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87 \ - --hash=sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b - # via cryptography -charset-normalizer==3.4.2 \ - --hash=sha256:005fa3432484527f9732ebd315da8da8001593e2cf46a3d817669f062c3d9ed4 \ - --hash=sha256:046595208aae0120559a67693ecc65dd75d46f7bf687f159127046628178dc45 \ - --hash=sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7 \ - --hash=sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0 \ - --hash=sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7 \ - --hash=sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d \ - --hash=sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0 \ - --hash=sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db \ - --hash=sha256:24498ba8ed6c2e0b56d4acbf83f2d989720a93b41d712ebd4f4979660db4417b \ - --hash=sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b \ - --hash=sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8 \ - --hash=sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff \ - --hash=sha256:3c21d4fca343c805a52c0c78edc01e3477f6dd1ad7c47653241cf2a206d4fc58 \ - --hash=sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e \ - --hash=sha256:43e0933a0eff183ee85833f341ec567c0980dae57c464d8a508e1b2ceb336471 \ - --hash=sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148 \ - --hash=sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a \ - --hash=sha256:50bf98d5e563b83cc29471fa114366e6806bc06bc7a25fd59641e41445327836 \ - --hash=sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e \ - --hash=sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63 \ - --hash=sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c \ - --hash=sha256:6333b3aa5a12c26b2a4d4e7335a28f1475e0e5e17d69d55141ee3cab736f66d1 \ - --hash=sha256:65c981bdbd3f57670af8b59777cbfae75364b483fa8a9f420f08094531d54a01 \ - --hash=sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366 \ - --hash=sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5 \ - --hash=sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c \ - --hash=sha256:70f7172939fdf8790425ba31915bfbe8335030f05b9913d7ae00a87d4395620a \ - --hash=sha256:721c76e84fe669be19c5791da68232ca2e05ba5185575086e384352e2c309597 \ - --hash=sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b \ - --hash=sha256:75d10d37a47afee94919c4fab4c22b9bc2a8bf7d4f46f87363bcf0573f3ff4f5 \ - --hash=sha256:76af085e67e56c8816c3ccf256ebd136def2ed9654525348cfa744b6802b69eb \ - --hash=sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0 \ - --hash=sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941 \ - --hash=sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0 \ - --hash=sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86 \ - --hash=sha256:8272b73e1c5603666618805fe821edba66892e2870058c94c53147602eab29c7 \ - --hash=sha256:82d8fd25b7f4675d0c47cf95b594d4e7b158aca33b76aa63d07186e13c0e0ab7 \ - --hash=sha256:844da2b5728b5ce0e32d863af26f32b5ce61bc4273a9c720a9f3aa9df73b1455 \ - --hash=sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6 \ - --hash=sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0 \ - --hash=sha256:982bb1e8b4ffda883b3d0a521e23abcd6fd17418f6d2c4118d257a10199c0ce3 \ - --hash=sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1 \ - --hash=sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6 \ - --hash=sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981 \ - --hash=sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c \ - --hash=sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980 \ - --hash=sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645 \ - --hash=sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7 \ - --hash=sha256:aaf27faa992bfee0264dc1f03f4c75e9fcdda66a519db6b957a3f826e285cf12 \ - --hash=sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd \ - --hash=sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef \ - --hash=sha256:b3daeac64d5b371dea99714f08ffc2c208522ec6b06fbc7866a450dd446f5c0f \ - --hash=sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2 \ - --hash=sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d \ - --hash=sha256:c72fbbe68c6f32f251bdc08b8611c7b3060612236e960ef848e0a517ddbe76c5 \ - --hash=sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3 \ - --hash=sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd \ - --hash=sha256:d11b54acf878eef558599658b0ffca78138c8c3655cf4f3a4a673c437e67732e \ - --hash=sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214 \ - --hash=sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd \ - --hash=sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a \ - --hash=sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c \ - --hash=sha256:dc7039885fa1baf9be153a0626e337aa7ec8bf96b0128605fb0d77788ddc1681 \ - --hash=sha256:dccab8d5fa1ef9bfba0590ecf4d46df048d18ffe3eec01eeb73a42e0d9e7a8ba \ - --hash=sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f \ - --hash=sha256:e45ba65510e2647721e35323d6ef54c7974959f6081b58d4ef5d87c60c84919a \ - --hash=sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28 \ - --hash=sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691 \ - --hash=sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82 \ - --hash=sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a \ - --hash=sha256:e8323a9b031aa0393768b87f04b4164a40037fb2a3c11ac06a03ffecd3618027 \ - --hash=sha256:e92fca20c46e9f5e1bb485887d074918b13543b1c2a1185e69bb8d17ab6236a7 \ - --hash=sha256:eb30abc20df9ab0814b5a2524f23d75dcf83cde762c161917a2b4b7b55b1e518 \ - --hash=sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf \ - --hash=sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b \ - --hash=sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9 \ - --hash=sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544 \ - --hash=sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509 \ - --hash=sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a \ - --hash=sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f - # via requests -colorama==0.4.6 ; os_name == 'nt' \ - --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \ - --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6 - # via build -cryptography==45.0.5 ; platform_machine != 'ppc64le' and platform_machine != 's390x' and sys_platform == 'linux' \ - --hash=sha256:0027d566d65a38497bc37e0dd7c2f8ceda73597d2ac9ba93810204f56f52ebc7 \ - --hash=sha256:12e55281d993a793b0e883066f590c1ae1e802e3acb67f8b442e721e475e6463 \ - --hash=sha256:14d96584701a887763384f3c47f0ca7c1cce322aa1c31172680eb596b890ec30 \ - --hash=sha256:2089cc8f70a6e454601525e5bf2779e665d7865af002a5dec8d14e561002e135 \ - --hash=sha256:3a264aae5f7fbb089dbc01e0242d3b67dffe3e6292e1f5182122bdf58e65215d \ - --hash=sha256:3af26738f2db354aafe492fb3869e955b12b2ef2e16908c8b9cb928128d42c57 \ - --hash=sha256:3fcfbefc4a7f332dece7272a88e410f611e79458fab97b5efe14e54fe476f4fd \ - --hash=sha256:460f8c39ba66af7db0545a8c6f2eabcbc5a5528fc1cf6c3fa9a1e44cec33385e \ - --hash=sha256:57c816dfbd1659a367831baca4b775b2a5b43c003daf52e9d57e1d30bc2e1b0e \ - --hash=sha256:5aa1e32983d4443e310f726ee4b071ab7569f58eedfdd65e9675484a4eb67bd1 \ - --hash=sha256:6ff8728d8d890b3dda5765276d1bc6fb099252915a2cd3aff960c4c195745dd0 \ - --hash=sha256:7259038202a47fdecee7e62e0fd0b0738b6daa335354396c6ddebdbe1206af2a \ - --hash=sha256:72e76caa004ab63accdf26023fccd1d087f6d90ec6048ff33ad0445abf7f605a \ - --hash=sha256:7760c1c2e1a7084153a0f68fab76e754083b126a47d0117c9ed15e69e2103492 \ - --hash=sha256:9024beb59aca9d31d36fcdc1604dd9bbeed0a55bface9f1908df19178e2f116e \ - --hash=sha256:91098f02ca81579c85f66df8a588c78f331ca19089763d733e34ad359f474174 \ - --hash=sha256:982518cd64c54fcada9d7e5cf28eabd3ee76bd03ab18e08a48cad7e8b6f31b18 \ - --hash=sha256:9b4cf6318915dccfe218e69bbec417fdd7c7185aa7aab139a2c0beb7468c89f0 \ - --hash=sha256:ad0caded895a00261a5b4aa9af828baede54638754b51955a0ac75576b831b27 \ - --hash=sha256:b8fa8b0a35a9982a3c60ec79905ba5bb090fc0b9addcfd3dc2dd04267e45f25e \ - --hash=sha256:bd4c45986472694e5121084c6ebbd112aa919a25e783b87eb95953c9573906d6 \ - --hash=sha256:be97d3a19c16a9be00edf79dca949c8fa7eff621763666a145f9f9535a5d7f42 \ - --hash=sha256:c648025b6840fe62e57107e0a25f604db740e728bd67da4f6f060f03017d5097 \ - --hash=sha256:d05a38884db2ba215218745f0781775806bde4f32e07b135348355fe8e4991d9 \ - --hash=sha256:dd420e577921c8c2d31289536c386aaa30140b473835e97f83bc71ea9d2baf2d \ - --hash=sha256:e6c00130ed423201c5bc5544c23359141660b07999ad82e34e7bb8f882bb78e0 \ - --hash=sha256:e74d30ec9c7cb2f404af331d5b4099a9b322a8a6b25c4632755c8757345baac5 - # via secretstorage -docutils==0.20.1 ; python_full_version < '3.9' \ - --hash=sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6 \ - --hash=sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b - # via readme-renderer -docutils==0.21.2 ; python_full_version >= '3.9' \ - --hash=sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f \ - --hash=sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2 - # via readme-renderer -id==1.5.0 \ - --hash=sha256:292cb8a49eacbbdbce97244f47a97b4c62540169c976552e497fd57df0734c1d \ - --hash=sha256:f1434e1cef91f2cbb8a4ec64663d5a23b9ed43ef44c4c957d02583d61714c658 - # via twine -idna==3.10 \ - --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ - --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 - # via requests -importlib-metadata==8.5.0 ; python_full_version < '3.9' \ - --hash=sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b \ - --hash=sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7 - # via - # build - # keyring - # twine -importlib-metadata==8.7.0 ; (python_full_version >= '3.9' and python_full_version < '3.10.2' and platform_machine == 'ppc64le') or (python_full_version >= '3.9' and python_full_version < '3.10.2' and platform_machine == 's390x') or (python_full_version >= '3.9' and python_full_version < '3.12' and platform_machine != 'ppc64le' and platform_machine != 's390x') \ - --hash=sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000 \ - --hash=sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd - # via - # build - # keyring - # twine -importlib-resources==6.4.5 ; python_full_version < '3.9' and platform_machine != 'ppc64le' and platform_machine != 's390x' \ - --hash=sha256:980862a1d16c9e147a59603677fa2aa5fd82b87f223b6cb870695bcfce830065 \ - --hash=sha256:ac29d5f956f01d5e4bb63102a5a19957f1b9175e45649977264a1416783bb717 - # via keyring -jaraco-classes==3.4.0 ; platform_machine != 'ppc64le' and platform_machine != 's390x' \ - --hash=sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd \ - --hash=sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790 - # via keyring -jaraco-context==6.0.1 ; platform_machine != 'ppc64le' and platform_machine != 's390x' \ - --hash=sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3 \ - --hash=sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4 - # via keyring -jaraco-functools==4.1.0 ; python_full_version < '3.9' and platform_machine != 'ppc64le' and platform_machine != 's390x' \ - --hash=sha256:70f7e0e2ae076498e212562325e805204fc092d7b4c17e0e86c959e249701a9d \ - --hash=sha256:ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649 - # via keyring -jaraco-functools==4.2.1 ; python_full_version >= '3.9' and platform_machine != 'ppc64le' and platform_machine != 's390x' \ - --hash=sha256:590486285803805f4b1f99c60ca9e94ed348d4added84b74c7a12885561e524e \ - --hash=sha256:be634abfccabce56fa3053f8c7ebe37b682683a4ee7793670ced17bab0087353 - # via keyring -jeepney==0.9.0 ; platform_machine != 'ppc64le' and platform_machine != 's390x' and sys_platform == 'linux' \ - --hash=sha256:97e5714520c16fc0a45695e5365a2e11b81ea79bba796e26f9f1d178cb182683 \ - --hash=sha256:cf0e9e845622b81e4a28df94c40345400256ec608d0e55bb8a3feaa9163f5732 - # via - # keyring - # secretstorage -keyring==25.5.0 ; python_full_version < '3.9' and platform_machine != 'ppc64le' and platform_machine != 's390x' \ - --hash=sha256:4c753b3ec91717fe713c4edd522d625889d8973a349b0e582622f49766de58e6 \ - --hash=sha256:e67f8ac32b04be4714b42fe84ce7dad9c40985b9ca827c592cc303e7c26d9741 - # via twine -keyring==25.6.0 ; python_full_version >= '3.9' and platform_machine != 'ppc64le' and platform_machine != 's390x' \ - --hash=sha256:0b39998aa941431eb3d9b0d4b2460bc773b9df6fed7621c2dfb291a7e0187a66 \ - --hash=sha256:552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd - # via twine -markdown-it-py==3.0.0 \ - --hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \ - --hash=sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb - # via rich -mdurl==0.1.2 \ - --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \ - --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba - # via markdown-it-py -more-itertools==10.5.0 ; python_full_version < '3.9' and platform_machine != 'ppc64le' and platform_machine != 's390x' \ - --hash=sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef \ - --hash=sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6 - # via - # jaraco-classes - # jaraco-functools -more-itertools==10.7.0 ; python_full_version >= '3.9' and platform_machine != 'ppc64le' and platform_machine != 's390x' \ - --hash=sha256:9fddd5403be01a94b204faadcff459ec3568cf110265d3c54323e1e866ad29d3 \ - --hash=sha256:d43980384673cb07d2f7d2d918c616b30c659c089ee23953f601d6609c67510e - # via - # jaraco-classes - # jaraco-functools -nh3==0.3.0 \ - --hash=sha256:0649464ac8eee018644aacbc103874ccbfac80e3035643c3acaab4287e36e7f5 \ - --hash=sha256:16f8670201f7e8e0e05ed1a590eb84bfa51b01a69dd5caf1d3ea57733de6a52f \ - --hash=sha256:1adeb1062a1c2974bc75b8d1ecb014c5fd4daf2df646bbe2831f7c23659793f9 \ - --hash=sha256:37d3003d98dedca6cd762bf88f2e70b67f05100f6b949ffe540e189cc06887f9 \ - --hash=sha256:389d93d59b8214d51c400fb5b07866c2a4f79e4e14b071ad66c92184fec3a392 \ - --hash=sha256:3f1b4f8a264a0c86ea01da0d0c390fe295ea0bcacc52c2103aca286f6884f518 \ - --hash=sha256:423201bbdf3164a9e09aa01e540adbb94c9962cc177d5b1cbb385f5e1e79216e \ - --hash=sha256:634e34e6162e0408e14fb61d5e69dbaea32f59e847cfcfa41b66100a6b796f62 \ - --hash=sha256:6d68fa277b4a3cf04e5c4b84dd0c6149ff7d56c12b3e3fab304c525b850f613d \ - --hash=sha256:7275fdffaab10cc5801bf026e3c089d8de40a997afc9e41b981f7ac48c5aa7d5 \ - --hash=sha256:7852f038a054e0096dac12b8141191e02e93e0b4608c4b993ec7d4ffafea4e49 \ - --hash=sha256:7c915060a2c8131bef6a29f78debc29ba40859b6dbe2362ef9e5fd44f11487c2 \ - --hash=sha256:80fe20171c6da69c7978ecba33b638e951b85fb92059259edd285ff108b82a6d \ - --hash=sha256:a537ece1bf513e5a88d8cff8a872e12fe8d0f42ef71dd15a5e7520fecd191bbb \ - --hash=sha256:af5aa8127f62bbf03d68f67a956627b1bd0469703a35b3dad28d0c1195e6c7fb \ - --hash=sha256:b0612ccf5de8a480cf08f047b08f9d3fecc12e63d2ee91769cb19d7290614c23 \ - --hash=sha256:ba0caa8aa184196daa6e574d997a33867d6d10234018012d35f86d46024a2a95 \ - --hash=sha256:bae63772408fd63ad836ec569a7c8f444dd32863d0c67f6e0b25ebbd606afa95 \ - --hash=sha256:c7a32a7f0d89f7d30cb8f4a84bdbd56d1eb88b78a2434534f62c71dac538c450 \ - --hash=sha256:ce5e7185599f89b0e391e2f29cc12dc2e206167380cea49b33beda4891be2fe1 \ - --hash=sha256:d8ba24cb31525492ea71b6aac11a4adac91d828aadeff7c4586541bf5dc34d2f \ - --hash=sha256:d97d3efd61404af7e5721a0e74d81cdbfc6e5f97e11e731bb6d090e30a7b62b2 \ - --hash=sha256:e90883f9f85288f423c77b3f5a6f4486375636f25f793165112679a7b6363b35 \ - --hash=sha256:e9e6a7e4d38f7e8dda9edd1433af5170c597336c1a74b4693c5cb75ab2b30f2a \ - --hash=sha256:ec6cfdd2e0399cb79ba4dcffb2332b94d9696c52272ff9d48a630c5dca5e325a \ - --hash=sha256:f416c35efee3e6a6c9ab7716d9e57aa0a49981be915963a82697952cba1353e1 - # via readme-renderer -packaging==25.0 \ - --hash=sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484 \ - --hash=sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f - # via - # build - # twine -pycparser==2.22 ; platform_machine != 'ppc64le' and platform_machine != 's390x' and platform_python_implementation != 'PyPy' and sys_platform == 'linux' \ - --hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \ - --hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc - # via cffi -pygments==2.19.2 \ - --hash=sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887 \ - --hash=sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b - # via - # readme-renderer - # rich -pyproject-hooks==1.2.0 \ - --hash=sha256:1e859bd5c40fae9448642dd871adf459e5e2084186e8d2c2a79a824c970da1f8 \ - --hash=sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913 - # via build -pywin32-ctypes==0.2.3 ; platform_machine != 'ppc64le' and platform_machine != 's390x' and sys_platform == 'win32' \ - --hash=sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8 \ - --hash=sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755 - # via keyring -readme-renderer==43.0 ; python_full_version < '3.9' \ - --hash=sha256:1818dd28140813509eeed8d62687f7cd4f7bad90d4db586001c5dc09d4fde311 \ - --hash=sha256:19db308d86ecd60e5affa3b2a98f017af384678c63c88e5d4556a380e674f3f9 - # via twine -readme-renderer==44.0 ; python_full_version >= '3.9' \ - --hash=sha256:2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151 \ - --hash=sha256:8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1 - # via twine -requests==2.32.4 \ - --hash=sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c \ - --hash=sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422 - # via - # id - # requests-toolbelt - # twine -requests-toolbelt==1.0.0 \ - --hash=sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6 \ - --hash=sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06 - # via twine -rfc3986==2.0.0 \ - --hash=sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd \ - --hash=sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c - # via twine -rich==14.0.0 \ - --hash=sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0 \ - --hash=sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725 - # via twine -secretstorage==3.3.3 ; platform_machine != 'ppc64le' and platform_machine != 's390x' and sys_platform == 'linux' \ - --hash=sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77 \ - --hash=sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99 - # via keyring -tomli==2.2.1 ; python_full_version < '3.11' \ - --hash=sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6 \ - --hash=sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd \ - --hash=sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c \ - --hash=sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b \ - --hash=sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8 \ - --hash=sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6 \ - --hash=sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77 \ - --hash=sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff \ - --hash=sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea \ - --hash=sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192 \ - --hash=sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249 \ - --hash=sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee \ - --hash=sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4 \ - --hash=sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98 \ - --hash=sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8 \ - --hash=sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4 \ - --hash=sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281 \ - --hash=sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744 \ - --hash=sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69 \ - --hash=sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13 \ - --hash=sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140 \ - --hash=sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e \ - --hash=sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e \ - --hash=sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc \ - --hash=sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff \ - --hash=sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec \ - --hash=sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2 \ - --hash=sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222 \ - --hash=sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106 \ - --hash=sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272 \ - --hash=sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a \ - --hash=sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7 - # via build -twine==6.1.0 \ - --hash=sha256:a47f973caf122930bf0fbbf17f80b83bc1602c9ce393c7845f289a3001dc5384 \ - --hash=sha256:be324f6272eff91d07ee93f251edf232fc647935dd585ac003539b42404a8dbd -typing-extensions==4.13.2 ; python_full_version < '3.9' \ - --hash=sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c \ - --hash=sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef - # via rich -typing-extensions==4.14.1 ; python_full_version >= '3.9' and python_full_version < '3.11' \ - --hash=sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36 \ - --hash=sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76 - # via rich -urllib3==2.2.3 ; python_full_version < '3.9' \ - --hash=sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac \ - --hash=sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9 - # via - # requests - # twine -urllib3==2.5.0 ; python_full_version >= '3.9' \ - --hash=sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760 \ - --hash=sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc - # via - # requests - # twine -zipp==3.20.2 ; python_full_version < '3.9' \ - --hash=sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350 \ - --hash=sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29 - # via - # importlib-metadata - # importlib-resources -zipp==3.23.0 ; (python_full_version >= '3.9' and python_full_version < '3.10.2' and platform_machine == 'ppc64le') or (python_full_version >= '3.9' and python_full_version < '3.10.2' and platform_machine == 's390x') or (python_full_version >= '3.9' and python_full_version < '3.12' and platform_machine != 'ppc64le' and platform_machine != 's390x') \ - --hash=sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e \ - --hash=sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166 - # via importlib-metadata diff --git a/requirements-dev-simple.txt b/requirements-dev-simple.txt deleted file mode 100644 index 3932bb4..0000000 --- a/requirements-dev-simple.txt +++ /dev/null @@ -1,8 +0,0 @@ -black==25.1.0 -build==1.2.2.post1 -coverage==7.9.2 -flake8==7.3.0 -mypy==1.17.0 -mypy-extensions==1.1.0 -pre-commit==4.2.0 -twine==6.1.0 diff --git a/requirements-dev.txt b/requirements-dev.txt index 54af22f..f41a58f 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,22 +1,90 @@ -# Development dependencies for action-dispatch -# Install with: pip install -r requirements-dev.txt - -# Code formatting and linting -black>=22.0 -flake8>=5.0 -mypy>=1.0 - -# Testing and coverage -coverage>=7.0 - -# Build and packaging -build>=1.2.2.post1 -twine>=6.1.0 - -# Pre-commit hooks -pre-commit>=2.20 - -# Documentation (optional) -sphinx>=5.0 -sphinx-rtd-theme>=1.0 -myst-parser>=0.18 +# This file was autogenerated by uv via the following command: +# uv export --format requirements-txt --dev --no-hashes +-e . +backports-tarfile==1.2.0 ; python_full_version < '3.12' and platform_machine != 'ppc64le' and platform_machine != 's390x' + # via jaraco-context +build==1.2.2.post1 +certifi==2025.7.14 + # via requests +cffi==1.17.1 ; platform_machine != 'ppc64le' and platform_machine != 's390x' and platform_python_implementation != 'PyPy' and sys_platform == 'linux' + # via cryptography +charset-normalizer==3.4.2 + # via requests +colorama==0.4.6 ; os_name == 'nt' + # via build +cryptography==45.0.5 ; platform_machine != 'ppc64le' and platform_machine != 's390x' and sys_platform == 'linux' + # via secretstorage +docutils==0.21.2 + # via readme-renderer +id==1.5.0 + # via twine +idna==3.10 + # via requests +importlib-metadata==8.7.0 ; (python_full_version < '3.10.2' and platform_machine == 'ppc64le') or (python_full_version < '3.10.2' and platform_machine == 's390x') or (python_full_version < '3.12' and platform_machine != 'ppc64le' and platform_machine != 's390x') + # via + # build + # keyring + # twine +isort==6.0.1 +jaraco-classes==3.4.0 ; platform_machine != 'ppc64le' and platform_machine != 's390x' + # via keyring +jaraco-context==6.0.1 ; platform_machine != 'ppc64le' and platform_machine != 's390x' + # via keyring +jaraco-functools==4.2.1 ; platform_machine != 'ppc64le' and platform_machine != 's390x' + # via keyring +jeepney==0.9.0 ; platform_machine != 'ppc64le' and platform_machine != 's390x' and sys_platform == 'linux' + # via + # keyring + # secretstorage +keyring==25.6.0 ; platform_machine != 'ppc64le' and platform_machine != 's390x' + # via twine +markdown-it-py==3.0.0 + # via rich +mdurl==0.1.2 + # via markdown-it-py +more-itertools==10.7.0 ; platform_machine != 'ppc64le' and platform_machine != 's390x' + # via + # jaraco-classes + # jaraco-functools +nh3==0.3.0 + # via readme-renderer +packaging==25.0 + # via + # build + # twine +pycparser==2.22 ; platform_machine != 'ppc64le' and platform_machine != 's390x' and platform_python_implementation != 'PyPy' and sys_platform == 'linux' + # via cffi +pygments==2.19.2 + # via + # readme-renderer + # rich +pyproject-hooks==1.2.0 + # via build +pywin32-ctypes==0.2.3 ; platform_machine != 'ppc64le' and platform_machine != 's390x' and sys_platform == 'win32' + # via keyring +readme-renderer==44.0 + # via twine +requests==2.32.4 + # via + # id + # requests-toolbelt + # twine +requests-toolbelt==1.0.0 + # via twine +rfc3986==2.0.0 + # via twine +rich==14.0.0 + # via twine +secretstorage==3.3.3 ; platform_machine != 'ppc64le' and platform_machine != 's390x' and sys_platform == 'linux' + # via keyring +tomli==2.2.1 ; python_full_version < '3.11' + # via build +twine==6.1.0 +typing-extensions==4.14.1 ; python_full_version < '3.11' + # via rich +urllib3==2.5.0 + # via + # requests + # twine +zipp==3.23.0 ; (python_full_version < '3.10.2' and platform_machine == 'ppc64le') or (python_full_version < '3.10.2' and platform_machine == 's390x') or (python_full_version < '3.12' and platform_machine != 'ppc64le' and platform_machine != 's390x') + # via importlib-metadata diff --git a/requirements-frozen.txt b/requirements-frozen.txt deleted file mode 100644 index af7f506..0000000 --- a/requirements-frozen.txt +++ /dev/null @@ -1,3 +0,0 @@ -# This file was autogenerated by uv via the following command: -# uv export --format requirements-txt --no-dev --e . diff --git a/requirements.txt b/requirements.txt index e95239c..a21b146 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -# Production dependencies for action-dispatch -# This file lists the minimal runtime dependencies -# The package itself has no runtime dependencies +# This file was autogenerated by uv via the following command: +# uv export --format requirements-txt --no-dev --no-hashes +-e . diff --git a/tests/README.md b/tests/README.md index 9d1b911..7a47f5f 100644 --- a/tests/README.md +++ b/tests/README.md @@ -7,7 +7,7 @@ This document explains how to run tests for the action-dispatch library. The tests are organized into several modules: - `test_action_dispatcher.py` - Core functionality tests -- `test_exceptions.py` - Exception class tests +- `test_exceptions.py` - Exception class tests - `test_integration.py` - Integration and real-world scenario tests - `test_config.py` - Test configuration and utilities @@ -26,7 +26,7 @@ python -m tests.run_tests # Run only core ActionDispatcher tests python -m tests.run_tests test_action_dispatcher -# Run only exception tests +# Run only exception tests python -m tests.run_tests test_exceptions # Run only integration tests @@ -102,16 +102,16 @@ from exceptions import HandlerNotFoundError class MyCustomTest(unittest.TestCase): def setUp(self): self.dispatcher = ActionDispatcher(['role', 'environment']) - + def test_my_scenario(self): @self.dispatcher.handler("my_action", role="admin") def my_handler(params): return "success" - + class MockContext: role = "admin" environment = "production" - + result = self.dispatcher.dispatch(MockContext(), "my_action") self.assertEqual(result, "success") ``` diff --git a/tests/main.py b/tests/main.py index 715adc4..c397a75 100644 --- a/tests/main.py +++ b/tests/main.py @@ -3,9 +3,9 @@ Test runner script for action-dispatch library. """ -import unittest -import sys import os +import sys +import unittest # Add the parent directory to sys.path so we can import the library sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) diff --git a/tests/test_action_dispatcher.py b/tests/test_action_dispatcher.py index 94717dc..b44f069 100644 --- a/tests/test_action_dispatcher.py +++ b/tests/test_action_dispatcher.py @@ -8,9 +8,9 @@ from action_dispatch import ActionDispatcher from action_dispatch.exceptions import ( - InvalidDimensionError, HandlerNotFoundError, InvalidActionError, + InvalidDimensionError, ) diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index c6181da..ac8b69d 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -6,9 +6,9 @@ from action_dispatch.exceptions import ( ActionDispatchError, - InvalidDimensionError, HandlerNotFoundError, InvalidActionError, + InvalidDimensionError, ) diff --git a/tests/test_integration.py b/tests/test_integration.py index ef66c5a..d1e56c0 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -46,7 +46,8 @@ def create_user_manager(params): @self.dispatcher.handler("delete_user", role="admin", environment="production") def delete_user_admin_prod(params): - return f"Admin deleting user in production: {params.get('username', 'unknown')}" + username = params.get("username", "unknown") + return f"Admin deleting user in production: {username}" @self.dispatcher.handler("delete_user", role="admin", environment="staging") def delete_user_admin_staging(params): @@ -107,11 +108,11 @@ def test_environment_fallback(self): "debug_info", role="developer", environment="development" ) def debug_info_dev(params): - return f"Debug info for developer in development" + return "Debug info for developer in development" @env_dispatcher.handler("debug_info", role="admin", environment="development") def debug_info_admin_dev(params): - return f"Debug info for admin in development" + return "Debug info for admin in development" dev_user = MockUser("developer", "development") admin_dev = MockUser("admin", "development") @@ -279,7 +280,11 @@ def get_users_admin_v2(params): @dispatcher.handler("get_users", role="user", api_version="v2") def get_users_user_v2(params): - return {"users": ["limited_users"], "version": "v2", "role": "user"} + return { + "users": ["limited_users"], + "version": "v2", + "role": "user", + } admin_v1 = MockUser("admin") admin_v1.api_version = "v1" diff --git a/uv.lock b/uv.lock index 5efaae2..d0395e3 100644 --- a/uv.lock +++ b/uv.lock @@ -16,6 +16,7 @@ dev = [ { name = "black" }, { name = "coverage" }, { name = "flake8" }, + { name = "isort" }, { name = "mypy" }, { name = "pre-commit" }, ] @@ -31,6 +32,7 @@ docs = [ [package.dev-dependencies] dev = [ { name = "build" }, + { name = "isort" }, { name = "twine" }, ] @@ -39,6 +41,7 @@ requires-dist = [ { name = "black", marker = "extra == 'dev'", specifier = ">=22.0" }, { name = "coverage", marker = "extra == 'dev'", specifier = ">=7.0" }, { name = "flake8", marker = "extra == 'dev'", specifier = ">=5.0" }, + { name = "isort", marker = "extra == 'dev'", specifier = ">=5.0" }, { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.0" }, { name = "myst-parser", marker = "extra == 'docs'", specifier = ">=0.18" }, { name = "pre-commit", marker = "extra == 'dev'", specifier = ">=2.20" }, @@ -50,6 +53,7 @@ provides-extras = ["dev", "docs"] [package.metadata.requires-dev] dev = [ { name = "build", specifier = ">=1.2.2.post1" }, + { name = "isort", specifier = ">=5.0" }, { name = "twine", specifier = ">=6.1.0" }, ] @@ -535,6 +539,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/20/b0/36bd937216ec521246249be3bf9855081de4c5e06a0c9b4219dbeda50373/importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd", size = 27656, upload-time = "2025-04-27T15:29:00.214Z" }, ] +[[package]] +name = "isort" +version = "6.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b8/21/1e2a441f74a653a144224d7d21afe8f4169e6c7c20bb13aec3a2dc3815e0/isort-6.0.1.tar.gz", hash = "sha256:1cb5df28dfbc742e490c5e41bad6da41b805b0a8be7bc93cd0fb2a8a890ac450", size = 821955, upload-time = "2025-02-26T21:13:16.955Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/11/114d0a5f4dabbdcedc1125dee0888514c3c3b16d3e9facad87ed96fad97c/isort-6.0.1-py3-none-any.whl", hash = "sha256:2dc5d7f65c9678d94c88dfc29161a320eec67328bc97aad576874cb4be1e9615", size = 94186, upload-time = "2025-02-26T21:13:14.911Z" }, +] + [[package]] name = "jaraco-classes" version = "3.4.0" From 23f5d058afd5bbfb5cae879e7e0331b5e184e11c Mon Sep 17 00:00:00 2001 From: ran Date: Tue, 12 Aug 2025 22:23:09 +0800 Subject: [PATCH 2/2] chore: delete local `build_package` --- build_package.py | 59 ------------------------------------------------ 1 file changed, 59 deletions(-) delete mode 100644 build_package.py diff --git a/build_package.py b/build_package.py deleted file mode 100644 index 39eccc9..0000000 --- a/build_package.py +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env python3 -""" -Build script for action-dispatch package. -""" - -import subprocess -import sys -from pathlib import Path - - -def run_command(cmd: str, description: str) -> bool: - """Run a shell command and print status.""" - print(f"šŸ”§ {description}...") - try: - subprocess.run(cmd, shell=True, check=True, capture_output=True, text=True) - print(f"āœ… {description} completed successfully") - return True - except subprocess.CalledProcessError as e: - print(f"āŒ {description} failed:") - print(f" Error: {e.stderr}") - return False - - -def main() -> None: - """Main build process.""" - print("šŸš€ Building action-dispatch package...\n") - - # Change to project root - project_root = Path(__file__).parent - subprocess.run(f"cd {project_root}", shell=True) - - steps = [ - ("uv run python -m unittest discover tests", "Running tests"), - ("uv run black action_dispatch tests", "Formatting code"), - ("uv run python -m build", "Building package"), - ] - - all_passed = True - for cmd, description in steps: - if not run_command(cmd, description): - all_passed = False - break - print() - - if all_passed: - print("šŸŽ‰ Package build completed successfully!") - print("\nšŸ“¦ Build artifacts:") - print(" - dist/action_dispatch-*.whl") - print(" - dist/action_dispatch-*.tar.gz") - print("\nšŸš€ To publish to PyPI:") - print(" - Test: uv run twine upload --repository testpypi dist/*") - print(" - Prod: uv run twine upload dist/*") - else: - print("šŸ’„ Build failed!") - sys.exit(1) - - -if __name__ == "__main__": - main()