diff --git a/.github/workflows/basedpyright.yml b/.github/workflows/basedpyright.yml new file mode 100644 index 00000000..6fbd60b2 --- /dev/null +++ b/.github/workflows/basedpyright.yml @@ -0,0 +1,38 @@ +name: basedpyright + +on: + pull_request: + push: + branches: + - main + - develop + - feature-* + +jobs: + basedpyright: + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + packages: write + pull-requests: write + steps: + - uses: actions/checkout@v4 + - name: Install uv + uses: astral-sh/setup-uv@v6 + with: + version: 0.8.22 + python-version: 3.11 + enable-cache: true + cache-suffix: pre-commit + cache-dependency-glob: uv.lock + - name: Restore venv cache + uses: actions/cache@v4 + with: + path: | + .venv + key: ${{ runner.os }}-uv-${{ hashFiles('uv.lock') }} + - name: Synchronize project dependencies + run: uv sync --group dev + - name: Run basedpyright + run: uv run basedpyright diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index e5fd8908..d73dcfd3 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -32,11 +32,6 @@ jobs: path: | .venv key: ${{ runner.os }}-uv-${{ hashFiles('uv.lock') }} - - name: Restore mypy cache - uses: actions/cache@v4 - with: - path: .mypy_cache - key: mypy_cache|${{ hashFiles('pyproject.toml') }} - name: Restore pre-commit cache uses: actions/cache@v4 with: @@ -45,4 +40,6 @@ jobs: - name: Synchronize project dependencies run: uv sync --group dev - name: Run pre-commit checks - run: uv run pre-commit run --show-diff-on-failure --all-files --hook-stage manual + run: uv run pre-commit run --show-diff-on-failure --all-files + env: + SKIP: basedpyright diff --git a/.gitignore b/.gitignore index ad36eefe..c104834d 100644 --- a/.gitignore +++ b/.gitignore @@ -451,3 +451,5 @@ $RECYCLE.BIN/ # Profiling *.prof.txt *.speedscope.json + +!pyrightconfig.json diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 00000000..13566b81 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/git_toolbox_prj.xml b/.idea/git_toolbox_prj.xml new file mode 100644 index 00000000..02b915b8 --- /dev/null +++ b/.idea/git_toolbox_prj.xml @@ -0,0 +1,15 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 00000000..6be19167 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,3126 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 00000000..dd4c951e --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 00000000..d4adb71c --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 00000000..8c81df2c --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/pdfrest-python.iml b/.idea/pdfrest-python.iml new file mode 100644 index 00000000..4e4b5a76 --- /dev/null +++ b/.idea/pdfrest-python.iml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/pyright.xml b/.idea/pyright.xml new file mode 100644 index 00000000..692a0a1c --- /dev/null +++ b/.idea/pyright.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/.idea/ruff.xml b/.idea/ruff.xml new file mode 100644 index 00000000..f35d5ed9 --- /dev/null +++ b/.idea/ruff.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..a081b18c --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fe7b88e0..942e5c65 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -72,21 +72,12 @@ repos: rev: v0.24.3 hooks: - id: toml-sort-fix - - repo: https://github.com/pre-commit/mirrors-mypy - rev: "v1.18.2" - hooks: - - id: mypy - stages: [pre-push, manual] - name: mypy - additional_dependencies: - # Need pydantic to load the pydantic.mypy plugin - - pydantic>=2.12.0 - repo: https://github.com/astral-sh/uv-pre-commit # uv version. rev: 0.8.24 hooks: - id: uv-lock - - repo: https://github.com/RobertCraigie/pyright-python - rev: v1.1.406 + - repo: https://github.com/DetachHead/basedpyright-pre-commit-mirror + rev: 1.34.0 # or whatever the latest version is at the time hooks: - - id: pyright + - id: basedpyright diff --git a/noxfile.py b/noxfile.py index dd7ed111..8cdfc69c 100644 --- a/noxfile.py +++ b/noxfile.py @@ -11,8 +11,8 @@ def tests(session: nox.Session) -> None: # Define only custom flags parser = argparse.ArgumentParser(add_help=False) - parser.add_argument("--no-parallel", action="store_true") - parser.add_argument( + _ = parser.add_argument("--no-parallel", action="store_true") + _ = parser.add_argument( "-n", "--workers", "--numprocesses" ) # e.g., -n 4 to set workers custom, remaining = parser.parse_known_args(session.posargs) @@ -27,7 +27,7 @@ def tests(session: nox.Session) -> None: else: pytest_args[:0] = ["-n", "8", "--maxschedchunk", "2"] - session.run_install( + _ = session.run_install( "uv", "sync", "--no-default-groups", @@ -36,7 +36,7 @@ def tests(session: nox.Session) -> None: f"--python={session.virtualenv.location}", env={"UV_PROJECT_ENVIRONMENT": session.virtualenv.location}, ) - session.run( + _ = session.run( "pytest", "--cov=pdfrest", "--cov-report=term-missing", diff --git a/pyproject.toml b/pyproject.toml index 36d26e53..24154627 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,9 +22,7 @@ dev = [ "ruff>=0.6.9", "pytest>=8.3.3", "pytest-cov>=5.0.0", - "mypy>=1.18.2", "pip-audit>=2.7.3", - "pyright>=1.1.406", "pytest-md>=0.2.0", "pytest-emoji>=0.2.0", "pytest-dotenv>=0.5.2", @@ -32,89 +30,9 @@ dev = [ "pytest-rerunfailures>=16.0.1", "pytest-xdist>=3.8.0", "nox>=2025.5.1", + "basedpyright>=1.34.0", ] -[tool.mypy] -python_version = "3.10" -pretty = true -plugins = [ - "pydantic.mypy", -] -# Discover modules that were installed in the virtualenv -python_executable = ".venv/bin/python" -fixed_format_cache = true -ignore_missing_imports = false -follow_imports = "silent" -# Balanced strictness (not “strict = true”); catches many bugs without being overbearing -no_implicit_optional = true -check_untyped_defs = true -warn_unused_ignores = true -warn_redundant_casts = true -warn_return_any = true -warn_no_return = true -strict_equality = true -# Defaults here stay a bit lenient; ratchet up over time if desired -disallow_untyped_defs = false -disallow_incomplete_defs = false -disallow_untyped_calls = false -disallow_any_generics = false -implicit_reexport = true -namespace_packages = true -show_error_codes = true -# Typical project structure -packages = ["pdfrest"] # if using setuptools; or rely on src/ layout -exclude = '(build|dist|\.venv|scripts|examples|docs)' - -# Example: tighten src/, loosen tests/ -[[tool.mypy.overrides]] -module = ["pdfrest.*"] -disallow_untyped_defs = true -disallow_incomplete_defs = true - -[[tool.mypy.overrides]] -module = ["tests.*"] -disallow_untyped_defs = false -allow_redefinition = true - -[tool.pyright] -venvPath = "." -venv = ".venv" -typeCheckingMode = "standard" -pythonVersion = "3.10" -reportMissingTypeStubs = true -# mypy catches this, so catch it in pyright too -reportOptionalMemberAccess = true -# Sensible signal without being punitive; tune severities as needed -reportUnusedImport = "error" -reportUnusedVariable = "error" -reportUnknownMemberType = "warning" -reportUnknownArgumentType = "warning" -reportUnknownVariableType = "warning" -reportPrivateUsage = "error" -# Keep false positives low in typical library code -useLibraryCodeForTypes = true -# Project layout -include = ["src", "tests"] -exclude = [ - "**/.venv", - "build", - "dist", - "scripts", - "examples", - "docs", -] - -[[tool.pyright.executionEnvironments]] -root = "src" - -[[tool.pyright.executionEnvironments]] -root = "tests" -typeCheckingMode = "basic" -reportUnknownMemberType = "none" -reportUnknownArgumentType = "none" -reportUnknownVariableType = "none" -reportPrivateUsage = "none" - [tool.pytest.ini_options] minversion = "7.4" testpaths = ["tests"] @@ -185,6 +103,8 @@ trailing_comma_inline_array = true [tool.uv] keyring-provider = "subprocess" +no-build = true +no-binary-package = ["pdfrest"] [[tool.uv.index]] name = "cit-pypi" diff --git a/pyrightconfig.json b/pyrightconfig.json new file mode 100644 index 00000000..a1f10a43 --- /dev/null +++ b/pyrightconfig.json @@ -0,0 +1,37 @@ +{ + "include": ["src", "tests", "noxfile.py"], + "exclude": [ + "**/.venv", + "build", + "dist", + "scripts", + "examples", + "docs", + "**/node_modules", + "**/__pycache__" + ], + "pythonVersion": "3.10", + "reportImplicitStringConcatenation": "none", + "reportAny": "none", + "reportExplicitAny": "none", + "reportUnannotatedClassAttribute": "none", + "executionEnvironments": [ + { + "root": "noxfile.py" + }, + { + "root": "src" + }, + { + "root": "tests", + "reportUnknownLambdaType": "none", + "reportUnknownMemberType": "none", + "reportArgumentType": "none", + "reportUnknownArgumentType": "none", + "reportUnknownVariableType": "none", + "reportPrivateUsage": "none", + "reportUnusedCallResult": "none", + "reportPrivateLocalImportUsage": "none" + } + ] +} diff --git a/src/pdfrest/client.py b/src/pdfrest/client.py index 7cec145c..bf053ae7 100644 --- a/src/pdfrest/client.py +++ b/src/pdfrest/client.py @@ -43,6 +43,7 @@ ValidationError, field_validator, ) +from typing_extensions import override from .exceptions import ( PdfRestApiError, @@ -258,9 +259,6 @@ def _normalize_file_type(file_value: FileTypes) -> NormalizedFileTypes: normalized_content_type = ( str(content_type) if content_type is not None else None ) - if not isinstance(headers, Mapping): - msg = "Headers must be provided as a mapping of str keys to str values." - raise TypeError(msg) normalized_headers = _normalize_headers(headers) return ( normalized_filename, @@ -303,9 +301,6 @@ def _parse_path_spec(spec: FilePathTypes) -> tuple[Path, str | None, Mapping[str headers: Mapping[str, str] = {} elif length == 3: raw_path, content_type, headers = cast(FilePathTuple3, spec) - if not isinstance(headers, Mapping): - msg = "Headers must be provided as a mapping of str keys to str values." - raise TypeError(msg) else: msg = "File path tuples must contain a path plus optional content type and headers." raise TypeError(msg) @@ -441,8 +436,6 @@ class _BaseApiClient(Generic[ClientType]): """Shared logic between sync and async client variants.""" _config: _ClientConfig - _client: ClientType - _owns_http_client: bool def __init__( self, @@ -454,7 +447,7 @@ def __init__( max_retries: int = DEFAULT_MAX_RETRIES, ) -> None: self._logger = LOGGER - if not isinstance(max_retries, int) or max_retries < 0: + if max_retries < 0: msg = "max_retries must be a non-negative integer." raise PdfRestConfigurationError(msg) self._max_retries = max_retries @@ -585,7 +578,7 @@ def _validate_pdfrest_api_key(api_key: str, url: URL) -> None: msg = "pdfRest API keys must be 36 characters (UUID format)." raise PdfRestConfigurationError(msg) try: - uuid.UUID(api_key) + _ = uuid.UUID(api_key) except ValueError: msg = "pdfRest API keys must be valid UUID strings." raise PdfRestConfigurationError(msg) from None @@ -740,8 +733,6 @@ def _handle_response(self, response: httpx.Response) -> Any: request = response.request request_label = ( f"{getattr(request, 'method', 'UNKNOWN')} {getattr(request, 'url', '')}" - if request is not None - else "UNKNOWN" ) if response.is_success: if self._logger.isEnabledFor(logging.DEBUG): @@ -811,6 +802,7 @@ class _SyncApiClient(_BaseApiClient[httpx.Client]): """Internal synchronous client implementation.""" _client: httpx.Client + _owns_http_client: bool def __init__( self, @@ -1072,6 +1064,7 @@ class _AsyncApiClient(_BaseApiClient[httpx.AsyncClient]): """Internal asynchronous client implementation.""" _client: httpx.AsyncClient + _owns_http_client: bool def __init__( self, @@ -1523,7 +1516,7 @@ def create_from_urls( ) -> list[PdfRestFile]: """Upload one or more files by providing remote URLs.""" - normalized_urls = UploadURLs.model_validate({"url": urls}) # pyright: ignore[reportPrivateUsage] + normalized_urls = UploadURLs.model_validate({"url": urls}) request = self._client.prepare_request( "POST", "/upload", @@ -1627,7 +1620,7 @@ def write_bytes( try: with path.open("wb") as file_handle: for chunk in response.iter_bytes(): - file_handle.write(chunk) + _ = file_handle.write(chunk) finally: response.close() return path @@ -1901,7 +1894,7 @@ async def write_bytes( try: with path.open("wb") as file_handle: async for chunk in response.aiter_bytes(): - file_handle.write(chunk) + _ = file_handle.write(chunk) finally: await response.aclose() return path @@ -1950,10 +1943,12 @@ def __init__( ) self._files_client = _FilesClient(self) + @override def __enter__(self) -> PdfRestClient: - super().__enter__() + _ = super().__enter__() return self + @override def __exit__(self, exc_type: Any, exc: Any, traceback: Any) -> None: super().__exit__(exc_type, exc, traceback) @@ -2379,10 +2374,12 @@ def __init__( ) self._files_client = _AsyncFilesClient(self) + @override async def __aenter__(self) -> AsyncPdfRestClient: - await super().__aenter__() + _ = await super().__aenter__() return self + @override async def __aexit__(self, exc_type: Any, exc: Any, traceback: Any) -> None: await super().__aexit__(exc_type, exc, traceback) diff --git a/src/pdfrest/exceptions.py b/src/pdfrest/exceptions.py index 421c51d8..a3b68b0b 100644 --- a/src/pdfrest/exceptions.py +++ b/src/pdfrest/exceptions.py @@ -5,6 +5,7 @@ from typing import Any import httpx +from typing_extensions import override __all__ = ( "PdfRestApiError", @@ -65,6 +66,7 @@ def __init__( detail = message or f"pdfRest API returned status code {status_code}" super().__init__(detail) + @override def __str__(self) -> str: # pragma: no cover - mirrors Exception.__str__ base = super().__str__() if self.response_content is None: diff --git a/src/pdfrest/models/_internal.py b/src/pdfrest/models/_internal.py index 887bc4ad..7706e839 100644 --- a/src/pdfrest/models/_internal.py +++ b/src/pdfrest/models/_internal.py @@ -30,7 +30,7 @@ def _ensure_list(value: Any) -> Any: if value is None: return None if isinstance(value, list): - return value + return value # pyright: ignore[reportUnknownVariableType] if isinstance(value, Sequence) and not isinstance(value, (str, bytes, bytearray)): return list(value) return [value] @@ -80,7 +80,7 @@ def _split_comma_list(value: Any) -> Any: if isinstance(value, str): return value.split(",") if isinstance(value, list): - return value + return value # pyright: ignore[reportUnknownVariableType] if isinstance(value, Sequence) and not isinstance(value, (str, bytes, bytearray)): return list(value) msg = "Must be a comma separated string or a list of strings." @@ -98,12 +98,6 @@ def _split_comma_string(value: Any) -> list[Any] | None: raise ValueError(msg) -def _pdfrest_file_to_id(value: Any) -> Any: - if isinstance(value, PdfRestFile): - return value.id - return value - - def _serialize_as_first_file_id(value: list[PdfRestFile]) -> str: return str(value[0].id) @@ -144,7 +138,7 @@ def allowed_mime_types_validator( ) -> PdfRestFile | list[PdfRestFile]: if isinstance(value, list): for item in value: - allowed_mime_types_validator(item) + _ = allowed_mime_types_validator(item) return value if value.type not in combined_allowed_mime_types: msg = error_msg or f"The file type must be one of: {allowed_mime_types}" @@ -158,7 +152,7 @@ def _int_to_string(value: Any) -> Any: if isinstance(value, int): return str(value) if isinstance(value, list): - return [_int_to_string(item) for item in value] + return [_int_to_string(item) for item in value] # pyright: ignore[reportUnknownVariableType] return value @@ -435,13 +429,13 @@ class _PdfMergeItem(BaseModel): @classmethod def _transform_input(cls, data: Any) -> Any: if isinstance(data, tuple): - if len(data) != 2: + if len(data) != 2: # pyright: ignore[reportUnknownArgumentType] msg = ( "Tuple merge entries must contain exactly two items: (file, pages)." ) raise ValueError(msg) - file_candidate, pages = data - return {"file": file_candidate, "pages": pages} + file_candidate, pages = data # pyright: ignore[reportUnknownVariableType] + return {"file": file_candidate, "pages": pages} # pyright: ignore[reportUnknownVariableType] if isinstance(data, PdfRestFile): return {"file": data} return data diff --git a/src/pdfrest/models/public.py b/src/pdfrest/models/public.py index d572f6d6..da2c8893 100644 --- a/src/pdfrest/models/public.py +++ b/src/pdfrest/models/public.py @@ -15,7 +15,9 @@ Field, HttpUrl, ) +from pydantic.json_schema import JsonSchemaValue from pydantic_core import CoreSchema +from typing_extensions import override __all__ = ("PdfRestErrorResponse", "PdfRestFile", "PdfRestFileID", "UpResponse") @@ -47,9 +49,6 @@ class PdfRestFileID(str): ) def __new__(cls, value: str) -> PdfRestFileID: - if not isinstance(value, str): - msg = "PdfRestPrefixedUUID4 requires a str" - raise TypeError(msg) if not cls._PY_PATTERN.fullmatch(value): msg = ( "Invalid PdfRestPrefixedUUID4. Expected: " @@ -58,9 +57,11 @@ def __new__(cls, value: str) -> PdfRestFileID: raise ValueError(msg) return str.__new__(cls, value.lower()) + @override def __str__(self) -> str: return str.__str__(self) + @override def __repr__(self) -> str: return f"{self.__class__.__name__}({super().__repr__()})" @@ -88,7 +89,7 @@ def uuid_obj(self) -> _uuid.UUID: @classmethod def is_valid(cls, value: str) -> bool: """Quick validity check without constructing the object.""" - return isinstance(value, str) and bool(cls._PY_PATTERN.fullmatch(value)) + return bool(cls._PY_PATTERN.fullmatch(value)) @classmethod def from_parts( @@ -160,7 +161,9 @@ def to_class(v: Any) -> PdfRestFileID: ) @classmethod - def __get_pydantic_json_schema__(cls, core_schema: Any, handler: Any) -> dict: + def __get_pydantic_json_schema__( + cls, core_schema: Any, handler: Any + ) -> JsonSchemaValue: """ Provide a clean JSON Schema for OpenAPI/JSON Schema generators. """ diff --git a/tests/live/test_live_pdf_split_merge.py b/tests/live/test_live_pdf_split_merge.py index 351be410..979f7b1e 100644 --- a/tests/live/test_live_pdf_split_merge.py +++ b/tests/live/test_live_pdf_split_merge.py @@ -56,9 +56,6 @@ def _extract_merge_entry( return entry if isinstance(entry, dict): file = entry["file"] - if file is None: - msg = "PdfMergeDocument entries must include a 'file' key." - raise KeyError(msg) pages = entry.get("pages") selection: PdfPageSelection | Sequence[PdfPageSelection] = ( pages if pages is not None else "1-last" diff --git a/tests/test_client.py b/tests/test_client.py index 3c21bd8d..d02aed91 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -8,6 +8,7 @@ import httpx import pytest +from typing_extensions import override from pdfrest import ( AsyncPdfRestClient, @@ -53,10 +54,12 @@ class NonSeekableByteStream(BytesIO): def __init__(self, payload: bytes) -> None: super().__init__(payload) + @override def seek(self, *args: Any, **kwargs: Any) -> int: msg = "non-seekable" raise UnsupportedOperation(msg) + @override def tell(self) -> int: msg = "non-seekable" raise UnsupportedOperation(msg) @@ -234,7 +237,7 @@ def test_client_retries_on_server_error(monkeypatch: pytest.MonkeyPatch) -> None attempts = {"count": 0} - def handler(request: httpx.Request) -> httpx.Response: + def handler(request: httpx.Request) -> httpx.Response: # pyright: ignore[reportUnusedParameter] attempts["count"] += 1 if attempts["count"] < 3: return httpx.Response(500, json={"error": "try-again"}) @@ -408,7 +411,7 @@ async def fake_sleep(delay: float) -> None: attempts = {"count": 0} - async def handler(request: httpx.Request) -> httpx.Response: + async def handler(request: httpx.Request) -> httpx.Response: # pyright: ignore[reportUnusedParameter] attempts["count"] += 1 if attempts["count"] < 3: return httpx.Response(503, json={"error": "retry"}) diff --git a/tests/test_files.py b/tests/test_files.py index be718d7c..73a10bc0 100644 --- a/tests/test_files.py +++ b/tests/test_files.py @@ -12,6 +12,7 @@ import httpx import pytest import pytest_asyncio +from typing_extensions import override from pdfrest import AsyncPdfRestClient, PdfRestClient from pdfrest.models import PdfRestFile, PdfRestFileID @@ -26,12 +27,14 @@ def __init__(self, payload: bytes) -> None: self._payload = payload self._consumed = False + @override def __iter__(self) -> Iterator[bytes]: if self._consumed: return iter(()) self._consumed = True return iter((self._payload,)) + @override def close(self) -> None: # pragma: no cover - trivial ... @@ -41,11 +44,13 @@ def __init__(self, payload: bytes) -> None: self._payload = payload self._consumed = False + @override async def __aiter__(self): if not self._consumed: self._consumed = True yield self._payload + @override async def aclose(self) -> None: # pragma: no cover - trivial ... diff --git a/uv.lock b/uv.lock index 1a4b3243..716f8d50 100644 --- a/uv.lock +++ b/uv.lock @@ -53,6 +53,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl", hash = "sha256:0da0a936a8aeb554eccb426dc55af3ba63bcdc69fa1a600b5bb305413a4477b5", size = 12313, upload-time = "2025-07-02T02:27:14.263Z" }, ] +[[package]] +name = "basedpyright" +version = "1.34.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nodejs-wheel-binaries" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/77/ded02ba2b400807b291fa2b9d29ac7f473e86a45d1f5212d8276e9029107/basedpyright-1.34.0.tar.gz", hash = "sha256:7ae3b06f644fac15fdd14a00d0d1f12f92a8205ae1609aabd5a0799b1a68be1d", size = 22803348, upload-time = "2025-11-19T14:48:16.38Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/9e/ced31964ed49f06be6197bd530958b6ddca9a079a8d7ee0ee7429cae9e27/basedpyright-1.34.0-py3-none-any.whl", hash = "sha256:e76015c1ebb671d2c6d7fef8a12bc0f1b9d15d74e17847b7b95a3a66e187c70f", size = 11865958, upload-time = "2025-11-19T14:48:13.724Z" }, +] + [[package]] name = "boolean-py" version = "5.0" @@ -521,60 +533,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/81/f2/08ace4142eb281c12701fc3b93a10795e4d4dc7f753911d836675050f886/msgpack-1.1.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d99ef64f349d5ec3293688e91486c5fdb925ed03807f64d98d205d2713c60b46", size = 70868, upload-time = "2025-10-08T09:15:44.959Z" }, ] -[[package]] -name = "mypy" -version = "1.18.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mypy-extensions" }, - { name = "pathspec" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c0/77/8f0d0001ffad290cef2f7f216f96c814866248a0b92a722365ed54648e7e/mypy-1.18.2.tar.gz", hash = "sha256:06a398102a5f203d7477b2923dda3634c36727fa5c237d8f859ef90c42a9924b", size = 3448846, upload-time = "2025-09-19T00:11:10.519Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/03/6f/657961a0743cff32e6c0611b63ff1c1970a0b482ace35b069203bf705187/mypy-1.18.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c1eab0cf6294dafe397c261a75f96dc2c31bffe3b944faa24db5def4e2b0f77c", size = 12807973, upload-time = "2025-09-19T00:10:35.282Z" }, - { url = "https://files.pythonhosted.org/packages/10/e9/420822d4f661f13ca8900f5fa239b40ee3be8b62b32f3357df9a3045a08b/mypy-1.18.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7a780ca61fc239e4865968ebc5240bb3bf610ef59ac398de9a7421b54e4a207e", size = 11896527, upload-time = "2025-09-19T00:10:55.791Z" }, - { url = "https://files.pythonhosted.org/packages/aa/73/a05b2bbaa7005f4642fcfe40fb73f2b4fb6bb44229bd585b5878e9a87ef8/mypy-1.18.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:448acd386266989ef11662ce3c8011fd2a7b632e0ec7d61a98edd8e27472225b", size = 12507004, upload-time = "2025-09-19T00:11:05.411Z" }, - { url = "https://files.pythonhosted.org/packages/4f/01/f6e4b9f0d031c11ccbd6f17da26564f3a0f3c4155af344006434b0a05a9d/mypy-1.18.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f9e171c465ad3901dc652643ee4bffa8e9fef4d7d0eece23b428908c77a76a66", size = 13245947, upload-time = "2025-09-19T00:10:46.923Z" }, - { url = "https://files.pythonhosted.org/packages/d7/97/19727e7499bfa1ae0773d06afd30ac66a58ed7437d940c70548634b24185/mypy-1.18.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:592ec214750bc00741af1f80cbf96b5013d81486b7bb24cb052382c19e40b428", size = 13499217, upload-time = "2025-09-19T00:09:39.472Z" }, - { url = "https://files.pythonhosted.org/packages/9f/4f/90dc8c15c1441bf31cf0f9918bb077e452618708199e530f4cbd5cede6ff/mypy-1.18.2-cp310-cp310-win_amd64.whl", hash = "sha256:7fb95f97199ea11769ebe3638c29b550b5221e997c63b14ef93d2e971606ebed", size = 9766753, upload-time = "2025-09-19T00:10:49.161Z" }, - { url = "https://files.pythonhosted.org/packages/88/87/cafd3ae563f88f94eec33f35ff722d043e09832ea8530ef149ec1efbaf08/mypy-1.18.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:807d9315ab9d464125aa9fcf6d84fde6e1dc67da0b6f80e7405506b8ac72bc7f", size = 12731198, upload-time = "2025-09-19T00:09:44.857Z" }, - { url = "https://files.pythonhosted.org/packages/0f/e0/1e96c3d4266a06d4b0197ace5356d67d937d8358e2ee3ffac71faa843724/mypy-1.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:776bb00de1778caf4db739c6e83919c1d85a448f71979b6a0edd774ea8399341", size = 11817879, upload-time = "2025-09-19T00:09:47.131Z" }, - { url = "https://files.pythonhosted.org/packages/72/ef/0c9ba89eb03453e76bdac5a78b08260a848c7bfc5d6603634774d9cd9525/mypy-1.18.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1379451880512ffce14505493bd9fe469e0697543717298242574882cf8cdb8d", size = 12427292, upload-time = "2025-09-19T00:10:22.472Z" }, - { url = "https://files.pythonhosted.org/packages/1a/52/ec4a061dd599eb8179d5411d99775bec2a20542505988f40fc2fee781068/mypy-1.18.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1331eb7fd110d60c24999893320967594ff84c38ac6d19e0a76c5fd809a84c86", size = 13163750, upload-time = "2025-09-19T00:09:51.472Z" }, - { url = "https://files.pythonhosted.org/packages/c4/5f/2cf2ceb3b36372d51568f2208c021870fe7834cf3186b653ac6446511839/mypy-1.18.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3ca30b50a51e7ba93b00422e486cbb124f1c56a535e20eff7b2d6ab72b3b2e37", size = 13351827, upload-time = "2025-09-19T00:09:58.311Z" }, - { url = "https://files.pythonhosted.org/packages/c8/7d/2697b930179e7277529eaaec1513f8de622818696857f689e4a5432e5e27/mypy-1.18.2-cp311-cp311-win_amd64.whl", hash = "sha256:664dc726e67fa54e14536f6e1224bcfce1d9e5ac02426d2326e2bb4e081d1ce8", size = 9757983, upload-time = "2025-09-19T00:10:09.071Z" }, - { url = "https://files.pythonhosted.org/packages/07/06/dfdd2bc60c66611dd8335f463818514733bc763e4760dee289dcc33df709/mypy-1.18.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:33eca32dd124b29400c31d7cf784e795b050ace0e1f91b8dc035672725617e34", size = 12908273, upload-time = "2025-09-19T00:10:58.321Z" }, - { url = "https://files.pythonhosted.org/packages/81/14/6a9de6d13a122d5608e1a04130724caf9170333ac5a924e10f670687d3eb/mypy-1.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a3c47adf30d65e89b2dcd2fa32f3aeb5e94ca970d2c15fcb25e297871c8e4764", size = 11920910, upload-time = "2025-09-19T00:10:20.043Z" }, - { url = "https://files.pythonhosted.org/packages/5f/a9/b29de53e42f18e8cc547e38daa9dfa132ffdc64f7250e353f5c8cdd44bee/mypy-1.18.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d6c838e831a062f5f29d11c9057c6009f60cb294fea33a98422688181fe2893", size = 12465585, upload-time = "2025-09-19T00:10:33.005Z" }, - { url = "https://files.pythonhosted.org/packages/77/ae/6c3d2c7c61ff21f2bee938c917616c92ebf852f015fb55917fd6e2811db2/mypy-1.18.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01199871b6110a2ce984bde85acd481232d17413868c9807e95c1b0739a58914", size = 13348562, upload-time = "2025-09-19T00:10:11.51Z" }, - { url = "https://files.pythonhosted.org/packages/4d/31/aec68ab3b4aebdf8f36d191b0685d99faa899ab990753ca0fee60fb99511/mypy-1.18.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a2afc0fa0b0e91b4599ddfe0f91e2c26c2b5a5ab263737e998d6817874c5f7c8", size = 13533296, upload-time = "2025-09-19T00:10:06.568Z" }, - { url = "https://files.pythonhosted.org/packages/9f/83/abcb3ad9478fca3ebeb6a5358bb0b22c95ea42b43b7789c7fb1297ca44f4/mypy-1.18.2-cp312-cp312-win_amd64.whl", hash = "sha256:d8068d0afe682c7c4897c0f7ce84ea77f6de953262b12d07038f4d296d547074", size = 9828828, upload-time = "2025-09-19T00:10:28.203Z" }, - { url = "https://files.pythonhosted.org/packages/5f/04/7f462e6fbba87a72bc8097b93f6842499c428a6ff0c81dd46948d175afe8/mypy-1.18.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:07b8b0f580ca6d289e69209ec9d3911b4a26e5abfde32228a288eb79df129fcc", size = 12898728, upload-time = "2025-09-19T00:10:01.33Z" }, - { url = "https://files.pythonhosted.org/packages/99/5b/61ed4efb64f1871b41fd0b82d29a64640f3516078f6c7905b68ab1ad8b13/mypy-1.18.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ed4482847168439651d3feee5833ccedbf6657e964572706a2adb1f7fa4dfe2e", size = 11910758, upload-time = "2025-09-19T00:10:42.607Z" }, - { url = "https://files.pythonhosted.org/packages/3c/46/d297d4b683cc89a6e4108c4250a6a6b717f5fa96e1a30a7944a6da44da35/mypy-1.18.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c3ad2afadd1e9fea5cf99a45a822346971ede8685cc581ed9cd4d42eaf940986", size = 12475342, upload-time = "2025-09-19T00:11:00.371Z" }, - { url = "https://files.pythonhosted.org/packages/83/45/4798f4d00df13eae3bfdf726c9244bcb495ab5bd588c0eed93a2f2dd67f3/mypy-1.18.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a431a6f1ef14cf8c144c6b14793a23ec4eae3db28277c358136e79d7d062f62d", size = 13338709, upload-time = "2025-09-19T00:11:03.358Z" }, - { url = "https://files.pythonhosted.org/packages/d7/09/479f7358d9625172521a87a9271ddd2441e1dab16a09708f056e97007207/mypy-1.18.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7ab28cc197f1dd77a67e1c6f35cd1f8e8b73ed2217e4fc005f9e6a504e46e7ba", size = 13529806, upload-time = "2025-09-19T00:10:26.073Z" }, - { url = "https://files.pythonhosted.org/packages/71/cf/ac0f2c7e9d0ea3c75cd99dff7aec1c9df4a1376537cb90e4c882267ee7e9/mypy-1.18.2-cp313-cp313-win_amd64.whl", hash = "sha256:0e2785a84b34a72ba55fb5daf079a1003a34c05b22238da94fcae2bbe46f3544", size = 9833262, upload-time = "2025-09-19T00:10:40.035Z" }, - { url = "https://files.pythonhosted.org/packages/5a/0c/7d5300883da16f0063ae53996358758b2a2df2a09c72a5061fa79a1f5006/mypy-1.18.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:62f0e1e988ad41c2a110edde6c398383a889d95b36b3e60bcf155f5164c4fdce", size = 12893775, upload-time = "2025-09-19T00:10:03.814Z" }, - { url = "https://files.pythonhosted.org/packages/50/df/2cffbf25737bdb236f60c973edf62e3e7b4ee1c25b6878629e88e2cde967/mypy-1.18.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8795a039bab805ff0c1dfdb8cd3344642c2b99b8e439d057aba30850b8d3423d", size = 11936852, upload-time = "2025-09-19T00:10:51.631Z" }, - { url = "https://files.pythonhosted.org/packages/be/50/34059de13dd269227fb4a03be1faee6e2a4b04a2051c82ac0a0b5a773c9a/mypy-1.18.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6ca1e64b24a700ab5ce10133f7ccd956a04715463d30498e64ea8715236f9c9c", size = 12480242, upload-time = "2025-09-19T00:11:07.955Z" }, - { url = "https://files.pythonhosted.org/packages/5b/11/040983fad5132d85914c874a2836252bbc57832065548885b5bb5b0d4359/mypy-1.18.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d924eef3795cc89fecf6bedc6ed32b33ac13e8321344f6ddbf8ee89f706c05cb", size = 13326683, upload-time = "2025-09-19T00:09:55.572Z" }, - { url = "https://files.pythonhosted.org/packages/e9/ba/89b2901dd77414dd7a8c8729985832a5735053be15b744c18e4586e506ef/mypy-1.18.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20c02215a080e3a2be3aa50506c67242df1c151eaba0dcbc1e4e557922a26075", size = 13514749, upload-time = "2025-09-19T00:10:44.827Z" }, - { url = "https://files.pythonhosted.org/packages/25/bc/cc98767cffd6b2928ba680f3e5bc969c4152bf7c2d83f92f5a504b92b0eb/mypy-1.18.2-cp314-cp314-win_amd64.whl", hash = "sha256:749b5f83198f1ca64345603118a6f01a4e99ad4bf9d103ddc5a3200cc4614adf", size = 9982959, upload-time = "2025-09-19T00:10:37.344Z" }, - { url = "https://files.pythonhosted.org/packages/87/e3/be76d87158ebafa0309946c4a73831974d4d6ab4f4ef40c3b53a385a66fd/mypy-1.18.2-py3-none-any.whl", hash = "sha256:22a1748707dd62b58d2ae53562ffc4d7f8bcc727e8ac7cbc69c053ddc874d47e", size = 2352367, upload-time = "2025-09-19T00:10:15.489Z" }, -] - -[[package]] -name = "mypy-extensions" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, -] - [[package]] name = "nodeenv" version = "1.9.1" @@ -584,6 +542,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, ] +[[package]] +name = "nodejs-wheel-binaries" +version = "24.11.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/89/da307731fdbb05a5f640b26de5b8ac0dc463fef059162accfc89e32f73bc/nodejs_wheel_binaries-24.11.1.tar.gz", hash = "sha256:413dfffeadfb91edb4d8256545dea797c237bba9b3faefea973cde92d96bb922", size = 8059, upload-time = "2025-11-18T18:21:58.207Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/5f/be5a4112e678143d4c15264d918f9a2dc086905c6426eb44515cf391a958/nodejs_wheel_binaries-24.11.1-py2.py3-none-macosx_13_0_arm64.whl", hash = "sha256:0e14874c3579def458245cdbc3239e37610702b0aa0975c1dc55e2cb80e42102", size = 55114309, upload-time = "2025-11-18T18:21:21.697Z" }, + { url = "https://files.pythonhosted.org/packages/fa/1c/2e9d6af2ea32b65928c42b3e5baa7a306870711d93c3536cb25fc090a80d/nodejs_wheel_binaries-24.11.1-py2.py3-none-macosx_13_0_x86_64.whl", hash = "sha256:c2741525c9874b69b3e5a6d6c9179a6fe484ea0c3d5e7b7c01121c8e5d78b7e2", size = 55285957, upload-time = "2025-11-18T18:21:27.177Z" }, + { url = "https://files.pythonhosted.org/packages/d0/79/35696d7ba41b1bd35ef8682f13d46ba38c826c59e58b86b267458eb53d87/nodejs_wheel_binaries-24.11.1-py2.py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:5ef598101b0fb1c2bf643abb76dfbf6f76f1686198ed17ae46009049ee83c546", size = 59645875, upload-time = "2025-11-18T18:21:33.004Z" }, + { url = "https://files.pythonhosted.org/packages/b4/98/2a9694adee0af72bc602a046b0632a0c89e26586090c558b1c9199b187cc/nodejs_wheel_binaries-24.11.1-py2.py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:cde41d5e4705266688a8d8071debf4f8a6fcea264c61292782672ee75a6905f9", size = 60140941, upload-time = "2025-11-18T18:21:37.228Z" }, + { url = "https://files.pythonhosted.org/packages/d0/d6/573e5e2cba9d934f5f89d0beab00c3315e2e6604eb4df0fcd1d80c5a07a8/nodejs_wheel_binaries-24.11.1-py2.py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:78bc5bb889313b565df8969bb7423849a9c7fc218bf735ff0ce176b56b3e96f0", size = 61644243, upload-time = "2025-11-18T18:21:43.325Z" }, + { url = "https://files.pythonhosted.org/packages/c7/e6/643234d5e94067df8ce8d7bba10f3804106668f7a1050aeb10fdd226ead4/nodejs_wheel_binaries-24.11.1-py2.py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:c79a7e43869ccecab1cae8183778249cceb14ca2de67b5650b223385682c6239", size = 62225657, upload-time = "2025-11-18T18:21:47.708Z" }, + { url = "https://files.pythonhosted.org/packages/4d/1c/2fb05127102a80225cab7a75c0e9edf88a0a1b79f912e1e36c7c1aaa8f4e/nodejs_wheel_binaries-24.11.1-py2.py3-none-win_amd64.whl", hash = "sha256:10197b1c9c04d79403501766f76508b0dac101ab34371ef8a46fcf51773497d0", size = 41322308, upload-time = "2025-11-18T18:21:51.347Z" }, + { url = "https://files.pythonhosted.org/packages/ad/b7/bc0cdbc2cc3a66fcac82c79912e135a0110b37b790a14c477f18e18d90cd/nodejs_wheel_binaries-24.11.1-py2.py3-none-win_arm64.whl", hash = "sha256:376b9ea1c4bc1207878975dfeb604f7aa5668c260c6154dcd2af9d42f7734116", size = 39026497, upload-time = "2025-11-18T18:21:54.634Z" }, +] + [[package]] name = "nox" version = "2025.5.1" @@ -620,15 +594,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, ] -[[package]] -name = "pathspec" -version = "0.12.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, -] - [[package]] name = "pdfrest" version = "0.1.0" @@ -640,11 +605,10 @@ dependencies = [ [package.dev-dependencies] dev = [ - { name = "mypy" }, + { name = "basedpyright" }, { name = "nox" }, { name = "pip-audit" }, { name = "pre-commit" }, - { name = "pyright" }, { name = "pytest" }, { name = "pytest-asyncio" }, { name = "pytest-cov" }, @@ -664,11 +628,10 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ - { name = "mypy", specifier = ">=1.18.2" }, + { name = "basedpyright", specifier = ">=1.34.0" }, { name = "nox", specifier = ">=2025.5.1" }, { name = "pip-audit", specifier = ">=2.7.3" }, { name = "pre-commit", specifier = ">=3.7.0" }, - { name = "pyright", specifier = ">=1.1.406" }, { name = "pytest", specifier = ">=8.3.3" }, { name = "pytest-asyncio", specifier = ">=1.2.0" }, { name = "pytest-cov", specifier = ">=5.0.0" }, @@ -923,19 +886,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/10/5e/1aa9a93198c6b64513c9d7752de7422c06402de6600a8767da1524f9570b/pyparsing-3.2.5-py3-none-any.whl", hash = "sha256:e38a4f02064cf41fe6593d328d0512495ad1f3d8a91c4f73fc401b3079a59a5e", size = 113890, upload-time = "2025-09-21T04:11:04.117Z" }, ] -[[package]] -name = "pyright" -version = "1.1.406" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "nodeenv" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f7/16/6b4fbdd1fef59a0292cbb99f790b44983e390321eccbc5921b4d161da5d1/pyright-1.1.406.tar.gz", hash = "sha256:c4872bc58c9643dac09e8a2e74d472c62036910b3bd37a32813989ef7576ea2c", size = 4113151, upload-time = "2025-10-02T01:04:45.488Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/a2/e309afbb459f50507103793aaef85ca4348b66814c86bc73908bdeb66d12/pyright-1.1.406-py3-none-any.whl", hash = "sha256:1d81fb43c2407bf566e97e57abb01c811973fdb21b2df8df59f870f688bdca71", size = 5980982, upload-time = "2025-10-02T01:04:43.137Z" }, -] - [[package]] name = "pytest" version = "8.4.2"