diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index c6ed3cf1a08d..112102954dd3 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -28,6 +28,7 @@ concurrency: jobs: docs: runs-on: ubuntu-latest + timeout-minutes: 10 env: TOXENV: docs TOX_SKIP_MISSING_INTERPRETERS: False @@ -38,7 +39,7 @@ jobs: with: python-version: '3.12' - name: Install tox - run: pip install tox==4.11.0 + run: pip install tox==4.21.2 - name: Setup tox environment run: tox run -e ${{ env.TOXENV }} --notest - name: Test diff --git a/.github/workflows/mypy_primer.yml b/.github/workflows/mypy_primer.yml index 0c77d3a255d8..2b2327798a72 100644 --- a/.github/workflows/mypy_primer.yml +++ b/.github/workflows/mypy_primer.yml @@ -32,6 +32,7 @@ jobs: matrix: shard-index: [0, 1, 2, 3, 4] fail-fast: false + timeout-minutes: 60 steps: - uses: actions/checkout@v4 with: @@ -69,18 +70,35 @@ jobs: --output concise \ | tee diff_${{ matrix.shard-index }}.txt ) || [ $? -eq 1 ] - - name: Upload mypy_primer diff - uses: actions/upload-artifact@v3 - with: - name: mypy_primer_diffs - path: diff_${{ matrix.shard-index }}.txt - - if: ${{ matrix.shard-index }} == 0 + - if: ${{ matrix.shard-index == 0 }} name: Save PR number run: | echo ${{ github.event.pull_request.number }} | tee pr_number.txt - - if: ${{ matrix.shard-index }} == 0 - name: Upload PR number - uses: actions/upload-artifact@v3 + - if: ${{ matrix.shard-index == 0 }} + name: Upload mypy_primer diff + PR number + uses: actions/upload-artifact@v4 + with: + name: mypy_primer_diffs-${{ matrix.shard-index }} + path: | + diff_${{ matrix.shard-index }}.txt + pr_number.txt + - name: Upload mypy_primer diff + uses: actions/upload-artifact@v4 + if: ${{ matrix.shard-index != 0 }} + with: + name: mypy_primer_diffs-${{ matrix.shard-index }} + path: diff_${{ matrix.shard-index }}.txt + + join_artifacts: + name: Join artifacts + runs-on: ubuntu-latest + needs: [mypy_primer] + permissions: + contents: read + steps: + - name: Merge artifacts + uses: actions/upload-artifact/merge@v4 with: name: mypy_primer_diffs - path: pr_number.txt + pattern: mypy_primer_diffs-* + delete-merged: true diff --git a/.github/workflows/mypy_primer_comment.yml b/.github/workflows/mypy_primer_comment.yml index 492e03aff16e..6e62d8c51713 100644 --- a/.github/workflows/mypy_primer_comment.yml +++ b/.github/workflows/mypy_primer_comment.yml @@ -18,7 +18,7 @@ jobs: if: ${{ github.event.workflow_run.conclusion == 'success' }} steps: - name: Download diffs - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const fs = require('fs'); diff --git a/.github/workflows/sync_typeshed.yml b/.github/workflows/sync_typeshed.yml index b545e7b0662b..84d246441f3d 100644 --- a/.github/workflows/sync_typeshed.yml +++ b/.github/workflows/sync_typeshed.yml @@ -14,6 +14,7 @@ jobs: name: Sync typeshed if: github.repository == 'python/mypy' runs-on: ubuntu-latest + timeout-minutes: 10 steps: - uses: actions/checkout@v4 with: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 39fbb14bd3b7..9e6c9cd1d9b3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -70,14 +70,14 @@ jobs: toxenv: py tox_extra_args: "-n 4" test_mypyc: true - - - name: Test suite with py313-dev-ubuntu, mypyc-compiled - python: '3.13-dev' + - name: Test suite with py313-ubuntu, mypyc-compiled + python: '3.13' arch: x64 os: ubuntu-latest toxenv: py tox_extra_args: "-n 4" test_mypyc: true + # - name: Test suite with py314-dev-ubuntu # python: '3.14-dev' # arch: x64 @@ -94,13 +94,16 @@ jobs: os: macos-13 toxenv: py tox_extra_args: "-n 3 mypyc/test/test_run.py mypyc/test/test_external.py" - - name: mypyc runtime tests with py38-debug-build-ubuntu - python: '3.8.17' - arch: x64 - os: ubuntu-latest - toxenv: py - tox_extra_args: "-n 4 mypyc/test/test_run.py mypyc/test/test_external.py" - debug_build: true + # This is broken. See + # - https://github.com/python/mypy/issues/17819 + # - https://github.com/python/mypy/pull/17822 + # - name: mypyc runtime tests with py38-debug-build-ubuntu + # python: '3.8.17' + # arch: x64 + # os: ubuntu-latest + # toxenv: py + # tox_extra_args: "-n 4 mypyc/test/test_run.py mypyc/test/test_external.py" + # debug_build: true - name: Type check our own code (py38-ubuntu) python: '3.8' @@ -123,10 +126,11 @@ jobs: toxenv: lint name: ${{ matrix.name }} + timeout-minutes: 60 env: TOX_SKIP_MISSING_INTERPRETERS: False - # Rich (pip) - FORCE_COLOR: 1 + # Rich (pip) -- Disable color for windows + pytest + FORCE_COLOR: ${{ !(startsWith(matrix.os, 'windows-') && startsWith(matrix.toxenv, 'py')) && 1 || 0 }} # Tox PY_COLORS: 1 # Mypy (see https://github.com/python/mypy/issues/7771) @@ -148,17 +152,17 @@ jobs: ./misc/build-debug-python.sh $PYTHONVERSION $PYTHONDIR $VENV # TODO: does this do anything? env vars aren't passed to the next step right source $VENV/bin/activate - - name: Latest Dev build + - name: Latest dev build if: ${{ endsWith(matrix.python, '-dev') }} run: | - sudo apt-get update - sudo apt-get install -y --no-install-recommends \ - build-essential gdb lcov libbz2-dev libffi-dev libgdbm-dev liblzma-dev libncurses5-dev \ - libreadline6-dev libsqlite3-dev libssl-dev lzma lzma-dev tk-dev uuid-dev zlib1g-dev git clone --depth 1 https://github.com/python/cpython.git /tmp/cpython --branch $( echo ${{ matrix.python }} | sed 's/-dev//' ) cd /tmp/cpython echo git rev-parse HEAD; git rev-parse HEAD git show --no-patch + sudo apt-get update + sudo apt-get install -y --no-install-recommends \ + build-essential gdb lcov libbz2-dev libffi-dev libgdbm-dev liblzma-dev libncurses5-dev \ + libreadline6-dev libsqlite3-dev libssl-dev lzma lzma-dev tk-dev uuid-dev zlib1g-dev ./configure --prefix=/opt/pythondev make -j$(nproc) sudo make install @@ -180,7 +184,7 @@ jobs: echo debug build; python -c 'import sysconfig; print(bool(sysconfig.get_config_var("Py_DEBUG")))' echo os.cpu_count; python -c 'import os; print(os.cpu_count())' echo os.sched_getaffinity; python -c 'import os; print(len(getattr(os, "sched_getaffinity", lambda *args: [])(0)))' - pip install setuptools==68.2.2 tox==4.11.0 + pip install setuptools==75.1.0 tox==4.21.2 - name: Compiled with mypyc if: ${{ matrix.test_mypyc }} @@ -190,7 +194,7 @@ jobs: - name: Setup tox environment run: | - tox run -e ${{ matrix.toxenv }} --notes + tox run -e ${{ matrix.toxenv }} --notest - name: Test run: tox run -e ${{ matrix.toxenv }} --skip-pkg-install -- ${{ matrix.tox_extra_args }} continue-on-error: ${{ matrix.allow_failure == 'true' }} @@ -202,6 +206,7 @@ jobs: python_32bits: runs-on: ubuntu-latest name: Test mypyc suite with 32-bit Python + timeout-minutes: 60 env: TOX_SKIP_MISSING_INTERPRETERS: False # Rich (pip) @@ -240,7 +245,7 @@ jobs: default: 3.11.1 command: python -c "import platform; print(f'{platform.architecture()=} {platform.machine()=}');" - name: Install tox - run: pip install setuptools==68.2.2 tox==4.11.0 + run: pip install setuptools==75.1.0 tox==4.21.2 - name: Setup tox environment run: tox run -e py --notest - name: Test diff --git a/.github/workflows/test_stubgenc.yml b/.github/workflows/test_stubgenc.yml index 519f63ac2bd7..0652702a0fc0 100644 --- a/.github/workflows/test_stubgenc.yml +++ b/.github/workflows/test_stubgenc.yml @@ -25,6 +25,7 @@ jobs: # Check stub file generation for a small pybind11 project # (full text match is required to pass) runs-on: ubuntu-latest + timeout-minutes: 10 steps: - uses: actions/checkout@v4 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a7ff48051aad..d8e66ecb4dfc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,19 +1,33 @@ exclude: '^(mypyc/external/)|(mypy/typeshed/)|misc/typeshed_patches' # Exclude all vendored code from lints repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 # must match test-requirements.txt + rev: v4.5.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - repo: https://github.com/psf/black-pre-commit-mirror - rev: 24.1.1 # must match test-requirements.txt + rev: 24.8.0 hooks: - id: black exclude: '^(test-data/)' - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.2.0 # must match test-requirements.txt + rev: v0.6.9 hooks: - id: ruff args: [--exit-non-zero-on-fix] + - repo: https://github.com/python-jsonschema/check-jsonschema + rev: 0.29.4 + hooks: + - id: check-dependabot + - id: check-github-workflows + - repo: https://github.com/rhysd/actionlint + rev: v1.7.3 + hooks: + - id: actionlint + args: [ + -ignore=property "debug_build" is not defined, + -ignore=property "allow_failure" is not defined, + -ignore=SC2(046|086), + ] ci: autoupdate_schedule: quarterly diff --git a/CHANGELOG.md b/CHANGELOG.md index 9632cb39a8b1..01c3ed16ddbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,638 @@ ## Next release +... + +## Mypy 1.14 + +We’ve just uploaded mypy 1.14 to the Python Package Index ([PyPI](https://pypi.org/project/mypy/)). +Mypy is a static type checker for Python. This release includes new features and bug fixes. +You can install it as follows: + + python3 -m pip install -U mypy + +You can read the full documentation for this release on [Read the Docs](http://mypy.readthedocs.io). + +### Change to Enum Membership Semantics + +As per the updated [typing specification for enums](https://typing.readthedocs.io/en/latest/spec/enums.html#defining-members), +enum members must be left unannotated. + +```python +class Pet(Enum): + CAT = 1 # Member attribute + DOG = 2 # Member attribute + + # New error: Enum members must be left unannotated + WOLF: int = 3 + + species: str # Considered a non-member attribute +``` + +In particular, the specification change can result in issues in type stubs (`.pyi` files), since +historically it was common to leave the value absent: + +```python +# In a type stub (.pyi file) + +class Pet(Enum): + # Change in semantics: previously considered members, + # now non-member attributes + CAT: int + DOG: int + + # Mypy will now issue a warning if it detects this + # situation in type stubs: + # > Detected enum "Pet" in a type stub with zero + # > members. There is a chance this is due to a recent + # > change in the semantics of enum membership. If so, + # > use `member = value` to mark an enum member, + # > instead of `member: type` + +class Pet(Enum): + # As per the specification, you should now do one of + # the following: + DOG = 1 # Member attribute with value 1 and known type + WOLF = cast(int, ...) # Member attribute with unknown + # value but known type + LION = ... # Member attribute with unknown value and + # # unknown type +``` + +Contributed by Terence Honles (PR [17207](https://github.com/python/mypy/pull/17207)) and +Shantanu Jain (PR [18068](https://github.com/python/mypy/pull/18068)). + +### Support for @deprecated Decorator (PEP 702) + +Mypy can now issue errors or notes when code imports a deprecated feature +explicitly with a `from mod import depr` statement, or uses a deprecated feature +imported otherwise or defined locally. Features are considered deprecated when +decorated with `warnings.deprecated`, as specified in [PEP 702](https://peps.python.org/pep-0702). + +You can enable the error code via `--enable-error-code=deprecated` on the mypy +command line or `enable_error_code = deprecated` in the mypy config file. +Use the command line flag `--report-deprecated-as-note` or config file option +`report_deprecated_as_note=True` to turn all such errors into notes. + +Deprecation errors will be enabled by default in a future mypy version. + +This feature was contributed by Christoph Tyralla. + +List of changes: + + * Add basic support for PEP 702 (`@deprecated`) (Christoph Tyralla, PR [17476](https://github.com/python/mypy/pull/17476)) + * Support descriptors with `@deprecated` (Christoph Tyralla, PR [18090](https://github.com/python/mypy/pull/18090)) + * Make "deprecated" note an error, disabled by default (Valentin Stanciu, PR [18192](https://github.com/python/mypy/pull/18192)) + * Consider all possible type positions with `@deprecated` (Christoph Tyralla, PR [17926](https://github.com/python/mypy/pull/17926)) + * Improve the handling of explicit type annotations in assignment statements with `@deprecated` (Christoph Tyralla, PR [17899](https://github.com/python/mypy/pull/17899)) + +### Optionally Analyzing Untyped Modules + +Mypy normally doesn't analyze imports from third-party modules (installed using pip, for example) +if there are no stubs or a py.typed marker file. To force mypy to analyze these imports, you +can now use the `--follow-untyped-imports` flag or set the `follow_untyped_imports` +config file option to True. This can be set either in the global section of your mypy config +file, or individually on a per-module basis. + +This feature was contributed by Jannick Kremer. + +List of changes: + + * Implement flag to allow type checking of untyped modules (Jannick Kremer, PR [17712](https://github.com/python/mypy/pull/17712)) + * Warn about `--follow-untyped-imports` (Shantanu, PR [18249](https://github.com/python/mypy/pull/18249)) + +### Support New Style Type Variable Defaults (PEP 696) + +Mypy now supports type variable defaults using the new syntax described in PEP 696, which +was introduced in Python 3.13. Example: + +```python +@dataclass +class Box[T = int]: # Set default for "T" + value: T | None = None + +reveal_type(Box()) # type is Box[int], since it's the default +reveal_type(Box(value="Hello World!")) # type is Box[str] +``` + +This feature was contributed by Marc Mueller (PR [17985](https://github.com/python/mypy/pull/17985)). + +### Improved For Loop Index Variable Type Narrowing + +Mypy now preserves the literal type of for loop index variables, to support `TypedDict` +lookups. Example: + +```python +from typing import TypedDict + +class X(TypedDict): + hourly: int + daily: int + +def func(x: X) -> int: + s = 0 + for var in ("hourly", "daily"): + # "Union[Literal['hourly']?, Literal['daily']?]" + reveal_type(var) + + # x[var] no longer triggers a literal-required error + s += x[var] + return s +``` + +This was contributed by Marc Mueller (PR [18014](https://github.com/python/mypy/pull/18014)). + +### Mypyc Improvements + + * Document optimized bytes operations and additional str operations (Jukka Lehtosalo, PR [18242](https://github.com/python/mypy/pull/18242)) + * Add primitives and specialization for `ord()` (Jukka Lehtosalo, PR [18240](https://github.com/python/mypy/pull/18240)) + * Optimize `str.encode` with specializations for common used encodings (Valentin Stanciu, PR [18232](https://github.com/python/mypy/pull/18232)) + * Fix fall back to generic operation for staticmethod and classmethod (Advait Dixit, PR [18228](https://github.com/python/mypy/pull/18228)) + * Support unicode surrogates in string literals (Jukka Lehtosalo, PR [18209](https://github.com/python/mypy/pull/18209)) + * Fix index variable in for loop with `builtins.enumerate` (Advait Dixit, PR [18202](https://github.com/python/mypy/pull/18202)) + * Fix check for enum classes (Advait Dixit, PR [18178](https://github.com/python/mypy/pull/18178)) + * Fix loading type from imported modules (Advait Dixit, PR [18158](https://github.com/python/mypy/pull/18158)) + * Fix initializers of final attributes in class body (Jared Hance, PR [18031](https://github.com/python/mypy/pull/18031)) + * Fix name generation for modules with similar full names (aatle, PR [18001](https://github.com/python/mypy/pull/18001)) + * Fix relative imports in `__init__.py` (Shantanu, PR [17979](https://github.com/python/mypy/pull/17979)) + * Optimize dunder methods (jairov4, PR [17934](https://github.com/python/mypy/pull/17934)) + * Replace deprecated `_PyDict_GetItemStringWithError` (Marc Mueller, PR [17930](https://github.com/python/mypy/pull/17930)) + * Fix wheel build for cp313-win (Marc Mueller, PR [17941](https://github.com/python/mypy/pull/17941)) + * Use public PyGen_GetCode instead of vendored implementation (Marc Mueller, PR [17931](https://github.com/python/mypy/pull/17931)) + * Optimize calls to final classes (jairov4, PR [17886](https://github.com/python/mypy/pull/17886)) + * Support ellipsis (`...`) expressions in class bodies (Newbyte, PR [17923](https://github.com/python/mypy/pull/17923)) + * Sync `pythoncapi_compat.h` (Marc Mueller, PR [17929](https://github.com/python/mypy/pull/17929)) + * Add `runtests.py mypyc-fast` for running fast mypyc tests (Jukka Lehtosalo, PR [17906](https://github.com/python/mypy/pull/17906)) + +### Stubgen Improvements + + * Do not include mypy generated symbols (Ali Hamdan, PR [18137](https://github.com/python/mypy/pull/18137)) + * Fix `FunctionContext.fullname` for nested classes (Chad Dombrova, PR [17963](https://github.com/python/mypy/pull/17963)) + * Add flagfile support (Ruslan Sayfutdinov, PR [18061](https://github.com/python/mypy/pull/18061)) + * Add support for PEP 695 and PEP 696 syntax (Ali Hamdan, PR [18054](https://github.com/python/mypy/pull/18054)) + +### Stubtest Improvements + + * Allow the use of `--show-traceback` and `--pdb` with stubtest (Stephen Morton, PR [18037](https://github.com/python/mypy/pull/18037)) + * Verify `__all__` exists in stub (Sebastian Rittau, PR [18005](https://github.com/python/mypy/pull/18005)) + * Stop telling people to use double underscores (Jelle Zijlstra, PR [17897](https://github.com/python/mypy/pull/17897)) + +### Documentation Updates + + * Update config file documentation (sobolevn, PR [18103](https://github.com/python/mypy/pull/18103)) + * Improve contributor documentation for Windows (ag-tafe, PR [18097](https://github.com/python/mypy/pull/18097)) + * Correct note about `--disallow-any-generics` flag in documentation (Abel Sen, PR [18055](https://github.com/python/mypy/pull/18055)) + * Further caution against `--follow-imports=skip` (Shantanu, PR [18048](https://github.com/python/mypy/pull/18048)) + * Fix the edit page buttton link in documentation (Kanishk Pachauri, PR [17933](https://github.com/python/mypy/pull/17933)) + +### Other Notables Fixes and Improvements + + * Show `Protocol` `__call__` for arguments with incompatible types (MechanicalConstruct, PR [18214](https://github.com/python/mypy/pull/18214)) + * Make join and meet symmetric with `strict_optional` (MechanicalConstruct, PR [18227](https://github.com/python/mypy/pull/18227)) + * Preserve block unreachablility when checking function definitions with constrained TypeVars (Brian Schubert, PR [18217](https://github.com/python/mypy/pull/18217)) + * Do not include non-init fields in the synthesized `__replace__` method for dataclasses (Victorien, PR [18221](https://github.com/python/mypy/pull/18221)) + * Disallow `TypeVar` constraints parameterized by type variables (Brian Schubert, PR [18186](https://github.com/python/mypy/pull/18186)) + * Always complain about invalid varargs and varkwargs (Shantanu, PR [18207](https://github.com/python/mypy/pull/18207)) + * Set default strict_optional state to True (Shantanu, PR [18198](https://github.com/python/mypy/pull/18198)) + * Preserve type variable default None in type alias (Sukhorosov Aleksey, PR [18197](https://github.com/python/mypy/pull/18197)) + * Add checks for invalid usage of continue/break/return in `except*` block (coldwolverine, PR [18132](https://github.com/python/mypy/pull/18132)) + * Do not consider bare TypeVar not overlapping with None for reachability analysis (Stanislav Terliakov, PR [18138](https://github.com/python/mypy/pull/18138)) + * Special case `types.DynamicClassAttribute` as property-like (Stephen Morton, PR [18150](https://github.com/python/mypy/pull/18150)) + * Disallow bare `ParamSpec` in type aliases (Brian Schubert, PR [18174](https://github.com/python/mypy/pull/18174)) + * Move long_description metadata to pyproject.toml (Marc Mueller, PR [18172](https://github.com/python/mypy/pull/18172)) + * Support `==`-based narrowing of Optional (Christoph Tyralla, PR [18163](https://github.com/python/mypy/pull/18163)) + * Allow TypedDict assignment of Required item to NotRequired ReadOnly item (Brian Schubert, PR [18164](https://github.com/python/mypy/pull/18164)) + * Allow nesting of Annotated with TypedDict special forms inside TypedDicts (Brian Schubert, PR [18165](https://github.com/python/mypy/pull/18165)) + * Infer generic type arguments for slice expressions (Brian Schubert, PR [18160](https://github.com/python/mypy/pull/18160)) + * Fix checking of match sequence pattern against bounded type variables (Brian Schubert, PR [18091](https://github.com/python/mypy/pull/18091)) + * Fix incorrect truthyness for Enum types and literals (David Salvisberg, PR [17337](https://github.com/python/mypy/pull/17337)) + * Move static project metadata to pyproject.toml (Marc Mueller, PR [18146](https://github.com/python/mypy/pull/18146)) + * Fallback to stdlib json if integer exceeds 64-bit range (q0w, PR [18148](https://github.com/python/mypy/pull/18148)) + * Fix 'or' pattern structural matching exhaustiveness (yihong, PR [18119](https://github.com/python/mypy/pull/18119)) + * Fix type inference of positional parameter in class pattern involving builtin subtype (Brian Schubert, PR [18141](https://github.com/python/mypy/pull/18141)) + * Fix `[override]` error with no line number when argument node has no line number (Brian Schubert, PR [18122](https://github.com/python/mypy/pull/18122)) + * Fix some dmypy crashes (Ivan Levkivskyi, PR [18098](https://github.com/python/mypy/pull/18098)) + * Fix subtyping between instance type and overloaded (Shantanu, PR [18102](https://github.com/python/mypy/pull/18102)) + * Clean up new_semantic_analyzer config (Shantanu, PR [18071](https://github.com/python/mypy/pull/18071)) + * Issue warning for enum with no members in stub (Shantanu, PR [18068](https://github.com/python/mypy/pull/18068)) + * Fix enum attributes are not members (Terence Honles, PR [17207](https://github.com/python/mypy/pull/17207)) + * Fix crash when checking slice expression with step 0 in tuple index (Brian Schubert, PR [18063](https://github.com/python/mypy/pull/18063)) + * Allow union-with-callable attributes to be overridden by methods (Brian Schubert, PR [18018](https://github.com/python/mypy/pull/18018)) + * Emit `[mutable-override]` for covariant override of attribute with method (Brian Schubert, PR [18058](https://github.com/python/mypy/pull/18058)) + * Support ParamSpec mapping with `functools.partial` (Stanislav Terliakov, PR [17355](https://github.com/python/mypy/pull/17355)) + * Fix approved stub ignore, remove normpath (Shantanu, PR [18045](https://github.com/python/mypy/pull/18045)) + * Make `disallow-any-unimported` flag invertible (Séamus Ó Ceanainn, PR [18030](https://github.com/python/mypy/pull/18030)) + * Filter to possible package paths before trying to resolve a module (falsedrow, PR [18038](https://github.com/python/mypy/pull/18038)) + * Fix overlap check for ParamSpec types (Jukka Lehtosalo, PR [18040](https://github.com/python/mypy/pull/18040)) + * Do not prioritize ParamSpec signatures during overload resolution (Stanislav Terliakov, PR [18033](https://github.com/python/mypy/pull/18033)) + * Fix ternary union for literals (Ivan Levkivskyi, PR [18023](https://github.com/python/mypy/pull/18023)) + * Fix compatibility checks for conditional function definitions using decorators (Brian Schubert, PR [18020](https://github.com/python/mypy/pull/18020)) + * TypeGuard should be bool not Any when matching TypeVar (Evgeniy Slobodkin, PR [17145](https://github.com/python/mypy/pull/17145)) + * Fix convert-cache tool (Shantanu, PR [17974](https://github.com/python/mypy/pull/17974)) + * Fix generator comprehension with mypyc (Shantanu, PR [17969](https://github.com/python/mypy/pull/17969)) + * Fix crash issue when using shadowfile with pretty (Max Chang, PR [17894](https://github.com/python/mypy/pull/17894)) + * Fix multiple nested classes with new generics syntax (Max Chang, PR [17820](https://github.com/python/mypy/pull/17820)) + * Better error for `mypy -p package` without py.typed (Joe Gordon, PR [17908](https://github.com/python/mypy/pull/17908)) + * Emit error for `raise NotImplemented` (Brian Schubert, PR [17890](https://github.com/python/mypy/pull/17890)) + * Add `is_lvalue` attribute to AttributeContext (Brian Schubert, PR [17881](https://github.com/python/mypy/pull/17881)) + +### Acknowledgements + +Thanks to all mypy contributors who contributed to this release: + +- aatle +- Abel Sen +- Advait Dixit +- ag-tafe +- Alex Waygood +- Ali Hamdan +- Brian Schubert +- Carlton Gibson +- Chad Dombrova +- Chelsea Durazo +- chiri +- Christoph Tyralla +- coldwolverine +- David Salvisberg +- Ekin Dursun +- Evgeniy Slobodkin +- falsedrow +- Gaurav Giri +- Ihor +- Ivan Levkivskyi +- jairov4 +- Jannick Kremer +- Jared Hance +- Jelle Zijlstra +- jianghuyiyuan +- Joe Gordon +- John Doknjas +- Jukka Lehtosalo +- Kanishk Pachauri +- Marc Mueller +- Max Chang +- MechanicalConstruct +- Newbyte +- q0w +- Ruslan Sayfutdinov +- Sebastian Rittau +- Shantanu +- sobolevn +- Stanislav Terliakov +- Stephen Morton +- Sukhorosov Aleksey +- Séamus Ó Ceanainn +- Terence Honles +- Valentin Stanciu +- vasiliy +- Victorien +- yihong + +I’d also like to thank my employer, Dropbox, for supporting mypy development. + + +## Mypy 1.13 + +We’ve just uploaded mypy 1.13 to the Python Package Index ([PyPI](https://pypi.org/project/mypy/)). +Mypy is a static type checker for Python. You can install it as follows: + + python3 -m pip install -U mypy + +You can read the full documentation for this release on [Read the Docs](http://mypy.readthedocs.io). + +Note that unlike typical releases, Mypy 1.13 does not have any changes to type checking semantics +from 1.12.1. + +### Improved Performance + +Mypy 1.13 contains several performance improvements. Users can expect mypy to be 5-20% faster. +In environments with long search paths (such as environments using many editable installs), mypy +can be significantly faster, e.g. 2.2x faster in the use case targeted by these improvements. + +Mypy 1.13 allows use of the `orjson` library for handling the cache instead of the stdlib `json`, +for improved performance. You can ensure the presence of `orjson` using the `faster-cache` extra: + + python3 -m pip install -U mypy[faster-cache] + +Mypy may depend on `orjson` by default in the future. + +These improvements were contributed by Shantanu. + +List of changes: +* Significantly speed up file handling error paths (Shantanu, PR [17920](https://github.com/python/mypy/pull/17920)) +* Use fast path in modulefinder more often (Shantanu, PR [17950](https://github.com/python/mypy/pull/17950)) +* Let mypyc optimise os.path.join (Shantanu, PR [17949](https://github.com/python/mypy/pull/17949)) +* Make is_sub_path faster (Shantanu, PR [17962](https://github.com/python/mypy/pull/17962)) +* Speed up stubs suggestions (Shantanu, PR [17965](https://github.com/python/mypy/pull/17965)) +* Use sha1 for hashing (Shantanu, PR [17953](https://github.com/python/mypy/pull/17953)) +* Use orjson instead of json, when available (Shantanu, PR [17955](https://github.com/python/mypy/pull/17955)) +* Add faster-cache extra, test in CI (Shantanu, PR [17978](https://github.com/python/mypy/pull/17978)) + +### Acknowledgements +Thanks to all mypy contributors who contributed to this release: + +- Shantanu Jain +- Jukka Lehtosalo + +## Mypy 1.12 + +We’ve just uploaded mypy 1.12 to the Python Package Index ([PyPI](https://pypi.org/project/mypy/)). Mypy is a static type +checker for Python. This release includes new features, performance improvements and bug fixes. +You can install it as follows: + + python3 -m pip install -U mypy + +You can read the full documentation for this release on [Read the Docs](http://mypy.readthedocs.io). + +### Support Python 3.12 Syntax for Generics (PEP 695) + +Support for the new type parameter syntax introduced in Python 3.12 is now enabled by default, +documented, and no longer experimental. It was available through a feature flag in +mypy 1.11 as an experimental feature. + +This example demonstrates the new syntax: + +```python +# Generic function +def f[T](x: T) -> T: ... + +reveal_type(f(1)) # Revealed type is 'int' + +# Generic class +class C[T]: + def __init__(self, x: T) -> None: + self.x = x + +c = C('a') +reveal_type(c.x) # Revealed type is 'str' + +# Type alias +type A[T] = C[list[T]] +``` + +For more information, refer to the [documentation](https://mypy.readthedocs.io/en/latest/generics.html). + +These improvements are included: + + * Document Python 3.12 type parameter syntax (Jukka Lehtosalo, PR [17816](https://github.com/python/mypy/pull/17816)) + * Further documentation updates (Jukka Lehtosalo, PR [17826](https://github.com/python/mypy/pull/17826)) + * Allow Self return types with contravariance (Jukka Lehtosalo, PR [17786](https://github.com/python/mypy/pull/17786)) + * Enable new type parameter syntax by default (Jukka Lehtosalo, PR [17798](https://github.com/python/mypy/pull/17798)) + * Generate error if new-style type alias used as base class (Jukka Lehtosalo, PR [17789](https://github.com/python/mypy/pull/17789)) + * Inherit variance if base class has explicit variance (Jukka Lehtosalo, PR [17787](https://github.com/python/mypy/pull/17787)) + * Fix crash on invalid type var reference (Jukka Lehtosalo, PR [17788](https://github.com/python/mypy/pull/17788)) + * Fix covariance of frozen dataclasses (Jukka Lehtosalo, PR [17783](https://github.com/python/mypy/pull/17783)) + * Allow covariance with attribute that has "`_`" name prefix (Jukka Lehtosalo, PR [17782](https://github.com/python/mypy/pull/17782)) + * Support `Annotated[...]` in new-style type aliases (Jukka Lehtosalo, PR [17777](https://github.com/python/mypy/pull/17777)) + * Fix nested generic classes (Jukka Lehtosalo, PR [17776](https://github.com/python/mypy/pull/17776)) + * Add detection and error reporting for the use of incorrect expressions within the scope of a type parameter and a type alias (Kirill Podoprigora, PR [17560](https://github.com/python/mypy/pull/17560)) + +### Basic Support for Python 3.13 + +This release adds partial support for Python 3.13 features and compiled binaries for +Python 3.13. Mypyc now also supports Python 3.13. + +In particular, these features are supported: + * Various new stdlib features and changes (through typeshed stub improvements) + * `typing.ReadOnly` (see below for more) + * `typing.TypeIs` (added in mypy 1.10, [PEP 742](https://peps.python.org/pep-0742/)) + * Type parameter defaults when using the legacy syntax ([PEP 696](https://peps.python.org/pep-0696/)) + +These features are not supported yet: + * `warnings.deprecated` ([PEP 702](https://peps.python.org/pep-0702/)) + * Type parameter defaults when using Python 3.12 type parameter syntax + +### Mypyc Support for Python 3.13 + +Mypyc now supports Python 3.13. This was contributed by Marc Mueller, with additional +fixes by Jukka Lehtosalo. Free threaded Python 3.13 builds are not supported yet. + +List of changes: + + * Add additional includes for Python 3.13 (Marc Mueller, PR [17506](https://github.com/python/mypy/pull/17506)) + * Add another include for Python 3.13 (Marc Mueller, PR [17509](https://github.com/python/mypy/pull/17509)) + * Fix ManagedDict functions for Python 3.13 (Marc Mueller, PR [17507](https://github.com/python/mypy/pull/17507)) + * Update mypyc test output for Python 3.13 (Marc Mueller, PR [17508](https://github.com/python/mypy/pull/17508)) + * Fix `PyUnicode` functions for Python 3.13 (Marc Mueller, PR [17504](https://github.com/python/mypy/pull/17504)) + * Fix `_PyObject_LookupAttrId` for Python 3.13 (Marc Mueller, PR [17505](https://github.com/python/mypy/pull/17505)) + * Fix `_PyList_Extend` for Python 3.13 (Marc Mueller, PR [17503](https://github.com/python/mypy/pull/17503)) + * Fix `gen_is_coroutine` for Python 3.13 (Marc Mueller, PR [17501](https://github.com/python/mypy/pull/17501)) + * Fix `_PyObject_FastCall` for Python 3.13 (Marc Mueller, PR [17502](https://github.com/python/mypy/pull/17502)) + * Avoid uses of `_PyObject_CallMethodOneArg` on 3.13 (Jukka Lehtosalo, PR [17526](https://github.com/python/mypy/pull/17526)) + * Don't rely on `_PyType_CalculateMetaclass` on 3.13 (Jukka Lehtosalo, PR [17525](https://github.com/python/mypy/pull/17525)) + * Don't use `_PyUnicode_FastCopyCharacters` on 3.13 (Jukka Lehtosalo, PR [17524](https://github.com/python/mypy/pull/17524)) + * Don't use `_PyUnicode_EQ` on 3.13, as it's no longer exported (Jukka Lehtosalo, PR [17523](https://github.com/python/mypy/pull/17523)) + +### Inferring Unions for Conditional Expressions + +Mypy now always tries to infer a union type for a conditional expression if left and right +operand types are different. This results in more precise inferred types and lets mypy detect +more issues. Example: + +```python +s = "foo" if cond() else 1 +# Type of "s" is now "str | int" (it used to be "object") +``` + +Notably, if one of the operands has type `Any`, the type of a conditional expression is +now ` | Any`. Previously the inferred type was just `Any`. The new type essentially +indicates that the value can be of type ``, and potentially of some (unknown) type. +Most operations performed on the result must also be valid for ``. +Example where this is relevant: + +```python +from typing import Any + +def func(a: Any, b: bool) -> None: + x = a if b else None + # Type of x is "Any | None" + print(x.y) # Error: None has no attribute "y" +``` + +This feature was contributed by Ivan Levkivskyi (PR [17427](https://github.com/python/mypy/pull/17427)). + +### ReadOnly Support for TypedDict (PEP 705) + +You can now use `typing.ReadOnly` to specity TypedDict items as +read-only ([PEP 705](https://peps.python.org/pep-0705/)): + +```python +from typing import TypedDict + +# Or "from typing ..." on Python 3.13 +from typing_extensions import ReadOnly + +class TD(TypedDict): + a: int + b: ReadOnly[int] + +d: TD = {"a": 1, "b": 2} +d["a"] = 3 # OK +d["b"] = 5 # Error: "b" is ReadOnly +``` + +This feature was contributed by Nikita Sobolev (PR [17644](https://github.com/python/mypy/pull/17644)). + +### Python 3.8 End of Life Approaching + +We are planning to drop support for Python 3.8 in the next mypy feature release or the +one after that. Python 3.8 reaches end of life in October 2024. + +### Planned Changes to Defaults + +We are planning to enable `--local-partial-types` by default in mypy 2.0. This will +often require at least minor code changes. This option is implicitly enabled by mypy +daemon, so this makes the behavior of daemon and non-daemon modes consistent. + +We recommend that mypy users start using local partial types soon (or to explicitly disable +them) to prepare for the change. + +This can also be configured in a mypy configuration file: + +``` +local_partial_types = True +``` + +For more information, refer to the +[documentation](https://mypy.readthedocs.io/en/stable/command_line.html#cmdoption-mypy-local-partial-types). + +### Documentation Updates + +Mypy documentation now uses modern syntax variants and imports in many examples. Some +examples no longer work on Python 3.8, which is the earliest Python version that mypy supports. + +Notably, `Iterable` and other protocols/ABCs are imported from `collections.abc` instead of +`typing`: +```python +from collections.abc import Iterable, Callable +``` + +Examples also avoid the upper-case aliases to built-in types: `list[str]` is used instead +of `List[str]`. The `X | Y` union type syntax introduced in Python 3.10 is also now prevalent. + +List of documentation updates: + + * Document `--output=json` CLI option (Edgar Ramírez Mondragón, PR [17611](https://github.com/python/mypy/pull/17611)) + * Update various references to deprecated type aliases in docs (Jukka Lehtosalo, PR [17829](https://github.com/python/mypy/pull/17829)) + * Make "X | Y" union syntax more prominent in documentation (Jukka Lehtosalo, PR [17835](https://github.com/python/mypy/pull/17835)) + * Discuss upper bounds before self types in documentation (Jukka Lehtosalo, PR [17827](https://github.com/python/mypy/pull/17827)) + * Make changelog visible in mypy documentation (quinn-sasha, PR [17742](https://github.com/python/mypy/pull/17742)) + * List all incomplete features in `--enable-incomplete-feature` docs (sobolevn, PR [17633](https://github.com/python/mypy/pull/17633)) + * Remove the explicit setting of a pygments theme (Pradyun Gedam, PR [17571](https://github.com/python/mypy/pull/17571)) + * Document ReadOnly with TypedDict (Jukka Lehtosalo, PR [17905](https://github.com/python/mypy/pull/17905)) + * Document TypeIs (Chelsea Durazo, PR [17821](https://github.com/python/mypy/pull/17821)) + +### Experimental Inline TypedDict Syntax + +Mypy now supports a non-standard, experimental syntax for defining anonymous TypedDicts. +Example: + +```python +def func(n: str, y: int) -> {"name": str, "year": int}: + return {"name": n, "year": y} +``` + +The feature is disabled by default. Use `--enable-incomplete-feature=InlineTypedDict` to +enable it. *We might remove this feature in a future release.* + +This feature was contributed by Ivan Levkivskyi (PR [17457](https://github.com/python/mypy/pull/17457)). + +### Stubgen Improvements + + * Fix crash on literal class-level keywords (sobolevn, PR [17663](https://github.com/python/mypy/pull/17663)) + * Stubgen add `--version` (sobolevn, PR [17662](https://github.com/python/mypy/pull/17662)) + * Fix `stubgen --no-analysis/--parse-only` docs (sobolevn, PR [17632](https://github.com/python/mypy/pull/17632)) + * Include keyword only args when generating signatures in stubgenc (Eric Mark Martin, PR [17448](https://github.com/python/mypy/pull/17448)) + * Add support for detecting `Literal` types when extracting types from docstrings (Michael Carlstrom, PR [17441](https://github.com/python/mypy/pull/17441)) + * Use `Generator` type var defaults (Sebastian Rittau, PR [17670](https://github.com/python/mypy/pull/17670)) + +### Stubtest Improvements + * Add support for `cached_property` (Ali Hamdan, PR [17626](https://github.com/python/mypy/pull/17626)) + * Add `enable_incomplete_feature` validation to `stubtest` (sobolevn, PR [17635](https://github.com/python/mypy/pull/17635)) + * Fix error code handling in `stubtest` with `--mypy-config-file` (sobolevn, PR [17629](https://github.com/python/mypy/pull/17629)) + +### Other Notables Fixes and Improvements + + * Report error if using unsupported type parameter defaults (Jukka Lehtosalo, PR [17876](https://github.com/python/mypy/pull/17876)) + * Fix re-processing cross-reference in mypy daemon when node kind changes (Ivan Levkivskyi, PR [17883](https://github.com/python/mypy/pull/17883)) + * Don't use equality to narrow when value is IntEnum/StrEnum (Jukka Lehtosalo, PR [17866](https://github.com/python/mypy/pull/17866)) + * Don't consider None vs IntEnum comparison ambiguous (Jukka Lehtosalo, PR [17877](https://github.com/python/mypy/pull/17877)) + * Fix narrowing of IntEnum and StrEnum types (Jukka Lehtosalo, PR [17874](https://github.com/python/mypy/pull/17874)) + * Filter overload items based on self type during type inference (Jukka Lehtosalo, PR [17873](https://github.com/python/mypy/pull/17873)) + * Enable negative narrowing of union TypeVar upper bounds (Brian Schubert, PR [17850](https://github.com/python/mypy/pull/17850)) + * Fix issue with member expression formatting (Brian Schubert, PR [17848](https://github.com/python/mypy/pull/17848)) + * Avoid type size explosion when expanding types (Jukka Lehtosalo, PR [17842](https://github.com/python/mypy/pull/17842)) + * Fix negative narrowing of tuples in match statement (Brian Schubert, PR [17817](https://github.com/python/mypy/pull/17817)) + * Narrow falsey str/bytes/int to literal type (Brian Schubert, PR [17818](https://github.com/python/mypy/pull/17818)) + * Test against latest Python 3.13, make testing 3.14 easy (Shantanu, PR [17812](https://github.com/python/mypy/pull/17812)) + * Reject ParamSpec-typed callables calls with insufficient arguments (Stanislav Terliakov, PR [17323](https://github.com/python/mypy/pull/17323)) + * Fix crash when passing too many type arguments to generic base class accepting single ParamSpec (Brian Schubert, PR [17770](https://github.com/python/mypy/pull/17770)) + * Fix TypeVar upper bounds sometimes not being displayed in pretty callables (Brian Schubert, PR [17802](https://github.com/python/mypy/pull/17802)) + * Added error code for overlapping function signatures (Katrina Connors, PR [17597](https://github.com/python/mypy/pull/17597)) + * Check for `truthy-bool` in `not ...` unary expressions (sobolevn, PR [17773](https://github.com/python/mypy/pull/17773)) + * Add missing lines-covered and lines-valid attributes (Soubhik Kumar Mitra, PR [17738](https://github.com/python/mypy/pull/17738)) + * Fix another crash scenario with recursive tuple types (Ivan Levkivskyi, PR [17708](https://github.com/python/mypy/pull/17708)) + * Resolve TypeVar upper bounds in `functools.partial` (Shantanu, PR [17660](https://github.com/python/mypy/pull/17660)) + * Always reset binder when checking deferred nodes (Ivan Levkivskyi, PR [17643](https://github.com/python/mypy/pull/17643)) + * Fix crash on a callable attribute with single unpack (Ivan Levkivskyi, PR [17641](https://github.com/python/mypy/pull/17641)) + * Fix mismatched signature between checker plugin API and implementation (bzoracler, PR [17343](https://github.com/python/mypy/pull/17343)) + * Indexing a type also produces a GenericAlias (Shantanu, PR [17546](https://github.com/python/mypy/pull/17546)) + * Fix crash on self-type in callable protocol (Ivan Levkivskyi, PR [17499](https://github.com/python/mypy/pull/17499)) + * Fix crash on NamedTuple with method and error in function (Ivan Levkivskyi, PR [17498](https://github.com/python/mypy/pull/17498)) + * Add `__replace__` for dataclasses in 3.13 (Max Muoto, PR [17469](https://github.com/python/mypy/pull/17469)) + * Fix help message for `--no-namespace-packages` (Raphael Krupinski, PR [17472](https://github.com/python/mypy/pull/17472)) + * Fix typechecking for async generators (Danny Yang, PR [17452](https://github.com/python/mypy/pull/17452)) + * Fix strict optional handling in attrs plugin (Ivan Levkivskyi, PR [17451](https://github.com/python/mypy/pull/17451)) + * Allow mixing ParamSpec and TypeVarTuple in Generic (Ivan Levkivskyi, PR [17450](https://github.com/python/mypy/pull/17450)) + * Improvements to `functools.partial` of types (Shantanu, PR [17898](https://github.com/python/mypy/pull/17898)) + * Make ReadOnly TypedDict items covariant (Jukka Lehtosalo, PR [17904](https://github.com/python/mypy/pull/17904)) + * Fix union callees with `functools.partial` (Jukka Lehtosalo, PR [17903](https://github.com/python/mypy/pull/17903)) + * Improve handling of generic functions with `functools.partial` (Ivan Levkivskyi, PR [17925](https://github.com/python/mypy/pull/17925)) + +### Typeshed Updates + +Please see [git log](https://github.com/python/typeshed/commits/main?after=91a58b07cdd807b1d965e04ba85af2adab8bf924+0&branch=main&path=stdlib) for full list of standard library typeshed stub changes. + +### Mypy 1.12.1 + * Fix crash when showing partially analyzed type in error message (Ivan Levkivskyi, PR [17961](https://github.com/python/mypy/pull/17961)) + * Fix iteration over union (when self type is involved) (Shantanu, PR [17976](https://github.com/python/mypy/pull/17976)) + * Fix type object with type var default in union context (Jukka Lehtosalo, PR [17991](https://github.com/python/mypy/pull/17991)) + * Revert change to `os.path` stubs affecting use of `os.PathLike[Any]` (Shantanu, PR [17995](https://github.com/python/mypy/pull/17995)) + +### Acknowledgements +Thanks to all mypy contributors who contributed to this release: + +- Ali Hamdan +- Anders Kaseorg +- Bénédikt Tran +- Brian Schubert +- bzoracler +- Chelsea Durazo +- Danny Yang +- Edgar Ramírez Mondragón +- Eric Mark Martin +- InSync +- Ivan Levkivskyi +- Jordandev678 +- Katrina Connors +- Kirill Podoprigora +- Marc Mueller +- Max Muoto +- Max Murin +- Michael Carlstrom +- Michael I Chen +- Pradyun Gedam +- quinn-sasha +- Raphael Krupinski +- Sebastian Rittau +- Shantanu +- sobolevn +- Soubhik Kumar Mitra +- Stanislav Terliakov +- wyattscarpenter + +I’d also like to thank my employer, Dropbox, for supporting mypy development. + ## Mypy 1.11 @@ -210,6 +842,15 @@ Mypyc now supports the new syntax for generics introduced in Python 3.12 (see ab Please see [git log](https://github.com/python/typeshed/commits/main?after=6dda799d8ad1d89e0f8aad7ac41d2d34bd838ace+0&branch=main&path=stdlib) for full list of standard library typeshed stub changes. +### Mypy 1.11.1 + * Fix `RawExpressionType.accept` crash with `--cache-fine-grained` (Anders Kaseorg, PR [17588](https://github.com/python/mypy/pull/17588)) + * Fix PEP 604 isinstance caching (Shantanu, PR [17563](https://github.com/python/mypy/pull/17563)) + * Fix `typing.TypeAliasType` being undefined on python < 3.12 (Nikita Sobolev, PR [17558](https://github.com/python/mypy/pull/17558)) + * Fix `types.GenericAlias` lookup crash (Shantanu, PR [17543](https://github.com/python/mypy/pull/17543)) + +### Mypy 1.11.2 + * Alternative fix for a union-like literal string (Ivan Levkivskyi, PR [17639](https://github.com/python/mypy/pull/17639)) + * Unwrap `TypedDict` item types before storing (Ivan Levkivskyi, PR [17640](https://github.com/python/mypy/pull/17640)) ### Acknowledgements Thanks to all mypy contributors who contributed to this release: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a5d339330a75..24f7e516e9e2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -65,16 +65,16 @@ However, if you wish to do so, you can run the full test suite like this: ```bash -python3 runtests.py +python runtests.py ``` Some useful commands for running specific tests include: ```bash # Use mypy to check mypy's own code -python3 runtests.py self +python runtests.py self # or equivalently: -python3 -m mypy --config-file mypy_self_check.ini -p mypy +python -m mypy --config-file mypy_self_check.ini -p mypy # Run a single test from the test suite pytest -n0 -k 'test_name' @@ -117,7 +117,7 @@ tox -e dev --override testenv:dev.allowlist_externals+=env -- env # inspect the ``` If you don't already have `tox` installed, you can use a virtual environment as -described above to install `tox` via `pip` (e.g., ``python3 -m pip install tox``). +described above to install `tox` via `pip` (e.g., ``python -m pip install tox``). ## First time contributors diff --git a/MANIFEST.in b/MANIFEST.in index c18b83cc0088..c2399d2b00b6 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -41,8 +41,8 @@ include runtests.py include pytest.ini include tox.ini -include LICENSE mypyc/README.md -exclude .gitmodules CONTRIBUTING.md CREDITS ROADMAP.md CHANGELOG.md action.yml .editorconfig +include LICENSE mypyc/README.md CHANGELOG.md +exclude .gitmodules CONTRIBUTING.md CREDITS ROADMAP.md action.yml .editorconfig exclude .git-blame-ignore-revs .pre-commit-config.yaml global-exclude *.py[cod] diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt index dc502d121ffc..a94c1b7ba95c 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,3 +1,3 @@ -sphinx>=5.1.0 +sphinx>=8.1.0 furo>=2022.3.4 myst-parser>=4.0.0 diff --git a/docs/source/command_line.rst b/docs/source/command_line.rst index 20fb3821438a..ea96e9f64790 100644 --- a/docs/source/command_line.rst +++ b/docs/source/command_line.rst @@ -166,6 +166,17 @@ imports. For more details, see :ref:`ignore-missing-imports`. +.. option:: --follow-untyped-imports + + This flag makes mypy analyze imports from installed packages even if + missing a :ref:`py.typed marker or stubs `. + + .. warning:: + + Note that analyzing all unannotated modules might result in issues + when analyzing code not designed to be type checked and may significantly + increase how long mypy takes to run. + .. option:: --follow-imports {normal,silent,skip,error} This flag adjusts how mypy follows imported modules that were not @@ -537,6 +548,12 @@ potentially problematic or redundant in some way. This limitation will be removed in future releases of mypy. +.. option:: --report-deprecated-as-note + + If error code ``deprecated`` is enabled, mypy emits errors if your code + imports or uses deprecated features. This flag converts such errors to + notes, causing mypy to eventually finish with a zero exit code. Features + are considered deprecated when decorated with ``warnings.deprecated``. .. _miscellaneous-strictness-flags: diff --git a/docs/source/conf.py b/docs/source/conf.py index f8faa03a09b2..ddc9923c6c93 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -51,7 +51,7 @@ # General information about the project. project = "mypy" -copyright = "2012-2022 Jukka Lehtosalo and mypy contributors" +copyright = "2012-%Y Jukka Lehtosalo and mypy contributors" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -107,6 +107,12 @@ # a list of builtin themes. html_theme = "furo" +html_theme_options = { + "source_repository": "https://github.com/python/mypy", + "source_branch": "master", + "source_directory": "docs/source", +} + # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. diff --git a/docs/source/config_file.rst b/docs/source/config_file.rst index ded8476b60e3..d7ae1b7a00df 100644 --- a/docs/source/config_file.rst +++ b/docs/source/config_file.rst @@ -315,6 +315,24 @@ section of the command line docs. match the name of the *imported* module, not the module containing the import statement. +.. confval:: follow_untyped_imports + + :type: boolean + :default: False + + Makes mypy analyze imports from installed packages even if missing a + :ref:`py.typed marker or stubs `. + + If this option is used in a per-module section, the module name should + match the name of the *imported* module, not the module containing the + import statement. + + .. warning:: + + Note that analyzing all unannotated modules might result in issues + when analyzing code not designed to be type checked and may significantly + increase how long mypy takes to run. + .. confval:: follow_imports :type: string @@ -717,6 +735,14 @@ section of the command line docs. Note: This option will override disabled error codes from the disable_error_code option. +.. confval:: extra_checks + + :type: boolean + :default: False + + This flag enables additional checks that are technically correct but may be impractical in real code. + See :option:`mypy --extra-checks` for more info. + .. confval:: implicit_reexport :type: boolean @@ -739,23 +765,23 @@ section of the command line docs. .. confval:: strict_concatenate - :type: boolean - :default: False + :type: boolean + :default: False - Make arguments prepended via ``Concatenate`` be truly positional-only. + Make arguments prepended via ``Concatenate`` be truly positional-only. .. confval:: strict_equality - :type: boolean - :default: False + :type: boolean + :default: False Prohibit equality checks, identity checks, and container checks between non-overlapping types. .. confval:: strict - :type: boolean - :default: False + :type: boolean + :default: False Enable all optional error checking flags. You can see the list of flags enabled by strict mode in the full :option:`mypy --help` diff --git a/docs/source/dynamic_typing.rst b/docs/source/dynamic_typing.rst index 1c31a535bdc1..304e25c085a8 100644 --- a/docs/source/dynamic_typing.rst +++ b/docs/source/dynamic_typing.rst @@ -86,7 +86,7 @@ treated as ``Any``: reveal_type(x[0]) # Revealed type is "Any" x[0].anything_goes() # OK -You can make mypy warn you about untyped function parameters using the +You can make mypy warn you about missing generic parameters using the :option:`--disallow-any-generics ` flag. Finally, another major source of ``Any`` types leaking into your program is from diff --git a/docs/source/error_code_list2.rst b/docs/source/error_code_list2.rst index 6d50e217a77d..df8b696745fc 100644 --- a/docs/source/error_code_list2.rst +++ b/docs/source/error_code_list2.rst @@ -231,6 +231,44 @@ incorrect control flow or conditional checks that are accidentally always true o # Error: Statement is unreachable [unreachable] print('unreachable') +.. _code-deprecated: + +Check that imported or used feature is deprecated [deprecated] +-------------------------------------------------------------- + +If you use :option:`--enable-error-code deprecated `, +mypy generates an error if your code imports a deprecated feature explicitly with a +``from mod import depr`` statement or uses a deprecated feature imported otherwise or defined +locally. Features are considered deprecated when decorated with ``warnings.deprecated``, as +specified in `PEP 702 `_. +Use the :option:`--report-deprecated-as-note ` option to +turn all such errors into notes. + +.. note:: + + The ``warnings`` module provides the ``@deprecated`` decorator since Python 3.13. + To use it with older Python versions, import it from ``typing_extensions`` instead. + +Examples: + +.. code-block:: python + + # mypy: report-deprecated-as-error + + # Error: abc.abstractproperty is deprecated: Deprecated, use 'property' with 'abstractmethod' instead + from abc import abstractproperty + + from typing_extensions import deprecated + + @deprecated("use new_function") + def old_function() -> None: + print("I am old") + + # Error: __main__.old_function is deprecated: use new_function + old_function() + old_function() # type: ignore[deprecated] + + .. _code-redundant-expr: Check that expression is redundant [redundant-expr] diff --git a/docs/source/extending_mypy.rst b/docs/source/extending_mypy.rst index bbbec2ad3880..0df45ea22d33 100644 --- a/docs/source/extending_mypy.rst +++ b/docs/source/extending_mypy.rst @@ -179,7 +179,7 @@ mypy will call ``get_method_signature_hook("ctypes.Array.__setitem__")`` so that the plugin can mimic the :py:mod:`ctypes` auto-convert behavior. **get_attribute_hook()** overrides instance member field lookups and property -access (not assignments, and not method calls). This hook is only called for +access (not method calls). This hook is only called for fields which already exist on the class. *Exception:* if :py:meth:`__getattr__ ` or :py:meth:`__getattribute__ ` is a method on the class, the hook is called for all fields which do not refer to methods. @@ -245,4 +245,4 @@ Mypy ships ``mypy.plugins.proper_plugin`` plugin which can be useful for plugin authors, since it finds missing ``get_proper_type()`` calls, which is a pretty common mistake. -It is recommended to enable it is a part of your plugin's CI. +It is recommended to enable it as a part of your plugin's CI. diff --git a/docs/source/generics.rst b/docs/source/generics.rst index 9c0a308ee39a..4ba6d322417d 100644 --- a/docs/source/generics.rst +++ b/docs/source/generics.rst @@ -146,7 +146,7 @@ example (Python 3.12 syntax): from typing import Mapping, Iterator # This is a generic subclass of Mapping - class MyMapp[KT, VT](Mapping[KT, VT]): + class MyMap[KT, VT](Mapping[KT, VT]): def __getitem__(self, k: KT) -> VT: ... def __iter__(self) -> Iterator[KT]: ... def __len__(self) -> int: ... @@ -641,7 +641,7 @@ infer the most flexible variance for each class type variable. Here .. code-block:: python - class Box[T]: # this type is implilicitly covariant + class Box[T]: # this type is implicitly covariant def __init__(self, content: T) -> None: self._content = content @@ -663,12 +663,12 @@ the attribute as ``Final``, the class could still be made covariant: from typing import Final - class Box[T]: # this type is implilicitly covariant + class Box[T]: # this type is implicitly covariant def __init__(self, content: T) -> None: self.content: Final = content def get_content(self) -> T: - return self._content + return self.content When using the legacy syntax, mypy assumes that all user-defined generics are invariant by default. To declare a given generic class as covariant or diff --git a/docs/source/running_mypy.rst b/docs/source/running_mypy.rst index 42474ae94c48..ff042b395e99 100644 --- a/docs/source/running_mypy.rst +++ b/docs/source/running_mypy.rst @@ -277,6 +277,25 @@ If you are getting this error, try to obtain type hints for the library you're u to the library -- see our documentation on creating :ref:`PEP 561 compliant packages `. +4. Force mypy to analyze the library as best as it can (as if the library provided + a ``py.typed`` file), despite it likely missing any type annotations. In general, + the quality of type checking will be poor and mypy may have issues when + analyzing code not designed to be type checked. + + You can do this via setting the + :option:`--follow-untyped-imports ` + command line flag or :confval:`follow_untyped_imports` config file option to True. + This option can be specified on a per-module basis as well:: + + # mypy.ini + [mypy-untyped_package.*] + follow_untyped_imports = True + + # pyproject.toml + [[tool.mypy.overrides]] + module = ["untyped_package.*"] + follow_untyped_imports = true + If you are unable to find any existing type hints nor have time to write your own, you can instead *suppress* the errors. @@ -295,9 +314,15 @@ not catch errors in its use. all import errors associated with that library and that library alone by adding the following section to your config file:: + # mypy.ini [mypy-foobar.*] ignore_missing_imports = True + # pyproject.toml + [[tool.mypy.overrides]] + module = ["foobar.*"] + ignore_missing_imports = true + Note: this option is equivalent to adding a ``# type: ignore`` to every import of ``foobar`` in your codebase. For more information, see the documentation about configuring @@ -311,9 +336,13 @@ not catch errors in its use. You can also set :confval:`disable_error_code`, like so:: + # mypy.ini [mypy] disable_error_code = import-untyped + # pyproject.toml + [tool.mypy] + disable_error_code = ["import-untyped"] You can also set the :option:`--ignore-missing-imports ` command line flag or set the :confval:`ignore_missing_imports` config file @@ -503,7 +532,7 @@ accepts one of four string values: main.py:1: note: (Using --follow-imports=error, module not passed on command line) If you are starting a new codebase and plan on using type hints from -the start, we recommend you use either :option:`--follow-imports=normal ` +the start, we **recommend** you use either :option:`--follow-imports=normal ` (the default) or :option:`--follow-imports=error `. Either option will help make sure you are not skipping checking any part of your codebase by accident. @@ -514,16 +543,27 @@ files that do not use type hints) pass under :option:`--follow-imports=normal `. Even if -mypy is unable to perfectly type check a file, it can still glean some +Only if doing this is intractable, try passing mypy just the files +you want to type check and using :option:`--follow-imports=silent `. +Even if mypy is unable to perfectly type check a file, it can still glean some useful information by parsing it (for example, understanding what methods a given object has). See :ref:`existing-code` for more recommendations. -We do not recommend using ``skip`` unless you know what you are doing: -while this option can be quite powerful, it can also cause many -hard-to-debug errors. - Adjusting import following behaviour is often most useful when restricted to specific modules. This can be accomplished by setting a per-module :confval:`follow_imports` config option. + +.. warning:: + + We do not recommend using ``follow_imports=skip`` unless you're really sure + you know what you are doing. This option greatly restricts the analysis mypy + can perform and you will lose a lot of the benefits of type checking. + + This is especially true at the global level. Setting a per-module + ``follow_imports=skip`` for a specific problematic module can be + useful without causing too much harm. + +.. note:: + + If you're looking to resolve import errors related to libraries, try following + the advice in :ref:`fix-missing-imports` before messing with ``follow_imports``. diff --git a/docs/source/type_narrowing.rst b/docs/source/type_narrowing.rst index 231a7edccfe7..697a1519a603 100644 --- a/docs/source/type_narrowing.rst +++ b/docs/source/type_narrowing.rst @@ -389,3 +389,169 @@ or rewrite the function to be slightly more verbose: elif b is not None: return b return C() + + +.. _typeis: + +TypeIs +------ + +Mypy supports TypeIs (:pep:`742`). + +A `TypeIs narrowing function `_ +allows you to define custom type checks that can narrow the type of a variable +in `both the if and else `_ +branches of a conditional, similar to how the built-in isinstance() function works. + +TypeIs is new in Python 3.13 — for use in older Python versions, use the backport +from `typing_extensions `_ + +Consider the following example using TypeIs: + +.. code-block:: python + + from typing import TypeIs + + def is_str(x: object) -> TypeIs[str]: + return isinstance(x, str) + + def process(x: int | str) -> None: + if is_str(x): + reveal_type(x) # Revealed type is 'str' + print(x.upper()) # Valid: x is str + else: + reveal_type(x) # Revealed type is 'int' + print(x + 1) # Valid: x is int + +In this example, the function is_str is a type narrowing function +that returns TypeIs[str]. When used in an if statement, x is narrowed +to str in the if branch and to int in the else branch. + +Key points: + + +- The function must accept at least one positional argument. + +- The return type is annotated as ``TypeIs[T]``, where ``T`` is the type you + want to narrow to. + +- The function must return a ``bool`` value. + +- In the ``if`` branch (when the function returns ``True``), the type of the + argument is narrowed to the intersection of its original type and ``T``. + +- In the ``else`` branch (when the function returns ``False``), the type of + the argument is narrowed to the intersection of its original type and the + complement of ``T``. + + +TypeIs vs TypeGuard +~~~~~~~~~~~~~~~~~~~ + +While both TypeIs and TypeGuard allow you to define custom type narrowing +functions, they differ in important ways: + +- **Type narrowing behavior**: TypeIs narrows the type in both the if and else branches, + whereas TypeGuard narrows only in the if branch. + +- **Compatibility requirement**: TypeIs requires that the narrowed type T be + compatible with the input type of the function. TypeGuard does not have this restriction. + +- **Type inference**: With TypeIs, the type checker may infer a more precise type by + combining existing type information with T. + +Here's an example demonstrating the behavior with TypeGuard: + +.. code-block:: python + + from typing import TypeGuard, reveal_type + + def is_str(x: object) -> TypeGuard[str]: + return isinstance(x, str) + + def process(x: int | str) -> None: + if is_str(x): + reveal_type(x) # Revealed type is "builtins.str" + print(x.upper()) # ok: x is str + else: + reveal_type(x) # Revealed type is "Union[builtins.int, builtins.str]" + print(x + 1) # ERROR: Unsupported operand types for + ("str" and "int") [operator] + +Generic TypeIs +~~~~~~~~~~~~~~ + +``TypeIs`` functions can also work with generic types: + +.. code-block:: python + + from typing import TypeVar, TypeIs + + T = TypeVar('T') + + def is_two_element_tuple(val: tuple[T, ...]) -> TypeIs[tuple[T, T]]: + return len(val) == 2 + + def process(names: tuple[str, ...]) -> None: + if is_two_element_tuple(names): + reveal_type(names) # Revealed type is 'tuple[str, str]' + else: + reveal_type(names) # Revealed type is 'tuple[str, ...]' + + +TypeIs with Additional Parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +TypeIs functions can accept additional parameters beyond the first. +The type narrowing applies only to the first argument. + +.. code-block:: python + + from typing import Any, TypeVar, reveal_type, TypeIs + + T = TypeVar('T') + + def is_instance_of(val: Any, typ: type[T]) -> TypeIs[T]: + return isinstance(val, typ) + + def process(x: Any) -> None: + if is_instance_of(x, int): + reveal_type(x) # Revealed type is 'int' + print(x + 1) # ok + else: + reveal_type(x) # Revealed type is 'Any' + +TypeIs in Methods +~~~~~~~~~~~~~~~~~ + +A method can also serve as a ``TypeIs`` function. Note that in instance or +class methods, the type narrowing applies to the second parameter +(after ``self`` or ``cls``). + +.. code-block:: python + + class Validator: + def is_valid(self, instance: object) -> TypeIs[str]: + return isinstance(instance, str) + + def process(self, to_validate: object) -> None: + if Validator().is_valid(to_validate): + reveal_type(to_validate) # Revealed type is 'str' + print(to_validate.upper()) # ok: to_validate is str + + +Assignment Expressions with TypeIs +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can use the assignment expression operator ``:=`` with ``TypeIs`` to create a new variable and narrow its type simultaneously. + +.. code-block:: python + + from typing import TypeIs, reveal_type + + def is_float(x: object) -> TypeIs[float]: + return isinstance(x, float) + + def main(a: object) -> None: + if is_float(x := a): + reveal_type(x) # Revealed type is 'float' + # x is narrowed to float in this block + print(x + 1.0) diff --git a/docs/source/typed_dict.rst b/docs/source/typed_dict.rst index e69b3895c668..bbb10a12abe8 100644 --- a/docs/source/typed_dict.rst +++ b/docs/source/typed_dict.rst @@ -236,6 +236,46 @@ another ``TypedDict`` if all required keys in the other ``TypedDict`` are requir first ``TypedDict``, and all non-required keys of the other ``TypedDict`` are also non-required keys in the first ``TypedDict``. +Read-only items +--------------- + +You can use ``typing.ReadOnly``, introduced in Python 3.13, or +``typing_extensions.ReadOnly`` to mark TypedDict items as read-only (:pep:`705`): + +.. code-block:: python + + from typing import TypedDict + + # Or "from typing ..." on Python 3.13+ + from typing_extensions import ReadOnly + + class Movie(TypedDict): + name: ReadOnly[str] + num_watched: int + + m: Movie = {"name": "Jaws", "num_watched": 1} + m["name"] = "The Godfather" # Error: "name" is read-only + m["num_watched"] += 1 # OK + +A TypedDict with a mutable item can be assigned to a TypedDict +with a corresponding read-only item, and the type of the item can +vary :ref:`covariantly `: + +.. code-block:: python + + class Entry(TypedDict): + name: ReadOnly[str | None] + year: ReadOnly[int] + + class Movie(TypedDict): + name: str + year: int + + def process_entry(i: Entry) -> None: ... + + m: Movie = {"name": "Jaws", "year": 1975} + process_entry(m) # OK + Unions of TypedDicts -------------------- diff --git a/misc/apply-cache-diff.py b/misc/apply-cache-diff.py index 29c55247de92..8ede9766bd06 100644 --- a/misc/apply-cache-diff.py +++ b/misc/apply-cache-diff.py @@ -8,13 +8,13 @@ from __future__ import annotations import argparse -import json import os import sys sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from mypy.metastore import FilesystemMetadataStore, MetadataStore, SqliteMetadataStore +from mypy.util import json_dumps, json_loads def make_cache(input_dir: str, sqlite: bool) -> MetadataStore: @@ -26,10 +26,10 @@ def make_cache(input_dir: str, sqlite: bool) -> MetadataStore: def apply_diff(cache_dir: str, diff_file: str, sqlite: bool = False) -> None: cache = make_cache(cache_dir, sqlite) - with open(diff_file) as f: - diff = json.load(f) + with open(diff_file, "rb") as f: + diff = json_loads(f.read()) - old_deps = json.loads(cache.read("@deps.meta.json")) + old_deps = json_loads(cache.read("@deps.meta.json")) for file, data in diff.items(): if data is None: @@ -37,10 +37,10 @@ def apply_diff(cache_dir: str, diff_file: str, sqlite: bool = False) -> None: else: cache.write(file, data) if file.endswith(".meta.json") and "@deps" not in file: - meta = json.loads(data) + meta = json_loads(data) old_deps["snapshot"][meta["id"]] = meta["hash"] - cache.write("@deps.meta.json", json.dumps(old_deps)) + cache.write("@deps.meta.json", json_dumps(old_deps)) cache.commit() diff --git a/misc/diff-cache.py b/misc/diff-cache.py index 15d3e5a83983..8441caf81304 100644 --- a/misc/diff-cache.py +++ b/misc/diff-cache.py @@ -8,7 +8,6 @@ from __future__ import annotations import argparse -import json import os import sys from collections import defaultdict @@ -17,6 +16,7 @@ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from mypy.metastore import FilesystemMetadataStore, MetadataStore, SqliteMetadataStore +from mypy.util import json_dumps, json_loads def make_cache(input_dir: str, sqlite: bool) -> MetadataStore: @@ -33,7 +33,7 @@ def merge_deps(all: dict[str, set[str]], new: dict[str, set[str]]) -> None: def load(cache: MetadataStore, s: str) -> Any: data = cache.read(s) - obj = json.loads(data) + obj = json_loads(data) if s.endswith(".meta.json"): # For meta files, zero out the mtimes and sort the # dependencies to avoid spurious conflicts @@ -73,7 +73,7 @@ def main() -> None: type_misses: dict[str, int] = defaultdict(int) type_hits: dict[str, int] = defaultdict(int) - updates: dict[str, str | None] = {} + updates: dict[str, bytes | None] = {} deps1: dict[str, set[str]] = {} deps2: dict[str, set[str]] = {} @@ -96,7 +96,7 @@ def main() -> None: # so we can produce a much smaller direct diff of them. if ".deps." not in s: if obj2 is not None: - updates[s] = json.dumps(obj2) + updates[s] = json_dumps(obj2) else: updates[s] = None elif obj2: @@ -122,7 +122,7 @@ def main() -> None: merge_deps(new_deps, root_deps) new_deps_json = {k: list(v) for k, v in new_deps.items() if v} - updates["@root.deps.json"] = json.dumps(new_deps_json) + updates["@root.deps.json"] = json_dumps(new_deps_json) # Drop updates to deps.meta.json for size reasons. The diff # applier will manually fix it up. @@ -136,8 +136,8 @@ def main() -> None: print("hits", type_hits) print("misses", type_misses) - with open(args.output, "w") as f: - json.dump(updates, f) + with open(args.output, "wb") as f: + f.write(json_dumps(updates)) if __name__ == "__main__": diff --git a/misc/typeshed_patches/0001-Remove-use-of-LiteralString-in-builtins-13743.patch b/misc/typeshed_patches/0001-Remove-use-of-LiteralString-in-builtins-13743.patch index 683b0c322b71..91e255242ee9 100644 --- a/misc/typeshed_patches/0001-Remove-use-of-LiteralString-in-builtins-13743.patch +++ b/misc/typeshed_patches/0001-Remove-use-of-LiteralString-in-builtins-13743.patch @@ -1,17 +1,17 @@ -From 3ec9b878d6bbe3fae64a508a62372f10a886406f Mon Sep 17 00:00:00 2001 +From b4259edd94188f9e4cc77a22e768eea183a32053 Mon Sep 17 00:00:00 2001 From: Shantanu <12621235+hauntsaninja@users.noreply.github.com> Date: Mon, 26 Sep 2022 12:55:07 -0700 Subject: [PATCH] Remove use of LiteralString in builtins (#13743) --- - mypy/typeshed/stdlib/builtins.pyi | 95 ------------------------------- - 1 file changed, 95 deletions(-) + mypy/typeshed/stdlib/builtins.pyi | 100 +----------------------------- + 1 file changed, 1 insertion(+), 99 deletions(-) diff --git a/mypy/typeshed/stdlib/builtins.pyi b/mypy/typeshed/stdlib/builtins.pyi -index 53e00ec6a..bad3250ef 100644 +index 63c53a5f6..d55042b56 100644 --- a/mypy/typeshed/stdlib/builtins.pyi +++ b/mypy/typeshed/stdlib/builtins.pyi -@@ -61,7 +61,6 @@ from typing import ( # noqa: Y022 +@@ -63,7 +63,6 @@ from typing import ( # noqa: Y022 from typing_extensions import ( # noqa: Y023 Concatenate, Literal, @@ -19,7 +19,7 @@ index 53e00ec6a..bad3250ef 100644 ParamSpec, Self, TypeAlias, -@@ -435,31 +434,16 @@ class str(Sequence[str]): +@@ -438,31 +437,16 @@ class str(Sequence[str]): def __new__(cls, object: object = ...) -> Self: ... @overload def __new__(cls, object: ReadableBuffer, encoding: str = ..., errors: str = ...) -> Self: ... @@ -51,7 +51,7 @@ index 53e00ec6a..bad3250ef 100644 def format(self, *args: object, **kwargs: object) -> str: ... def format_map(self, mapping: _FormatMapMapping, /) -> str: ... def index(self, sub: str, start: SupportsIndex | None = ..., end: SupportsIndex | None = ..., /) -> int: ... -@@ -475,99 +459,35 @@ class str(Sequence[str]): +@@ -478,99 +462,35 @@ class str(Sequence[str]): def isspace(self) -> bool: ... def istitle(self) -> bool: ... def isupper(self) -> bool: ... @@ -151,7 +151,7 @@ index 53e00ec6a..bad3250ef 100644 def zfill(self, width: SupportsIndex, /) -> str: ... # type: ignore[misc] @staticmethod @overload -@@ -578,9 +498,6 @@ class str(Sequence[str]): +@@ -581,39 +501,21 @@ class str(Sequence[str]): @staticmethod @overload def maketrans(x: str, y: str, z: str, /) -> dict[int, int | None]: ... @@ -161,8 +161,13 @@ index 53e00ec6a..bad3250ef 100644 def __add__(self, value: str, /) -> str: ... # type: ignore[misc] # Incompatible with Sequence.__contains__ def __contains__(self, key: str, /) -> bool: ... # type: ignore[override] -@@ -589,25 +506,13 @@ class str(Sequence[str]): - def __getitem__(self, key: SupportsIndex | slice, /) -> str: ... + def __eq__(self, value: object, /) -> bool: ... + def __ge__(self, value: str, /) -> bool: ... +- @overload +- def __getitem__(self: LiteralString, key: SupportsIndex | slice, /) -> LiteralString: ... +- @overload +- def __getitem__(self, key: SupportsIndex | slice, /) -> str: ... # type: ignore[misc] ++ def __getitem__(self, key: SupportsIndex | slice, /) -> str: ... def __gt__(self, value: str, /) -> bool: ... def __hash__(self) -> int: ... - @overload @@ -188,5 +193,5 @@ index 53e00ec6a..bad3250ef 100644 def __getnewargs__(self) -> tuple[str]: ... -- -2.45.2 +2.47.0 diff --git a/mypy/binder.py b/mypy/binder.py index 9d0a33b54bc2..52ae9774e6d4 100644 --- a/mypy/binder.py +++ b/mypy/binder.py @@ -2,7 +2,7 @@ from collections import defaultdict from contextlib import contextmanager -from typing import DefaultDict, Iterator, List, Optional, Tuple, Union, cast +from typing import DefaultDict, Iterator, List, NamedTuple, Optional, Tuple, Union from typing_extensions import TypeAlias as _TypeAlias from mypy.erasetype import remove_instance_last_known_values @@ -30,6 +30,11 @@ BindableExpression: _TypeAlias = Union[IndexExpr, MemberExpr, NameExpr] +class CurrentType(NamedTuple): + type: Type + from_assignment: bool + + class Frame: """A Frame represents a specific point in the execution of a program. It carries information about the current types of expressions at @@ -44,7 +49,7 @@ class Frame: def __init__(self, id: int, conditional_frame: bool = False) -> None: self.id = id - self.types: dict[Key, Type] = {} + self.types: dict[Key, CurrentType] = {} self.unreachable = False self.conditional_frame = conditional_frame self.suppress_unreachable_warnings = False @@ -132,10 +137,10 @@ def push_frame(self, conditional_frame: bool = False) -> Frame: self.options_on_return.append([]) return f - def _put(self, key: Key, type: Type, index: int = -1) -> None: - self.frames[index].types[key] = type + def _put(self, key: Key, type: Type, from_assignment: bool, index: int = -1) -> None: + self.frames[index].types[key] = CurrentType(type, from_assignment) - def _get(self, key: Key, index: int = -1) -> Type | None: + def _get(self, key: Key, index: int = -1) -> CurrentType | None: if index < 0: index += len(self.frames) for i in range(index, -1, -1): @@ -143,7 +148,7 @@ def _get(self, key: Key, index: int = -1) -> Type | None: return self.frames[i].types[key] return None - def put(self, expr: Expression, typ: Type) -> None: + def put(self, expr: Expression, typ: Type, *, from_assignment: bool = True) -> None: if not isinstance(expr, (IndexExpr, MemberExpr, NameExpr)): return if not literal(expr): @@ -153,7 +158,7 @@ def put(self, expr: Expression, typ: Type) -> None: if key not in self.declarations: self.declarations[key] = get_declaration(expr) self._add_dependencies(key) - self._put(key, typ) + self._put(key, typ, from_assignment) def unreachable(self) -> None: self.frames[-1].unreachable = True @@ -164,7 +169,10 @@ def suppress_unreachable_warnings(self) -> None: def get(self, expr: Expression) -> Type | None: key = literal_hash(expr) assert key is not None, "Internal error: binder tried to get non-literal" - return self._get(key) + found = self._get(key) + if found is None: + return None + return found.type def is_unreachable(self) -> bool: # TODO: Copy the value of unreachable into new frames to avoid @@ -193,7 +201,7 @@ def update_from_options(self, frames: list[Frame]) -> bool: If a key is declared as AnyType, only update it if all the options are the same. """ - + all_reachable = all(not f.unreachable for f in frames) frames = [f for f in frames if not f.unreachable] changed = False keys = {key for f in frames for key in f.types} @@ -207,17 +215,30 @@ def update_from_options(self, frames: list[Frame]) -> bool: # know anything about key in at least one possible frame. continue - type = resulting_values[0] - assert type is not None + if all_reachable and all( + x is not None and not x.from_assignment for x in resulting_values + ): + # Do not synthesize a new type if we encountered a conditional block + # (if, while or match-case) without assignments. + # See check-isinstance.test::testNoneCheckDoesNotMakeTypeVarOptional + # This is a safe assumption: the fact that we checked something with `is` + # or `isinstance` does not change the type of the value. + continue + + current_type = resulting_values[0] + assert current_type is not None + type = current_type.type declaration_type = get_proper_type(self.declarations.get(key)) if isinstance(declaration_type, AnyType): # At this point resulting values can't contain None, see continue above - if not all(is_same_type(type, cast(Type, t)) for t in resulting_values[1:]): + if not all( + t is not None and is_same_type(type, t.type) for t in resulting_values[1:] + ): type = AnyType(TypeOfAny.from_another_any, source_any=declaration_type) else: for other in resulting_values[1:]: assert other is not None - type = join_simple(self.declarations[key], type, other) + type = join_simple(self.declarations[key], type, other.type) # Try simplifying resulting type for unions involving variadic tuples. # Technically, everything is still valid without this step, but if we do # not do this, this may create long unions after exiting an if check like: @@ -236,8 +257,8 @@ def update_from_options(self, frames: list[Frame]) -> bool: ) if simplified == self.declarations[key]: type = simplified - if current_value is None or not is_same_type(type, current_value): - self._put(key, type) + if current_value is None or not is_same_type(type, current_value[0]): + self._put(key, type, from_assignment=True) changed = True self.frames[-1].unreachable = not frames @@ -374,7 +395,9 @@ def most_recent_enclosing_type(self, expr: BindableExpression, type: Type) -> Ty key = literal_hash(expr) assert key is not None enclosers = [get_declaration(expr)] + [ - f.types[key] for f in self.frames if key in f.types and is_subtype(type, f.types[key]) + f.types[key].type + for f in self.frames + if key in f.types and is_subtype(type, f.types[key][0]) ] return enclosers[-1] diff --git a/mypy/build.py b/mypy/build.py index 733f0685792e..40dd73313335 100644 --- a/mypy/build.py +++ b/mypy/build.py @@ -59,7 +59,7 @@ get_mypy_comments, hash_digest, is_stub_package_file, - is_sub_path, + is_sub_path_normabs, is_typeshed_file, module_prefix, read_py_file, @@ -92,9 +92,10 @@ from mypy.plugins.default import DefaultPlugin from mypy.renaming import LimitedVariableRenameVisitor, VariableRenameVisitor from mypy.stats import dump_type_stats -from mypy.stubinfo import legacy_bundled_packages, non_bundled_packages, stub_distribution_name +from mypy.stubinfo import is_module_from_legacy_bundled_package, stub_distribution_name from mypy.types import Type from mypy.typestate import reset_global_state, type_state +from mypy.util import json_dumps, json_loads from mypy.version import __version__ # Switch to True to produce debug output related to fine-grained incremental @@ -664,7 +665,7 @@ def __init__( for module in CORE_BUILTIN_MODULES: if options.use_builtins_fixtures: continue - path = self.find_module_cache.find_module(module) + path = self.find_module_cache.find_module(module, fast_path=True) if not isinstance(path, str): raise CompileError( [f"Failed to find builtin module {module}, perhaps typeshed is broken?"] @@ -736,8 +737,8 @@ def maybe_swap_for_shadow_path(self, path: str) -> str: shadow_file = self.shadow_equivalence_map.get(path) return shadow_file if shadow_file else path - def get_stat(self, path: str) -> os.stat_result: - return self.fscache.stat(self.maybe_swap_for_shadow_path(path)) + def get_stat(self, path: str) -> os.stat_result | None: + return self.fscache.stat_or_none(self.maybe_swap_for_shadow_path(path)) def getmtime(self, path: str) -> int: """Return a file's mtime; but 0 in bazel mode. @@ -858,7 +859,7 @@ def load_fine_grained_deps(self, id: str) -> dict[str, set[str]]: t0 = time.time() if id in self.fg_deps_meta: # TODO: Assert deps file wasn't changed. - deps = json.loads(self.metastore.read(self.fg_deps_meta[id]["path"])) + deps = json_loads(self.metastore.read(self.fg_deps_meta[id]["path"])) else: deps = {} val = {k: set(v) for k, v in deps.items()} @@ -911,8 +912,8 @@ def stats_summary(self) -> Mapping[str, object]: return self.stats -def deps_to_json(x: dict[str, set[str]]) -> str: - return json.dumps({k: list(v) for k, v in x.items()}, separators=(",", ":")) +def deps_to_json(x: dict[str, set[str]]) -> bytes: + return json_dumps({k: list(v) for k, v in x.items()}) # File for storing metadata about all the fine-grained dependency caches @@ -980,7 +981,7 @@ def write_deps_cache( meta = {"snapshot": meta_snapshot, "deps_meta": fg_deps_meta} - if not metastore.write(DEPS_META_FILE, json.dumps(meta, separators=(",", ":"))): + if not metastore.write(DEPS_META_FILE, json_dumps(meta)): manager.log(f"Error writing fine-grained deps meta JSON file {DEPS_META_FILE}") error = True @@ -1048,8 +1049,11 @@ def generate_deps_for_cache(manager: BuildManager, graph: Graph) -> dict[str, di def write_plugins_snapshot(manager: BuildManager) -> None: """Write snapshot of versions and hashes of currently active plugins.""" - snapshot = json.dumps(manager.plugins_snapshot, separators=(",", ":")) - if not manager.metastore.write(PLUGIN_SNAPSHOT_FILE, snapshot): + snapshot = json_dumps(manager.plugins_snapshot) + if ( + not manager.metastore.write(PLUGIN_SNAPSHOT_FILE, snapshot) + and manager.options.cache_dir != os.devnull + ): manager.errors.set_file(_cache_dir_prefix(manager.options), None, manager.options) manager.errors.report(0, 0, "Error writing plugins snapshot", blocker=True) @@ -1079,8 +1083,8 @@ def read_quickstart_file( # just ignore it. raw_quickstart: dict[str, Any] = {} try: - with open(options.quickstart_file) as f: - raw_quickstart = json.load(f) + with open(options.quickstart_file, "rb") as f: + raw_quickstart = json_loads(f.read()) quickstart = {} for file, (x, y, z) in raw_quickstart.items(): @@ -1148,10 +1152,10 @@ def _load_json_file( manager.add_stats(metastore_read_time=time.time() - t0) # Only bother to compute the log message if we are logging it, since it could be big if manager.verbosity() >= 2: - manager.trace(log_success + data.rstrip()) + manager.trace(log_success + data.rstrip().decode()) try: t1 = time.time() - result = json.loads(data) + result = json_loads(data) manager.add_stats(data_json_load_time=time.time() - t1) except json.JSONDecodeError: manager.errors.set_file(file, None, manager.options) @@ -1343,8 +1347,8 @@ def find_cache_meta(id: str, path: str, manager: BuildManager) -> CacheMeta | No # So that plugins can return data with tuples in it without # things silently always invalidating modules, we round-trip # the config data. This isn't beautiful. - plugin_data = json.loads( - json.dumps(manager.plugin.report_config_data(ReportConfigContext(id, path, is_check=True))) + plugin_data = json_loads( + json_dumps(manager.plugin.report_config_data(ReportConfigContext(id, path, is_check=True))) ) if m.plugin_data != plugin_data: manager.log(f"Metadata abandoned for {id}: plugin configuration differs") @@ -1394,9 +1398,9 @@ def validate_meta( if bazel: # Normalize path under bazel to make sure it isn't absolute path = normpath(path, manager.options) - try: - st = manager.get_stat(path) - except OSError: + + st = manager.get_stat(path) + if st is None: return None if not stat.S_ISDIR(st.st_mode) and not stat.S_ISREG(st.st_mode): manager.log(f"Metadata abandoned for {id}: file or directory {path} does not exist") @@ -1478,10 +1482,7 @@ def validate_meta( "ignore_all": meta.ignore_all, "plugin_data": meta.plugin_data, } - if manager.options.debug_cache: - meta_str = json.dumps(meta_dict, indent=2, sort_keys=True) - else: - meta_str = json.dumps(meta_dict, separators=(",", ":")) + meta_bytes = json_dumps(meta_dict, manager.options.debug_cache) meta_json, _, _ = get_cache_names(id, path, manager.options) manager.log( "Updating mtime for {}: file {}, meta {}, mtime {}".format( @@ -1489,7 +1490,7 @@ def validate_meta( ) ) t1 = time.time() - manager.metastore.write(meta_json, meta_str) # Ignore errors, just an optimization. + manager.metastore.write(meta_json, meta_bytes) # Ignore errors, just an optimization. manager.add_stats(validate_update_time=time.time() - t1, validate_munging_time=t1 - t0) return meta @@ -1507,13 +1508,6 @@ def compute_hash(text: str) -> str: return hash_digest(text.encode("utf-8")) -def json_dumps(obj: Any, debug_cache: bool) -> str: - if debug_cache: - return json.dumps(obj, indent=2, sort_keys=True) - else: - return json.dumps(obj, sort_keys=True, separators=(",", ":")) - - def write_cache( id: str, path: str, @@ -1566,16 +1560,15 @@ def write_cache( # Serialize data and analyze interface data = tree.serialize() - data_str = json_dumps(data, manager.options.debug_cache) - interface_hash = compute_hash(data_str) + data_bytes = json_dumps(data, manager.options.debug_cache) + interface_hash = hash_digest(data_bytes) plugin_data = manager.plugin.report_config_data(ReportConfigContext(id, path, is_check=False)) # Obtain and set up metadata - try: - st = manager.get_stat(path) - except OSError as err: - manager.log(f"Cannot get stat for {path}: {err}") + st = manager.get_stat(path) + if st is None: + manager.log(f"Cannot get stat for {path}") # Remove apparently-invalid cache files. # (This is purely an optimization.) for filename in [data_json, meta_json]: @@ -1592,7 +1585,7 @@ def write_cache( manager.trace(f"Interface for {id} is unchanged") else: manager.trace(f"Interface for {id} has changed") - if not metastore.write(data_json, data_str): + if not metastore.write(data_json, data_bytes): # Most likely the error is the replace() call # (see https://github.com/python/mypy/issues/3215). manager.log(f"Error writing data JSON file {data_json}") @@ -2150,10 +2143,12 @@ def parse_file(self, *, temporary: bool = False) -> None: # other systems, but os.strerror(ioerr.errno) does not, so we use that. # (We want the error messages to be platform-independent so that the # tests have predictable output.) + assert ioerr.errno is not None raise CompileError( [ "mypy: can't read file '{}': {}".format( - self.path, os.strerror(ioerr.errno) + self.path.replace(os.getcwd() + os.sep, ""), + os.strerror(ioerr.errno), ) ], module_with_blocker=self.id, @@ -2668,17 +2663,13 @@ def find_module_and_diagnose( ignore_missing_imports = options.ignore_missing_imports - id_components = id.split(".") # Don't honor a global (not per-module) ignore_missing_imports # setting for modules that used to have bundled stubs, as # otherwise updating mypy can silently result in new false # negatives. (Unless there are stubs but they are incomplete.) global_ignore_missing_imports = manager.options.ignore_missing_imports if ( - any( - ".".join(id_components[:i]) in legacy_bundled_packages - for i in range(len(id_components), 0, -1) - ) + is_module_from_legacy_bundled_package(id) and global_ignore_missing_imports and not options.ignore_missing_imports_per_module and result is ModuleNotFoundReason.APPROVED_STUBS_NOT_INSTALLED @@ -2726,7 +2717,9 @@ def exist_added_packages(suppressed: list[str], manager: BuildManager, options: def find_module_simple(id: str, manager: BuildManager) -> str | None: """Find a filesystem path for module `id` or `None` if not found.""" - x = find_module_with_reason(id, manager) + t0 = time.time() + x = manager.find_module_cache.find_module(id, fast_path=True) + manager.add_stats(find_module_time=time.time() - t0, find_module_calls=1) if isinstance(x, ModuleNotFoundReason): return None return x @@ -2735,7 +2728,7 @@ def find_module_simple(id: str, manager: BuildManager) -> str | None: def find_module_with_reason(id: str, manager: BuildManager) -> ModuleSearchResult: """Find a filesystem path for module `id` or the reason it can't be found.""" t0 = time.time() - x = manager.find_module_cache.find_module(id) + x = manager.find_module_cache.find_module(id, fast_path=False) manager.add_stats(find_module_time=time.time() - t0, find_module_calls=1) return x @@ -2797,18 +2790,15 @@ def module_not_found( code = codes.IMPORT errors.report(line, 0, msg.format(module=target), code=code) - components = target.split(".") - for i in range(len(components), 0, -1): - module = ".".join(components[:i]) - if module in legacy_bundled_packages or module in non_bundled_packages: - break - + dist = stub_distribution_name(target) for note in notes: if "{stub_dist}" in note: - note = note.format(stub_dist=stub_distribution_name(module)) + assert dist is not None + note = note.format(stub_dist=dist) errors.report(line, 0, note, severity="note", only_once=True, code=code) if reason is ModuleNotFoundReason.APPROVED_STUBS_NOT_INSTALLED: - manager.missing_stub_packages.add(stub_distribution_name(module)) + assert dist is not None + manager.missing_stub_packages.add(dist) errors.set_import_context(save_import_context) @@ -2876,7 +2866,7 @@ def log_configuration(manager: BuildManager, sources: list[BuildSource]) -> None manager.log(f"{'Found source:':24}{source}") # Complete list of searched paths can get very long, put them under TRACE - for path_type, paths in manager.search_paths._asdict().items(): + for path_type, paths in manager.search_paths.asdict().items(): if not paths: manager.trace(f"No {path_type}") continue @@ -3543,10 +3533,9 @@ def is_silent_import_module(manager: BuildManager, path: str) -> bool: if manager.options.no_silence_site_packages: return False # Silence errors in site-package dirs and typeshed - return any( - is_sub_path(path, dir) - for dir in manager.search_paths.package_path + manager.search_paths.typeshed_path - ) + if any(is_sub_path_normabs(path, dir) for dir in manager.search_paths.package_path): + return True + return any(is_sub_path_normabs(path, dir) for dir in manager.search_paths.typeshed_path) def write_undocumented_ref_info( @@ -3567,4 +3556,4 @@ def write_undocumented_ref_info( assert not ref_info_file.startswith(".") deps_json = get_undocumented_ref_info_json(state.tree, type_map) - metastore.write(ref_info_file, json.dumps(deps_json, separators=(",", ":"))) + metastore.write(ref_info_file, json_dumps(deps_json)) diff --git a/mypy/checker.py b/mypy/checker.py index 8d77bb02eeb2..2edcaa6bc5c5 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -686,10 +686,10 @@ def extract_callable_type(self, inner_type: Type | None, ctx: Context) -> Callab if isinstance(inner_type, TypeVarLikeType): inner_type = get_proper_type(inner_type.upper_bound) if isinstance(inner_type, TypeType): - if isinstance(inner_type.item, Instance): - inner_type = expand_type_by_instance( - type_object_type(inner_type.item.type, self.named_type), inner_type.item - ) + inner_type = get_proper_type( + self.expr_checker.analyze_type_type_callee(inner_type.item, ctx) + ) + if isinstance(inner_type, CallableType): outer_type = inner_type elif isinstance(inner_type, Instance): @@ -1060,46 +1060,7 @@ def _visit_func_def(self, defn: FuncDef) -> None: if defn.original_def: # Override previous definition. new_type = self.function_type(defn) - if isinstance(defn.original_def, FuncDef): - # Function definition overrides function definition. - old_type = self.function_type(defn.original_def) - if not is_same_type(new_type, old_type): - self.msg.incompatible_conditional_function_def(defn, old_type, new_type) - else: - # Function definition overrides a variable initialized via assignment or a - # decorated function. - orig_type = defn.original_def.type - if orig_type is None: - # If other branch is unreachable, we don't type check it and so we might - # not have a type for the original definition - return - if isinstance(orig_type, PartialType): - if orig_type.type is None: - # Ah this is a partial type. Give it the type of the function. - orig_def = defn.original_def - if isinstance(orig_def, Decorator): - var = orig_def.var - else: - var = orig_def - partial_types = self.find_partial_types(var) - if partial_types is not None: - var.type = new_type - del partial_types[var] - else: - # Trying to redefine something like partial empty list as function. - self.fail(message_registry.INCOMPATIBLE_REDEFINITION, defn) - else: - name_expr = NameExpr(defn.name) - name_expr.node = defn.original_def - self.binder.assign_type(name_expr, new_type, orig_type) - self.check_subtype( - new_type, - orig_type, - defn, - message_registry.INCOMPATIBLE_REDEFINITION, - "redefinition with type", - "original type", - ) + self.check_func_def_override(defn, new_type) def check_func_item( self, @@ -1135,6 +1096,49 @@ def check_func_item( if dataclasses_plugin.is_processed_dataclass(defn.info): dataclasses_plugin.check_post_init(self, defn, defn.info) + def check_func_def_override(self, defn: FuncDef, new_type: FunctionLike) -> None: + assert defn.original_def is not None + if isinstance(defn.original_def, FuncDef): + # Function definition overrides function definition. + old_type = self.function_type(defn.original_def) + if not is_same_type(new_type, old_type): + self.msg.incompatible_conditional_function_def(defn, old_type, new_type) + else: + # Function definition overrides a variable initialized via assignment or a + # decorated function. + orig_type = defn.original_def.type + if orig_type is None: + # If other branch is unreachable, we don't type check it and so we might + # not have a type for the original definition + return + if isinstance(orig_type, PartialType): + if orig_type.type is None: + # Ah this is a partial type. Give it the type of the function. + orig_def = defn.original_def + if isinstance(orig_def, Decorator): + var = orig_def.var + else: + var = orig_def + partial_types = self.find_partial_types(var) + if partial_types is not None: + var.type = new_type + del partial_types[var] + else: + # Trying to redefine something like partial empty list as function. + self.fail(message_registry.INCOMPATIBLE_REDEFINITION, defn) + else: + name_expr = NameExpr(defn.name) + name_expr.node = defn.original_def + self.binder.assign_type(name_expr, new_type, orig_type) + self.check_subtype( + new_type, + orig_type, + defn, + message_registry.INCOMPATIBLE_REDEFINITION, + "redefinition with type", + "original type", + ) + @contextmanager def enter_attribute_inference_context(self) -> Iterator[None]: old_types = self.inferred_attribute_types @@ -1147,6 +1151,7 @@ def check_func_def( ) -> None: """Type check a function definition.""" # Expand type variables with value restrictions to ordinary types. + self.check_typevar_defaults(typ.variables) expanded = self.expand_typevars(defn, typ) original_typ = typ for item, typ in expanded: @@ -2131,7 +2136,7 @@ def check_method_override_for_base_with_name( pass elif isinstance(original_type, FunctionLike) and isinstance(typ, FunctionLike): # Check that the types are compatible. - self.check_override( + ok = self.check_override( typ, original_type, defn.name, @@ -2141,6 +2146,41 @@ def check_method_override_for_base_with_name( override_class_or_static, context, ) + # Check if this override is covariant. + if ( + ok + and original_node + and codes.MUTABLE_OVERRIDE in self.options.enabled_error_codes + and self.is_writable_attribute(original_node) + and not is_subtype(original_type, typ, ignore_pos_arg_names=True) + ): + base_str, override_str = format_type_distinctly( + original_type, typ, options=self.options + ) + msg = message_registry.COVARIANT_OVERRIDE_OF_MUTABLE_ATTRIBUTE.with_additional_msg( + f' (base class "{base.name}" defined the type as {base_str},' + f" override has type {override_str})" + ) + self.fail(msg, context) + elif isinstance(original_type, UnionType) and any( + is_subtype(typ, orig_typ, ignore_pos_arg_names=True) + for orig_typ in original_type.items + ): + # This method is a subtype of at least one union variant. + if ( + original_node + and codes.MUTABLE_OVERRIDE in self.options.enabled_error_codes + and self.is_writable_attribute(original_node) + ): + # Covariant override of mutable attribute. + base_str, override_str = format_type_distinctly( + original_type, typ, options=self.options + ) + msg = message_registry.COVARIANT_OVERRIDE_OF_MUTABLE_ATTRIBUTE.with_additional_msg( + f' (base class "{base.name}" defined the type as {base_str},' + f" override has type {override_str})" + ) + self.fail(msg, context) elif is_equivalent(original_type, typ): # Assume invariance for a non-callable attribute here. Note # that this doesn't affect read-only properties which can have @@ -2230,7 +2270,7 @@ def check_override( original_class_or_static: bool, override_class_or_static: bool, node: Context, - ) -> None: + ) -> bool: """Check a method override with given signatures. Arguments: @@ -2327,10 +2367,11 @@ def erase_override(t: Type) -> Type: else: continue if not is_subtype(original_arg_type, erase_override(override_arg_type)): + context: Context = node if isinstance(node, FuncDef) and not node.is_property: - context: Context = node.arguments[i + len(override.bound_args)] - else: - context = node + arg_node = node.arguments[i + len(override.bound_args)] + if arg_node.line != -1: + context = arg_node self.msg.argument_incompatible_with_supertype( i + 1, name, @@ -2380,6 +2421,7 @@ def erase_override(t: Type) -> Type: node, code=codes.OVERRIDE, ) + return not fail def check__exit__return_type(self, defn: FuncItem) -> None: """Generate error if the return type of __exit__ is problematic. @@ -2471,6 +2513,8 @@ def visit_class_def(self, defn: ClassDef) -> None: context=defn, code=codes.TYPE_VAR, ) + if typ.defn.type_vars: + self.check_typevar_defaults(typ.defn.type_vars) if typ.is_protocol and typ.defn.type_vars: self.check_protocol_variance(defn) @@ -2534,22 +2578,41 @@ def check_init_subclass(self, defn: ClassDef) -> None: # all other bases have already been checked. break + def check_typevar_defaults(self, tvars: Sequence[TypeVarLikeType]) -> None: + for tv in tvars: + if not (isinstance(tv, TypeVarType) and tv.has_default()): + continue + if not is_subtype(tv.default, tv.upper_bound): + self.fail("TypeVar default must be a subtype of the bound type", tv) + if tv.values and not any(tv.default == value for value in tv.values): + self.fail("TypeVar default must be one of the constraint types", tv) + def check_enum(self, defn: ClassDef) -> None: assert defn.info.is_enum - if defn.info.fullname not in ENUM_BASES: - for sym in defn.info.names.values(): - if ( - isinstance(sym.node, Var) - and sym.node.has_explicit_value - and sym.node.name == "__members__" - ): - # `__members__` will always be overwritten by `Enum` and is considered - # read-only so we disallow assigning a value to it - self.fail(message_registry.ENUM_MEMBERS_ATTR_WILL_BE_OVERRIDEN, sym.node) + if defn.info.fullname not in ENUM_BASES and "__members__" in defn.info.names: + sym = defn.info.names["__members__"] + if isinstance(sym.node, Var) and sym.node.has_explicit_value: + # `__members__` will always be overwritten by `Enum` and is considered + # read-only so we disallow assigning a value to it + self.fail(message_registry.ENUM_MEMBERS_ATTR_WILL_BE_OVERRIDEN, sym.node) for base in defn.info.mro[1:-1]: # we don't need self and `object` if base.is_enum and base.fullname not in ENUM_BASES: self.check_final_enum(defn, base) + if self.is_stub and self.tree.fullname not in {"enum", "_typeshed"}: + if not defn.info.enum_members: + self.fail( + f'Detected enum "{defn.info.fullname}" in a type stub with zero members. ' + "There is a chance this is due to a recent change in the semantics of " + "enum membership. If so, use `member = value` to mark an enum member, " + "instead of `member: type`", + defn, + ) + self.note( + "See https://typing.readthedocs.io/en/latest/spec/enums.html#defining-members", + defn, + ) + self.check_enum_bases(defn) self.check_enum_new(defn) @@ -2838,6 +2901,9 @@ def check_metaclass_compatibility(self, typ: TypeInfo) -> None: ) def visit_import_from(self, node: ImportFrom) -> None: + for name, _ in node.names: + if (sym := self.globals.get(name)) is not None: + self.warn_deprecated(sym.node, node) self.check_import(node) def visit_import_all(self, node: ImportAll) -> None: @@ -2926,6 +2992,7 @@ def visit_assignment_stmt(self, s: AssignmentStmt) -> None: Handle all kinds of assignment statements (simple, indexed, multiple). """ + # Avoid type checking type aliases in stubs to avoid false # positives about modern type syntax available in stubs such # as X | Y. @@ -3134,6 +3201,14 @@ def check_assignment( # Don't use type binder for definitions of special forms, like named tuples. if not (isinstance(lvalue, NameExpr) and lvalue.is_special_form): self.binder.assign_type(lvalue, rvalue_type, lvalue_type, False) + if ( + isinstance(lvalue, NameExpr) + and isinstance(lvalue.node, Var) + and lvalue.node.is_inferred + and lvalue.node.is_index_var + and lvalue_type is not None + ): + lvalue.node.type = remove_instance_last_known_values(lvalue_type) elif index_lvalue: self.check_indexed_assignment(index_lvalue, rvalue, lvalue) @@ -3143,6 +3218,7 @@ def check_assignment( rvalue_type = self.expr_checker.accept(rvalue, type_context=type_context) if not ( inferred.is_final + or inferred.is_index_var or (isinstance(lvalue, NameExpr) and lvalue.name == "__match_args__") ): rvalue_type = remove_instance_last_known_values(rvalue_type) @@ -4350,7 +4426,7 @@ def check_member_assignment( msg=self.msg, chk=self, ) - get_type = analyze_descriptor_access(attribute_type, mx) + get_type = analyze_descriptor_access(attribute_type, mx, assignment=True) if not attribute_type.type.has_readable_member("__set__"): # If there is no __set__, we type-check that the assigned value matches # the return type of __get__. This doesn't match the python semantics, @@ -4417,6 +4493,12 @@ def check_member_assignment( callable_name=callable_name, ) + # Search for possible deprecations: + mx.chk.check_deprecated(dunder_set, mx.context) + mx.chk.warn_deprecated_overload_item( + dunder_set, mx.context, target=inferred_dunder_set_type, selftype=attribute_type + ) + # In the following cases, a message already will have been recorded in check_call. if (not isinstance(inferred_dunder_set_type, CallableType)) or ( len(inferred_dunder_set_type.arg_types) < 2 @@ -4568,6 +4650,13 @@ def check_return_stmt(self, s: ReturnStmt) -> None: s.expr, return_type, allow_none_return=allow_none_func_call ) ) + # Treat NotImplemented as having type Any, consistent with its + # definition in typeshed prior to python/typeshed#4222. + if ( + isinstance(typ, Instance) + and typ.type.fullname == "builtins._NotImplementedType" + ): + typ = AnyType(TypeOfAny.special_form) if defn.is_async_generator: self.fail(message_registry.RETURN_IN_ASYNC_GENERATOR, s) @@ -4642,11 +4731,11 @@ def visit_if_stmt(self, s: IfStmt) -> None: # XXX Issue a warning if condition is always False? with self.binder.frame_context(can_skip=True, fall_through=2): - self.push_type_map(if_map) + self.push_type_map(if_map, from_assignment=False) self.accept(b) # XXX Issue a warning if condition is always True? - self.push_type_map(else_map) + self.push_type_map(else_map, from_assignment=False) with self.binder.frame_context(can_skip=False, fall_through=2): if s.else_body: @@ -4671,6 +4760,16 @@ def visit_operator_assignment_stmt(self, s: OperatorAssignmentStmt) -> None: if inplace: # There is __ifoo__, treat as x = x.__ifoo__(y) rvalue_type, method_type = self.expr_checker.check_op(method, lvalue_type, s.rvalue, s) + if isinstance(inst := get_proper_type(lvalue_type), Instance) and isinstance( + defn := inst.type.get_method(method), OverloadedFuncDef + ): + for item in defn.items: + if ( + isinstance(item, Decorator) + and isinstance(typ := item.func.type, CallableType) + and (bind_self(typ) == method_type) + ): + self.warn_deprecated(item.func, s) if not is_subtype(rvalue_type, lvalue_type): self.msg.incompatible_operator_assignment(s.op, s) else: @@ -4723,6 +4822,14 @@ def type_check_raise(self, e: Expression, s: RaiseStmt, optional: bool = False) # https://github.com/python/mypy/issues/11089 self.expr_checker.check_call(typ, [], [], e) + if isinstance(typ, Instance) and typ.type.fullname == "builtins._NotImplementedType": + self.fail( + message_registry.INVALID_EXCEPTION.with_additional_msg( + '; did you mean "NotImplementedError"?' + ), + s, + ) + def visit_try_stmt(self, s: TryStmt) -> None: """Type check a try statement.""" # Our enclosing frame will get the result if the try/except falls through. @@ -5058,6 +5165,10 @@ def visit_decorator_inner(self, e: Decorator, allow_empty: bool = False) -> None if e.type and not isinstance(get_proper_type(e.type), (FunctionLike, AnyType)): self.fail(message_registry.BAD_CONSTRUCTOR_TYPE, e) + if e.func.original_def and isinstance(sig, FunctionLike): + # Function definition overrides function definition. + self.check_func_def_override(e.func, sig) + def check_for_untyped_decorator( self, func: FuncDef, dec_type: Type, dec_expr: Expression ) -> None: @@ -5205,18 +5316,21 @@ def visit_match_stmt(self, s: MatchStmt) -> None: if b.is_unreachable or isinstance( get_proper_type(pattern_type.type), UninhabitedType ): - self.push_type_map(None) + self.push_type_map(None, from_assignment=False) else_map: TypeMap = {} else: pattern_map, else_map = conditional_types_to_typemaps( named_subject, pattern_type.type, pattern_type.rest_type ) self.remove_capture_conflicts(pattern_type.captures, inferred_types) - self.push_type_map(pattern_map) + self.push_type_map(pattern_map, from_assignment=False) if pattern_map: for expr, typ in pattern_map.items(): - self.push_type_map(self._get_recursive_sub_patterns_map(expr, typ)) - self.push_type_map(pattern_type.captures) + self.push_type_map( + self._get_recursive_sub_patterns_map(expr, typ), + from_assignment=False, + ) + self.push_type_map(pattern_type.captures, from_assignment=False) if g is not None: with self.binder.frame_context(can_skip=False, fall_through=3): gt = get_proper_type(self.expr_checker.accept(g)) @@ -5242,11 +5356,11 @@ def visit_match_stmt(self, s: MatchStmt) -> None: continue type_map[named_subject] = type_map[expr] - self.push_type_map(guard_map) + self.push_type_map(guard_map, from_assignment=False) self.accept(b) else: self.accept(b) - self.push_type_map(else_map) + self.push_type_map(else_map, from_assignment=False) # This is needed due to a quirk in frame_context. Without it types will stay narrowed # after the match. @@ -5315,6 +5429,9 @@ def remove_capture_conflicts(self, type_map: TypeMap, inferred_types: dict[Var, del type_map[expr] def visit_type_alias_stmt(self, o: TypeAliasStmt) -> None: + if o.alias_node: + self.check_typevar_defaults(o.alias_node.alias_tvars) + with self.msg.filter_errors(): self.expr_checker.accept(o.value) @@ -5525,7 +5642,7 @@ def partition_by_callable( if isinstance(typ, TypeVarType): # We could do better probably? - # Refine the the type variable's bound as our type in the case that + # Refine the type variable's bound as our type in the case that # callable() is true. This unfortunately loses the information that # the type is a type variable in that branch. # This matches what is done for isinstance, but it may be possible to @@ -5901,179 +6018,10 @@ def find_isinstance_check_helper( ), ) elif isinstance(node, ComparisonExpr): - # Step 1: Obtain the types of each operand and whether or not we can - # narrow their types. (For example, we shouldn't try narrowing the - # types of literal string or enum expressions). - - operands = [collapse_walrus(x) for x in node.operands] - operand_types = [] - narrowable_operand_index_to_hash = {} - for i, expr in enumerate(operands): - if not self.has_type(expr): - return {}, {} - expr_type = self.lookup_type(expr) - operand_types.append(expr_type) - - if ( - literal(expr) == LITERAL_TYPE - and not is_literal_none(expr) - and not self.is_literal_enum(expr) - ): - h = literal_hash(expr) - if h is not None: - narrowable_operand_index_to_hash[i] = h - - # Step 2: Group operands chained by either the 'is' or '==' operands - # together. For all other operands, we keep them in groups of size 2. - # So the expression: - # - # x0 == x1 == x2 < x3 < x4 is x5 is x6 is not x7 is not x8 - # - # ...is converted into the simplified operator list: - # - # [("==", [0, 1, 2]), ("<", [2, 3]), ("<", [3, 4]), - # ("is", [4, 5, 6]), ("is not", [6, 7]), ("is not", [7, 8])] - # - # We group identity/equality expressions so we can propagate information - # we discover about one operand across the entire chain. We don't bother - # handling 'is not' and '!=' chains in a special way: those are very rare - # in practice. - - simplified_operator_list = group_comparison_operands( - node.pairwise(), narrowable_operand_index_to_hash, {"==", "is"} - ) - - # Step 3: Analyze each group and infer more precise type maps for each - # assignable operand, if possible. We combine these type maps together - # in the final step. - - partial_type_maps = [] - for operator, expr_indices in simplified_operator_list: - if operator in {"is", "is not", "==", "!="}: - # is_valid_target: - # Controls which types we're allowed to narrow exprs to. Note that - # we cannot use 'is_literal_type_like' in both cases since doing - # 'x = 10000 + 1; x is 10001' is not always True in all Python - # implementations. - # - # coerce_only_in_literal_context: - # If true, coerce types into literal types only if one or more of - # the provided exprs contains an explicit Literal type. This could - # technically be set to any arbitrary value, but it seems being liberal - # with narrowing when using 'is' and conservative when using '==' seems - # to break the least amount of real-world code. - # - # should_narrow_by_identity: - # Set to 'false' only if the user defines custom __eq__ or __ne__ methods - # that could cause identity-based narrowing to produce invalid results. - if operator in {"is", "is not"}: - is_valid_target: Callable[[Type], bool] = is_singleton_type - coerce_only_in_literal_context = False - should_narrow_by_identity = True - else: - - def is_exactly_literal_type(t: Type) -> bool: - return isinstance(get_proper_type(t), LiteralType) - - def has_no_custom_eq_checks(t: Type) -> bool: - return not custom_special_method( - t, "__eq__", check_all=False - ) and not custom_special_method(t, "__ne__", check_all=False) - - is_valid_target = is_exactly_literal_type - coerce_only_in_literal_context = True - - expr_types = [operand_types[i] for i in expr_indices] - should_narrow_by_identity = all( - map(has_no_custom_eq_checks, expr_types) - ) and not is_ambiguous_mix_of_enums(expr_types) - - if_map: TypeMap = {} - else_map: TypeMap = {} - if should_narrow_by_identity: - if_map, else_map = self.refine_identity_comparison_expression( - operands, - operand_types, - expr_indices, - narrowable_operand_index_to_hash.keys(), - is_valid_target, - coerce_only_in_literal_context, - ) - - # Strictly speaking, we should also skip this check if the objects in the expr - # chain have custom __eq__ or __ne__ methods. But we (maybe optimistically) - # assume nobody would actually create a custom objects that considers itself - # equal to None. - if if_map == {} and else_map == {}: - if_map, else_map = self.refine_away_none_in_comparison( - operands, - operand_types, - expr_indices, - narrowable_operand_index_to_hash.keys(), - ) - - # If we haven't been able to narrow types yet, we might be dealing with a - # explicit type(x) == some_type check - if if_map == {} and else_map == {}: - if_map, else_map = self.find_type_equals_check(node, expr_indices) - elif operator in {"in", "not in"}: - assert len(expr_indices) == 2 - left_index, right_index = expr_indices - item_type = operand_types[left_index] - iterable_type = operand_types[right_index] - - if_map, else_map = {}, {} - - if left_index in narrowable_operand_index_to_hash: - # We only try and narrow away 'None' for now - if is_overlapping_none(item_type): - collection_item_type = get_proper_type( - builtin_item_type(iterable_type) - ) - if ( - collection_item_type is not None - and not is_overlapping_none(collection_item_type) - and not ( - isinstance(collection_item_type, Instance) - and collection_item_type.type.fullname == "builtins.object" - ) - and is_overlapping_erased_types(item_type, collection_item_type) - ): - if_map[operands[left_index]] = remove_optional(item_type) - - if right_index in narrowable_operand_index_to_hash: - if_type, else_type = self.conditional_types_for_iterable( - item_type, iterable_type - ) - expr = operands[right_index] - if if_type is None: - if_map = None - else: - if_map[expr] = if_type - if else_type is None: - else_map = None - else: - else_map[expr] = else_type - - else: - if_map = {} - else_map = {} - - if operator in {"is not", "!=", "not in"}: - if_map, else_map = else_map, if_map - - partial_type_maps.append((if_map, else_map)) - - # If we have found non-trivial restrictions from the regular comparisons, - # then return soon. Otherwise try to infer restrictions involving `len(x)`. - # TODO: support regular and len() narrowing in the same chain. - if any(m != ({}, {}) for m in partial_type_maps): - return reduce_conditional_maps(partial_type_maps) - else: - # Use meet for `and` maps to get correct results for chained checks - # like `if 1 < len(x) < 4: ...` - return reduce_conditional_maps(self.find_tuple_len_narrowing(node), use_meet=True) + return self.comparison_type_narrowing_helper(node) elif isinstance(node, AssignmentExpr): + if_map: dict[Expression, Type] | None + else_map: dict[Expression, Type] | None if_map = {} else_map = {} @@ -6160,6 +6108,192 @@ def has_no_custom_eq_checks(t: Type) -> bool: else_map = {node: else_type} if not isinstance(else_type, UninhabitedType) else None return if_map, else_map + def comparison_type_narrowing_helper(self, node: ComparisonExpr) -> tuple[TypeMap, TypeMap]: + """Infer type narrowing from a comparison expression.""" + # Step 1: Obtain the types of each operand and whether or not we can + # narrow their types. (For example, we shouldn't try narrowing the + # types of literal string or enum expressions). + + operands = [collapse_walrus(x) for x in node.operands] + operand_types = [] + narrowable_operand_index_to_hash = {} + for i, expr in enumerate(operands): + if not self.has_type(expr): + return {}, {} + expr_type = self.lookup_type(expr) + operand_types.append(expr_type) + + if ( + literal(expr) == LITERAL_TYPE + and not is_literal_none(expr) + and not self.is_literal_enum(expr) + ): + h = literal_hash(expr) + if h is not None: + narrowable_operand_index_to_hash[i] = h + + # Step 2: Group operands chained by either the 'is' or '==' operands + # together. For all other operands, we keep them in groups of size 2. + # So the expression: + # + # x0 == x1 == x2 < x3 < x4 is x5 is x6 is not x7 is not x8 + # + # ...is converted into the simplified operator list: + # + # [("==", [0, 1, 2]), ("<", [2, 3]), ("<", [3, 4]), + # ("is", [4, 5, 6]), ("is not", [6, 7]), ("is not", [7, 8])] + # + # We group identity/equality expressions so we can propagate information + # we discover about one operand across the entire chain. We don't bother + # handling 'is not' and '!=' chains in a special way: those are very rare + # in practice. + + simplified_operator_list = group_comparison_operands( + node.pairwise(), narrowable_operand_index_to_hash, {"==", "is"} + ) + + # Step 3: Analyze each group and infer more precise type maps for each + # assignable operand, if possible. We combine these type maps together + # in the final step. + + partial_type_maps = [] + for operator, expr_indices in simplified_operator_list: + if operator in {"is", "is not", "==", "!="}: + if_map, else_map = self.equality_type_narrowing_helper( + node, + operator, + operands, + operand_types, + expr_indices, + narrowable_operand_index_to_hash, + ) + elif operator in {"in", "not in"}: + assert len(expr_indices) == 2 + left_index, right_index = expr_indices + item_type = operand_types[left_index] + iterable_type = operand_types[right_index] + + if_map, else_map = {}, {} + + if left_index in narrowable_operand_index_to_hash: + # We only try and narrow away 'None' for now + if is_overlapping_none(item_type): + collection_item_type = get_proper_type(builtin_item_type(iterable_type)) + if ( + collection_item_type is not None + and not is_overlapping_none(collection_item_type) + and not ( + isinstance(collection_item_type, Instance) + and collection_item_type.type.fullname == "builtins.object" + ) + and is_overlapping_erased_types(item_type, collection_item_type) + ): + if_map[operands[left_index]] = remove_optional(item_type) + + if right_index in narrowable_operand_index_to_hash: + if_type, else_type = self.conditional_types_for_iterable( + item_type, iterable_type + ) + expr = operands[right_index] + if if_type is None: + if_map = None + else: + if_map[expr] = if_type + if else_type is None: + else_map = None + else: + else_map[expr] = else_type + + else: + if_map = {} + else_map = {} + + if operator in {"is not", "!=", "not in"}: + if_map, else_map = else_map, if_map + + partial_type_maps.append((if_map, else_map)) + + # If we have found non-trivial restrictions from the regular comparisons, + # then return soon. Otherwise try to infer restrictions involving `len(x)`. + # TODO: support regular and len() narrowing in the same chain. + if any(m != ({}, {}) for m in partial_type_maps): + return reduce_conditional_maps(partial_type_maps) + else: + # Use meet for `and` maps to get correct results for chained checks + # like `if 1 < len(x) < 4: ...` + return reduce_conditional_maps(self.find_tuple_len_narrowing(node), use_meet=True) + + def equality_type_narrowing_helper( + self, + node: ComparisonExpr, + operator: str, + operands: list[Expression], + operand_types: list[Type], + expr_indices: list[int], + narrowable_operand_index_to_hash: dict[int, tuple[Key, ...]], + ) -> tuple[TypeMap, TypeMap]: + """Calculate type maps for '==', '!=', 'is' or 'is not' expression.""" + # is_valid_target: + # Controls which types we're allowed to narrow exprs to. Note that + # we cannot use 'is_literal_type_like' in both cases since doing + # 'x = 10000 + 1; x is 10001' is not always True in all Python + # implementations. + # + # coerce_only_in_literal_context: + # If true, coerce types into literal types only if one or more of + # the provided exprs contains an explicit Literal type. This could + # technically be set to any arbitrary value, but it seems being liberal + # with narrowing when using 'is' and conservative when using '==' seems + # to break the least amount of real-world code. + # + # should_narrow_by_identity: + # Set to 'false' only if the user defines custom __eq__ or __ne__ methods + # that could cause identity-based narrowing to produce invalid results. + if operator in {"is", "is not"}: + is_valid_target: Callable[[Type], bool] = is_singleton_type + coerce_only_in_literal_context = False + should_narrow_by_identity = True + else: + + def is_exactly_literal_type(t: Type) -> bool: + return isinstance(get_proper_type(t), LiteralType) + + def has_no_custom_eq_checks(t: Type) -> bool: + return not custom_special_method( + t, "__eq__", check_all=False + ) and not custom_special_method(t, "__ne__", check_all=False) + + is_valid_target = is_exactly_literal_type + coerce_only_in_literal_context = True + + expr_types = [operand_types[i] for i in expr_indices] + should_narrow_by_identity = all( + map(has_no_custom_eq_checks, expr_types) + ) and not is_ambiguous_mix_of_enums(expr_types) + + if_map: TypeMap = {} + else_map: TypeMap = {} + if should_narrow_by_identity: + if_map, else_map = self.refine_identity_comparison_expression( + operands, + operand_types, + expr_indices, + narrowable_operand_index_to_hash.keys(), + is_valid_target, + coerce_only_in_literal_context, + ) + + if if_map == {} and else_map == {}: + if_map, else_map = self.refine_away_none_in_comparison( + operands, operand_types, expr_indices, narrowable_operand_index_to_hash.keys() + ) + + # If we haven't been able to narrow types yet, we might be dealing with a + # explicit type(x) == some_type check + if if_map == {} and else_map == {}: + if_map, else_map = self.find_type_equals_check(node, expr_indices) + return if_map, else_map + def propagate_up_typemap_info(self, new_types: TypeMap) -> TypeMap: """Attempts refining parent expressions of any MemberExpr or IndexExprs in new_types. @@ -6473,25 +6607,36 @@ def refine_away_none_in_comparison( For more details about what the different arguments mean, see the docstring of 'refine_identity_comparison_expression' up above. """ + non_optional_types = [] for i in chain_indices: typ = operand_types[i] if not is_overlapping_none(typ): non_optional_types.append(typ) - # Make sure we have a mixture of optional and non-optional types. - if len(non_optional_types) == 0 or len(non_optional_types) == len(chain_indices): - return {}, {} + if_map, else_map = {}, {} - if_map = {} - for i in narrowable_operand_indices: - expr_type = operand_types[i] - if not is_overlapping_none(expr_type): - continue - if any(is_overlapping_erased_types(expr_type, t) for t in non_optional_types): - if_map[operands[i]] = remove_optional(expr_type) + if not non_optional_types or (len(non_optional_types) != len(chain_indices)): - return if_map, {} + # Narrow e.g. `Optional[A] == "x"` or `Optional[A] is "x"` to `A` (which may be + # convenient but is strictly not type-safe): + for i in narrowable_operand_indices: + expr_type = operand_types[i] + if not is_overlapping_none(expr_type): + continue + if any(is_overlapping_erased_types(expr_type, t) for t in non_optional_types): + if_map[operands[i]] = remove_optional(expr_type) + + # Narrow e.g. `Optional[A] != None` to `A` (which is stricter than the above step and + # so type-safe but less convenient, because e.g. `Optional[A] == None` still results + # in `Optional[A]`): + if any(isinstance(get_proper_type(ot), NoneType) for ot in operand_types): + for i in narrowable_operand_indices: + expr_type = operand_types[i] + if is_overlapping_none(expr_type): + else_map[operands[i]] = remove_optional(expr_type) + + return if_map, else_map def is_len_of_tuple(self, expr: Expression) -> bool: """Is this expression a `len(x)` call where x is a tuple or union of tuples?""" @@ -7236,12 +7381,12 @@ def iterable_item_type( def function_type(self, func: FuncBase) -> FunctionLike: return function_type(func, self.named_type("builtins.function")) - def push_type_map(self, type_map: TypeMap) -> None: + def push_type_map(self, type_map: TypeMap, *, from_assignment: bool = True) -> None: if type_map is None: self.binder.unreachable() else: for expr, type in type_map.items(): - self.binder.put(expr, type) + self.binder.put(expr, type, from_assignment=from_assignment) def infer_issubclass_maps(self, node: CallExpr, expr: Expression) -> tuple[TypeMap, TypeMap]: """Infer type restrictions for an expression in issubclass call.""" @@ -7520,10 +7665,10 @@ def has_valid_attribute(self, typ: Type, name: str) -> bool: name, typ, TempNode(AnyType(TypeOfAny.special_form)), - False, - False, - False, - self.msg, + is_lvalue=False, + is_super=False, + is_operator=False, + msg=self.msg, original_type=typ, chk=self, # This is not a real attribute lookup so don't mess with deferring nodes. @@ -7535,6 +7680,46 @@ def has_valid_attribute(self, typ: Type, name: str) -> bool: def get_expression_type(self, node: Expression, type_context: Type | None = None) -> Type: return self.expr_checker.accept(node, type_context=type_context) + def check_deprecated(self, node: Node | None, context: Context) -> None: + """Warn if deprecated and not directly imported with a `from` statement.""" + if isinstance(node, Decorator): + node = node.func + if isinstance(node, (FuncDef, OverloadedFuncDef, TypeInfo)) and ( + node.deprecated is not None + ): + for imp in self.tree.imports: + if isinstance(imp, ImportFrom) and any(node.name == n[0] for n in imp.names): + break + else: + self.warn_deprecated(node, context) + + def warn_deprecated(self, node: Node | None, context: Context) -> None: + """Warn if deprecated.""" + if isinstance(node, Decorator): + node = node.func + if ( + isinstance(node, (FuncDef, OverloadedFuncDef, TypeInfo)) + and ((deprecated := node.deprecated) is not None) + and not self.is_typeshed_stub + ): + warn = self.msg.note if self.options.report_deprecated_as_note else self.msg.fail + warn(deprecated, context, code=codes.DEPRECATED) + + def warn_deprecated_overload_item( + self, node: Node | None, context: Context, *, target: Type, selftype: Type | None = None + ) -> None: + """Warn if the overload item corresponding to the given callable is deprecated.""" + target = get_proper_type(target) + if isinstance(node, OverloadedFuncDef) and isinstance(target, CallableType): + for item in node.items: + if isinstance(item, Decorator) and isinstance( + candidate := item.func.type, CallableType + ): + if selftype is not None: + candidate = bind_self(candidate, selftype) + if candidate == target: + self.warn_deprecated(item.func, context) + class CollectArgTypeVarTypes(TypeTraverserVisitor): """Collects the non-nested argument types in a set.""" @@ -7589,9 +7774,7 @@ def conditional_types( ) and is_proper_subtype(current_type, proposed_type, ignore_promotions=True): # Expression is always of one of the types in proposed_type_ranges return default, UninhabitedType() - elif not is_overlapping_types( - current_type, proposed_type, prohibit_none_typevar_overlap=True, ignore_promotions=True - ): + elif not is_overlapping_types(current_type, proposed_type, ignore_promotions=True): # Expression is never of any type in proposed_type_ranges return UninhabitedType(), default else: diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 98e6eb6a7fc3..34004b5e3b48 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -126,6 +126,7 @@ validate_instance, ) from mypy.typeops import ( + bind_self, callable_type, custom_special_method, erase_to_union_or_bound, @@ -180,6 +181,7 @@ get_proper_type, get_proper_types, has_recursive_types, + has_type_vars, is_named_instance, split_with_prefix_and_suffix, ) @@ -354,7 +356,9 @@ def visit_name_expr(self, e: NameExpr) -> Type: """ self.chk.module_refs.update(extract_refexpr_names(e)) result = self.analyze_ref_expr(e) - return self.narrow_type_from_binder(e, result) + narrowed = self.narrow_type_from_binder(e, result) + self.chk.check_deprecated(e.node, e) + return narrowed def analyze_ref_expr(self, e: RefExpr, lvalue: bool = False) -> Type: result: Type | None = None @@ -396,8 +400,8 @@ def analyze_ref_expr(self, e: RefExpr, lvalue: bool = False) -> Type: # TODO: always do this in type_object_type by passing the original context result.ret_type.line = e.line result.ret_type.column = e.column - if isinstance(get_proper_type(self.type_context[-1]), TypeType): - # This is the type in a Type[] expression, so substitute type + if is_type_type_context(self.type_context[-1]): + # This is the type in a type[] expression, so substitute type # variables with Any. result = erasetype.erase_typevars(result) elif isinstance(node, MypyFile): @@ -1479,6 +1483,8 @@ def check_call_expr_with_callee_type( object_type=object_type, ) proper_callee = get_proper_type(callee_type) + if isinstance(e.callee, (NameExpr, MemberExpr)): + self.chk.warn_deprecated_overload_item(e.callee.node, e, target=callee_type) if isinstance(e.callee, RefExpr) and isinstance(proper_callee, CallableType): # Cache it for find_isinstance_check() if proper_callee.type_guard is not None: @@ -1497,10 +1503,10 @@ def check_union_call_expr(self, e: CallExpr, object_type: UnionType, member: str member, typ, e, - False, - False, - False, - self.msg, + is_lvalue=False, + is_super=False, + is_operator=False, + msg=self.msg, original_type=object_type, chk=self.chk, in_literal_context=self.is_literal_context(), @@ -2370,7 +2376,11 @@ def check_argument_count( # Positional argument when expecting a keyword argument. self.msg.too_many_positional_arguments(callee, context) ok = False - elif callee.param_spec() is not None and not formal_to_actual[i]: + elif ( + callee.param_spec() is not None + and not formal_to_actual[i] + and callee.special_sig != "partial" + ): self.msg.too_few_arguments(callee, context, actual_names) ok = False return ok @@ -2470,6 +2480,17 @@ def check_argument_types( check_arg = check_arg or self.check_arg # Keep track of consumed tuple *arg items. mapper = ArgTypeExpander(self.argument_infer_context()) + + for arg_type, arg_kind in zip(arg_types, arg_kinds): + arg_type = get_proper_type(arg_type) + if arg_kind == nodes.ARG_STAR and not self.is_valid_var_arg(arg_type): + self.msg.invalid_var_arg(arg_type, context) + if arg_kind == nodes.ARG_STAR2 and not self.is_valid_keyword_var_arg(arg_type): + is_mapping = is_subtype( + arg_type, self.chk.named_type("_typeshed.SupportsKeysAndGetItem") + ) + self.msg.invalid_keyword_var_arg(arg_type, is_mapping, context) + for i, actuals in enumerate(formal_to_actual): orig_callee_arg_type = get_proper_type(callee.arg_types[i]) @@ -2562,15 +2583,6 @@ def check_argument_types( if actual_type is None: continue # Some kind of error was already reported. # Check that a *arg is valid as varargs. - if actual_kind == nodes.ARG_STAR and not self.is_valid_var_arg(actual_type): - self.msg.invalid_var_arg(actual_type, context) - if actual_kind == nodes.ARG_STAR2 and not self.is_valid_keyword_var_arg( - actual_type - ): - is_mapping = is_subtype( - actual_type, self.chk.named_type("_typeshed.SupportsKeysAndGetItem") - ) - self.msg.invalid_keyword_var_arg(actual_type, is_mapping, context) expanded_actual = mapper.expand_actual_type( actual_type, actual_kind, @@ -2774,7 +2786,7 @@ def plausible_overload_call_targets( ) -> list[CallableType]: """Returns all overload call targets that having matching argument counts. - If the given args contains a star-arg (*arg or **kwarg argument, including + If the given args contains a star-arg (*arg or **kwarg argument, except for ParamSpec), this method will ensure all star-arg overloads appear at the start of the list, instead of their usual location. @@ -2809,7 +2821,9 @@ def has_shape(typ: Type) -> bool: # ParamSpec can be expanded in a lot of different ways. We may try # to expand it here instead, but picking an impossible overload # is safe: it will be filtered out later. - star_matches.append(typ) + # Unlike other var-args signatures, ParamSpec produces essentially + # a fixed signature, so there's no need to push them to the top. + matches.append(typ) elif self.check_argument_count( typ, arg_types, arg_kinds, arg_names, formal_to_actual, None ): @@ -3267,7 +3281,9 @@ def visit_member_expr(self, e: MemberExpr, is_lvalue: bool = False) -> Type: """Visit member expression (of form e.id).""" self.chk.module_refs.update(extract_refexpr_names(e)) result = self.analyze_ordinary_member_access(e, is_lvalue) - return self.narrow_type_from_binder(e, result) + narrowed = self.narrow_type_from_binder(e, result) + self.chk.warn_deprecated(e.node, e) + return narrowed def analyze_ordinary_member_access(self, e: MemberExpr, is_lvalue: bool) -> Type: """Analyse member expression or member lvalue.""" @@ -3293,10 +3309,10 @@ def analyze_ordinary_member_access(self, e: MemberExpr, is_lvalue: bool) -> Type e.name, original_type, e, - is_lvalue, - False, - False, - self.msg, + is_lvalue=is_lvalue, + is_super=False, + is_operator=False, + msg=self.msg, original_type=original_type, chk=self.chk, in_literal_context=self.is_literal_context(), @@ -3317,10 +3333,10 @@ def analyze_external_member_access( member, base_type, context, - False, - False, - False, - self.msg, + is_lvalue=False, + is_super=False, + is_operator=False, + msg=self.msg, original_type=base_type, chk=self.chk, in_literal_context=self.is_literal_context(), @@ -3800,11 +3816,12 @@ def check_method_call_by_name( method, base_type, context, - False, - False, - True, - self.msg, + is_lvalue=False, + is_super=False, + is_operator=True, + msg=self.msg, original_type=original_type, + self_type=base_type, chk=self.chk, in_literal_context=self.is_literal_context(), ) @@ -3956,7 +3973,7 @@ def lookup_definer(typ: Instance, attr_name: str) -> str | None: # This is the case even if the __add__ method is completely missing and the __radd__ # method is defined. - variants_raw = [(left_op, left_type, right_expr)] + variants_raw = [(op_name, left_op, left_type, right_expr)] elif ( is_subtype(right_type, left_type) and isinstance(left_type, Instance) @@ -3977,19 +3994,25 @@ def lookup_definer(typ: Instance, attr_name: str) -> str | None: # As a special case, the alt_promote check makes sure that we don't use the # __radd__ method of int if the LHS is a native int type. - variants_raw = [(right_op, right_type, left_expr), (left_op, left_type, right_expr)] + variants_raw = [ + (rev_op_name, right_op, right_type, left_expr), + (op_name, left_op, left_type, right_expr), + ] else: # In all other cases, we do the usual thing and call __add__ first and # __radd__ second when doing "A() + B()". - variants_raw = [(left_op, left_type, right_expr), (right_op, right_type, left_expr)] + variants_raw = [ + (op_name, left_op, left_type, right_expr), + (rev_op_name, right_op, right_type, left_expr), + ] # STEP 3: # We now filter out all non-existent operators. The 'variants' list contains # all operator methods that are actually present, in the order that Python # attempts to invoke them. - variants = [(op, obj, arg) for (op, obj, arg) in variants_raw if op is not None] + variants = [(na, op, obj, arg) for (na, op, obj, arg) in variants_raw if op is not None] # STEP 4: # We now try invoking each one. If an operation succeeds, end early and return @@ -3998,13 +4021,23 @@ def lookup_definer(typ: Instance, attr_name: str) -> str | None: errors = [] results = [] - for method, obj, arg in variants: + for name, method, obj, arg in variants: with self.msg.filter_errors(save_filtered_errors=True) as local_errors: result = self.check_method_call(op_name, obj, method, [arg], [ARG_POS], context) if local_errors.has_new_errors(): errors.append(local_errors.filtered_errors()) results.append(result) else: + if isinstance(obj, Instance) and isinstance( + defn := obj.type.get_method(name), OverloadedFuncDef + ): + for item in defn.items: + if ( + isinstance(item, Decorator) + and isinstance(typ := item.func.type, CallableType) + and bind_self(typ) == result[1] + ): + self.chk.check_deprecated(item.func, context) return result # We finish invoking above operators and no early return happens. Therefore, @@ -5580,11 +5613,15 @@ def visit_slice_expr(self, e: SliceExpr) -> Type: except KeyError: supports_index = self.chk.named_type("builtins.int") # thanks, fixture life expected = make_optional_type(supports_index) + type_args = [] for index in [e.begin_index, e.end_index, e.stride]: if index: t = self.accept(index) self.chk.check_subtype(t, expected, index, message_registry.INVALID_SLICE_INDEX) - return self.named_type("builtins.slice") + type_args.append(t) + else: + type_args.append(NoneType()) + return self.chk.named_generic_type("builtins.slice", type_args) def visit_list_comprehension(self, e: ListComprehension) -> Type: return self.check_generator_or_comprehension( @@ -5779,6 +5816,12 @@ def visit_conditional_expr(self, e: ConditionalExpr, allow_none_return: bool = F context=if_type_fallback, allow_none_return=allow_none_return, ) + + # In most cases using if_type as a context for right branch gives better inferred types. + # This is however not the case for literal types, so use the full context instead. + if is_literal_type_like(full_context_else_type) and not is_literal_type_like(else_type): + else_type = full_context_else_type + res: Type = make_simplified_union([if_type, else_type]) if has_uninhabited_component(res) and not isinstance( get_proper_type(self.type_context[-1]), UnionType @@ -6306,23 +6349,7 @@ def __init__(self) -> None: def visit_callable_type(self, t: CallableType) -> bool: # TODO: we need to check only for type variables of original callable. - return self.query_types(t.arg_types) or t.accept(HasTypeVarQuery()) - - -class HasTypeVarQuery(types.BoolTypeQuery): - """Visitor for querying whether a type has a type variable component.""" - - def __init__(self) -> None: - super().__init__(types.ANY_STRATEGY) - - def visit_type_var(self, t: TypeVarType) -> bool: - return True - - def visit_param_spec(self, t: ParamSpecType) -> bool: - return True - - def visit_type_var_tuple(self, t: TypeVarTupleType) -> bool: - return True + return self.query_types(t.arg_types) or has_type_vars(t) def has_erased_component(t: Type | None) -> bool: @@ -6591,3 +6618,12 @@ def get_partial_instance_type(t: Type | None) -> PartialType | None: if t is None or not isinstance(t, PartialType) or t.type is None: return None return t + + +def is_type_type_context(context: Type | None) -> bool: + context = get_proper_type(context) + if isinstance(context, TypeType): + return True + if isinstance(context, UnionType): + return any(is_type_type_context(item) for item in context.items) + return False diff --git a/mypy/checkmember.py b/mypy/checkmember.py index 8f99f96e2dd5..50e54ca30460 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -17,6 +17,7 @@ ARG_POS, ARG_STAR, ARG_STAR2, + EXCLUDED_ENUM_ATTRIBUTES, SYMBOL_FUNCBASE_TYPES, Context, Decorator, @@ -48,7 +49,6 @@ type_object_type_from_function, ) from mypy.types import ( - ENUM_REMOVED_PROPS, AnyType, CallableType, DeletedType, @@ -87,6 +87,7 @@ class MemberContext: def __init__( self, + *, is_lvalue: bool, is_super: bool, is_operator: bool, @@ -126,16 +127,16 @@ def copy_modified( original_type: Type | None = None, ) -> MemberContext: mx = MemberContext( - self.is_lvalue, - self.is_super, - self.is_operator, - self.original_type, - self.context, - self.msg, - self.chk, - self.self_type, - self.module_symbol_table, - self.no_deferral, + is_lvalue=self.is_lvalue, + is_super=self.is_super, + is_operator=self.is_operator, + original_type=self.original_type, + context=self.context, + msg=self.msg, + chk=self.chk, + self_type=self.self_type, + module_symbol_table=self.module_symbol_table, + no_deferral=self.no_deferral, ) if messages is not None: mx.msg = messages @@ -152,11 +153,11 @@ def analyze_member_access( name: str, typ: Type, context: Context, + *, is_lvalue: bool, is_super: bool, is_operator: bool, msg: MessageBuilder, - *, original_type: Type, chk: mypy.checker.TypeChecker, override_info: TypeInfo | None = None, @@ -190,12 +191,12 @@ def analyze_member_access( are not available via the type object directly) """ mx = MemberContext( - is_lvalue, - is_super, - is_operator, - original_type, - context, - msg, + is_lvalue=is_lvalue, + is_super=is_super, + is_operator=is_operator, + original_type=original_type, + context=context, + msg=msg, chk=chk, self_type=self_type, module_symbol_table=module_symbol_table, @@ -316,9 +317,12 @@ def analyze_instance_member_access( if method.is_property: assert isinstance(method, OverloadedFuncDef) - first_item = method.items[0] - assert isinstance(first_item, Decorator) - return analyze_var(name, first_item.var, typ, info, mx) + getter = method.items[0] + assert isinstance(getter, Decorator) + if mx.is_lvalue and (len(items := method.items) > 1): + mx.chk.warn_deprecated(items[1], mx.context) + return analyze_var(name, getter.var, typ, info, mx) + if mx.is_lvalue: mx.msg.cant_assign_to_method(mx.context) if not isinstance(method, OverloadedFuncDef): @@ -493,6 +497,8 @@ def analyze_member_var_access( # It was not a method. Try looking up a variable. v = lookup_member_var_or_accessor(info, name, mx.is_lvalue) + mx.chk.warn_deprecated(v, mx.context) + vv = v if isinstance(vv, Decorator): # The associated Var node of a decorator contains the type. @@ -572,7 +578,11 @@ def analyze_member_var_access( if hook: result = hook( AttributeContext( - get_proper_type(mx.original_type), result, mx.context, mx.chk + get_proper_type(mx.original_type), + result, + mx.is_lvalue, + mx.context, + mx.chk, ) ) return result @@ -628,7 +638,9 @@ def check_final_member(name: str, info: TypeInfo, msg: MessageBuilder, ctx: Cont msg.cant_assign_to_final(name, attr_assign=True, ctx=ctx) -def analyze_descriptor_access(descriptor_type: Type, mx: MemberContext) -> Type: +def analyze_descriptor_access( + descriptor_type: Type, mx: MemberContext, *, assignment: bool = False +) -> Type: """Type check descriptor access. Arguments: @@ -709,6 +721,12 @@ def analyze_descriptor_access(descriptor_type: Type, mx: MemberContext) -> Type: callable_name=callable_name, ) + if not assignment: + mx.chk.check_deprecated(dunder_get, mx.context) + mx.chk.warn_deprecated_overload_item( + dunder_get, mx.context, target=inferred_dunder_get_type, selftype=descriptor_type + ) + inferred_dunder_get_type = get_proper_type(inferred_dunder_get_type) if isinstance(inferred_dunder_get_type, AnyType): # check_call failed, and will have reported an error @@ -829,7 +847,9 @@ def analyze_var( result = analyze_descriptor_access(result, mx) if hook: result = hook( - AttributeContext(get_proper_type(mx.original_type), result, mx.context, mx.chk) + AttributeContext( + get_proper_type(mx.original_type), result, mx.is_lvalue, mx.context, mx.chk + ) ) return result @@ -1004,6 +1024,8 @@ def analyze_class_attribute_access( # on the class object itself rather than the instance. return None + mx.chk.warn_deprecated(node.node, mx.context) + is_decorated = isinstance(node.node, Decorator) is_method = is_decorated or isinstance(node.node, FuncBase) if mx.is_lvalue: @@ -1148,7 +1170,9 @@ def apply_class_attr_hook( ) -> Type | None: if hook: result = hook( - AttributeContext(get_proper_type(mx.original_type), result, mx.context, mx.chk) + AttributeContext( + get_proper_type(mx.original_type), result, mx.is_lvalue, mx.context, mx.chk + ) ) return result @@ -1157,7 +1181,7 @@ def analyze_enum_class_attribute_access( itype: Instance, name: str, mx: MemberContext ) -> Type | None: # Skip these since Enum will remove it - if name in ENUM_REMOVED_PROPS: + if name in EXCLUDED_ENUM_ATTRIBUTES: return report_missing_attribute(mx.original_type, itype, name, mx) # Dunders and private names are not Enum members if name.startswith("__") and name.replace("_", "") != "": diff --git a/mypy/checkpattern.py b/mypy/checkpattern.py index fa23dfb5f453..43f42039b199 100644 --- a/mypy/checkpattern.py +++ b/mypy/checkpattern.py @@ -46,6 +46,7 @@ TypedDictType, TypeOfAny, TypeVarTupleType, + TypeVarType, UninhabitedType, UnionType, UnpackType, @@ -158,7 +159,8 @@ def visit_or_pattern(self, o: OrPattern) -> PatternType: for pattern in o.patterns: pattern_type = self.accept(pattern, current_type) pattern_types.append(pattern_type) - current_type = pattern_type.rest_type + if not is_uninhabited(pattern_type.type): + current_type = pattern_type.rest_type # # Collect the final type @@ -342,13 +344,11 @@ def visit_sequence_pattern(self, o: SequencePattern) -> PatternType: new_inner_type = UninhabitedType() for typ in new_inner_types: new_inner_type = join_types(new_inner_type, typ) - new_type = self.construct_sequence_child(current_type, new_inner_type) - if is_subtype(new_type, current_type): - new_type, _ = self.chk.conditional_types_with_intersection( - current_type, [get_type_range(new_type)], o, default=current_type - ) + if isinstance(current_type, TypeVarType): + new_bound = self.narrow_sequence_child(current_type.upper_bound, new_inner_type, o) + new_type = current_type.copy_modified(upper_bound=new_bound) else: - new_type = current_type + new_type = self.narrow_sequence_child(current_type, new_inner_type, o) return PatternType(new_type, rest_type, captures) def get_sequence_type(self, t: Type, context: Context) -> Type | None: @@ -447,6 +447,16 @@ def expand_starred_pattern_types( return new_types + def narrow_sequence_child(self, outer_type: Type, inner_type: Type, ctx: Context) -> Type: + new_type = self.construct_sequence_child(outer_type, inner_type) + if is_subtype(new_type, outer_type): + new_type, _ = self.chk.conditional_types_with_intersection( + outer_type, [get_type_range(new_type)], ctx, default=outer_type + ) + else: + new_type = outer_type + return new_type + def visit_starred_pattern(self, o: StarredPattern) -> PatternType: captures: dict[Expression, Type] = {} if o.capture is not None: @@ -594,10 +604,10 @@ def visit_class_pattern(self, o: ClassPattern) -> PatternType: "__match_args__", typ, o, - False, - False, - False, - self.msg, + is_lvalue=False, + is_super=False, + is_operator=False, + msg=self.msg, original_type=typ, chk=self.chk, ) @@ -660,10 +670,10 @@ def visit_class_pattern(self, o: ClassPattern) -> PatternType: keyword, narrowed_type, pattern, - False, - False, - False, - self.msg, + is_lvalue=False, + is_super=False, + is_operator=False, + msg=self.msg, original_type=new_type, chk=self.chk, ) @@ -693,7 +703,9 @@ def visit_class_pattern(self, o: ClassPattern) -> PatternType: def should_self_match(self, typ: Type) -> bool: typ = get_proper_type(typ) - if isinstance(typ, Instance) and typ.type.is_named_tuple: + if isinstance(typ, Instance) and typ.type.get("__match_args__") is not None: + # Named tuples and other subtypes of builtins that define __match_args__ + # should not self match. return False for other in self.self_match_types: if is_subtype(typ, other): diff --git a/mypy/checkstrformat.py b/mypy/checkstrformat.py index c63210a96c44..dd42fe7755a0 100644 --- a/mypy/checkstrformat.py +++ b/mypy/checkstrformat.py @@ -393,8 +393,10 @@ def check_specs_in_format_call( # If the explicit conversion is given, then explicit conversion is called _first_. if spec.conversion[1] not in "rsa": self.msg.fail( - 'Invalid conversion type "{}",' - ' must be one of "r", "s" or "a"'.format(spec.conversion[1]), + ( + f'Invalid conversion type "{spec.conversion[1]}", ' + f'must be one of "r", "s" or "a"' + ), call, code=codes.STRING_FORMATTING, ) @@ -472,8 +474,7 @@ def find_replacements_in_call(self, call: CallExpr, keys: list[str]) -> list[Exp expr = self.get_expr_by_position(int(key), call) if not expr: self.msg.fail( - "Cannot find replacement for positional" - " format specifier {}".format(key), + f"Cannot find replacement for positional format specifier {key}", call, code=codes.STRING_FORMATTING, ) @@ -654,8 +655,9 @@ class User(TypedDict): assert spec.key, "Call this method only after auto-generating keys!" assert spec.field self.msg.fail( - "Invalid index expression in format field" - ' accessor "{}"'.format(spec.field[len(spec.key) :]), + 'Invalid index expression in format field accessor "{}"'.format( + spec.field[len(spec.key) :] + ), ctx, code=codes.STRING_FORMATTING, ) diff --git a/mypy/config_parser.py b/mypy/config_parser.py index a6bf021000c1..9fa99333a42a 100644 --- a/mypy/config_parser.py +++ b/mypy/config_parser.py @@ -472,12 +472,7 @@ def parse_section( ) continue else: - dv = None - # We have to keep new_semantic_analyzer in Options - # for plugin compatibility but it is not a valid option anymore. - assert hasattr(template, "new_semantic_analyzer") - if key != "new_semantic_analyzer": - dv = getattr(template, key, None) + dv = getattr(template, key, None) if dv is None: if key.endswith("_report"): report_type = key[:-7].replace("_", "-") diff --git a/mypy/constraints.py b/mypy/constraints.py index 49a2aea8fa05..5c815bf2af65 100644 --- a/mypy/constraints.py +++ b/mypy/constraints.py @@ -1029,18 +1029,10 @@ def visit_callable_type(self, template: CallableType) -> list[Constraint]: if template.type_guard is not None and cactual.type_guard is not None: template_ret_type = template.type_guard cactual_ret_type = cactual.type_guard - elif template.type_guard is not None: - template_ret_type = AnyType(TypeOfAny.special_form) - elif cactual.type_guard is not None: - cactual_ret_type = AnyType(TypeOfAny.special_form) if template.type_is is not None and cactual.type_is is not None: template_ret_type = template.type_is cactual_ret_type = cactual.type_is - elif template.type_is is not None: - template_ret_type = AnyType(TypeOfAny.special_form) - elif cactual.type_is is not None: - cactual_ret_type = AnyType(TypeOfAny.special_form) res.extend(infer_constraints(template_ret_type, cactual_ret_type, self.direction)) diff --git a/mypy/dmypy_server.py b/mypy/dmypy_server.py index f8a0f91f87d9..70cfaa5b2fb9 100644 --- a/mypy/dmypy_server.py +++ b/mypy/dmypy_server.py @@ -625,6 +625,8 @@ def fine_grained_increment_follow_imports( changed, new_files = self.find_reachable_changed_modules( sources, graph, seen, changed_paths ) + # Same as in fine_grained_increment(). + self.add_explicitly_new(sources, changed) if explicit_export_types: # Same as in fine_grained_increment(). add_all_sources_to_changed(sources, changed) @@ -888,6 +890,22 @@ def _find_changed( assert path removed.append((source.module, path)) + self.add_explicitly_new(sources, changed) + + # Find anything that has had its module path change because of added or removed __init__s + last = {s.path: s.module for s in self.previous_sources} + for s in sources: + assert s.path + if s.path in last and last[s.path] != s.module: + # Mark it as removed from its old name and changed at its new name + removed.append((last[s.path], s.path)) + changed.append((s.module, s.path)) + + return changed, removed + + def add_explicitly_new( + self, sources: list[BuildSource], changed: list[tuple[str, str]] + ) -> None: # Always add modules that were (re-)added, since they may be detected as not changed by # fswatcher (if they were actually not changed), but they may still need to be checked # in case they had errors before they were deleted from sources on previous runs. @@ -903,17 +921,6 @@ def _find_changed( ] ) - # Find anything that has had its module path change because of added or removed __init__s - last = {s.path: s.module for s in self.previous_sources} - for s in sources: - assert s.path - if s.path in last and last[s.path] != s.module: - # Mark it as removed from its old name and changed at its new name - removed.append((last[s.path], s.path)) - changed.append((s.module, s.path)) - - return changed, removed - def cmd_inspect( self, show: str, diff --git a/mypy/dmypy_util.py b/mypy/dmypy_util.py index 0baff863b3c3..9b21d78ce599 100644 --- a/mypy/dmypy_util.py +++ b/mypy/dmypy_util.py @@ -104,8 +104,7 @@ def truncate(self, size: int | None = 0) -> int: raise io.UnsupportedOperation def write(self, output: str) -> int: - resp: dict[str, Any] = {} - resp[self.output_key] = output + resp: dict[str, Any] = {self.output_key: output} send(self.server, resp) return len(output) diff --git a/mypy/errorcodes.py b/mypy/errorcodes.py index a170b5d4d65a..5736be5c143e 100644 --- a/mypy/errorcodes.py +++ b/mypy/errorcodes.py @@ -304,5 +304,12 @@ def __hash__(self) -> int: "General", ) +DEPRECATED: Final = ErrorCode( + "deprecated", + "Warn when importing or using deprecated (overloaded) functions, methods or classes", + "General", + default_enabled=False, +) + # This copy will not include any error codes defined later in the plugins. mypy_error_codes = error_codes.copy() diff --git a/mypy/errors.py b/mypy/errors.py index d6dcd4e49e13..1b3f485d19c0 100644 --- a/mypy/errors.py +++ b/mypy/errors.py @@ -20,7 +20,7 @@ # Show error codes for some note-level messages (these usually appear alone # and not as a comment for a previous error-level message). -SHOW_NOTE_CODES: Final = {codes.ANNOTATION_UNCHECKED} +SHOW_NOTE_CODES: Final = {codes.ANNOTATION_UNCHECKED, codes.DEPRECATED} # Do not add notes with links to error code docs to errors with these codes. # We can tweak this set as we get more experience about what is helpful and what is not. @@ -194,6 +194,9 @@ def on_error(self, file: str, info: ErrorInfo) -> bool: Return True to filter out the error, preventing it from being seen by other ErrorWatcher further down the stack and from being recorded by Errors """ + if info.code == codes.DEPRECATED: + return False + self._has_new_errors = True if isinstance(self._filter, bool): should_filter = self._filter @@ -919,9 +922,25 @@ def file_messages(self, path: str, formatter: ErrorFormatter | None = None) -> l self.flushed_files.add(path) source_lines = None if self.options.pretty and self.read_source: - source_lines = self.read_source(path) + # Find shadow file mapping and read source lines if a shadow file exists for the given path. + # If shadow file mapping is not found, read source lines + mapped_path = self.find_shadow_file_mapping(path) + if mapped_path: + source_lines = self.read_source(mapped_path) + else: + source_lines = self.read_source(path) return self.format_messages(error_tuples, source_lines) + def find_shadow_file_mapping(self, path: str) -> str | None: + """Return the shadow file path for a given source file path or None.""" + if self.options.shadow_file is None: + return None + + for i in self.options.shadow_file: + if i[0] == path: + return i[1] + return None + def new_messages(self) -> list[str]: """Return a string list of new error messages. diff --git a/mypy/fastparse.py b/mypy/fastparse.py index 726397adb849..a47ed9b536da 100644 --- a/mypy/fastparse.py +++ b/mypy/fastparse.py @@ -1196,19 +1196,17 @@ def validate_type_param(self, type_param: ast_TypeVar) -> None: def translate_type_params(self, type_params: list[Any]) -> list[TypeParam]: explicit_type_params = [] for p in type_params: - bound = None + bound: Type | None = None values: list[Type] = [] - if sys.version_info >= (3, 13) and p.default_value is not None: - self.fail( - message_registry.TYPE_PARAM_DEFAULT_NOT_SUPPORTED, - p.lineno, - p.col_offset, - blocker=False, - ) + default: Type | None = None + if sys.version_info >= (3, 13): + default = TypeConverter(self.errors, line=p.lineno).visit(p.default_value) if isinstance(p, ast_ParamSpec): # type: ignore[misc] - explicit_type_params.append(TypeParam(p.name, PARAM_SPEC_KIND, None, [])) + explicit_type_params.append(TypeParam(p.name, PARAM_SPEC_KIND, None, [], default)) elif isinstance(p, ast_TypeVarTuple): # type: ignore[misc] - explicit_type_params.append(TypeParam(p.name, TYPE_VAR_TUPLE_KIND, None, [])) + explicit_type_params.append( + TypeParam(p.name, TYPE_VAR_TUPLE_KIND, None, [], default) + ) else: if isinstance(p.bound, ast3.Tuple): if len(p.bound.elts) < 2: @@ -1224,7 +1222,9 @@ def translate_type_params(self, type_params: list[Any]) -> list[TypeParam]: elif p.bound is not None: self.validate_type_param(p) bound = TypeConverter(self.errors, line=p.lineno).visit(p.bound) - explicit_type_params.append(TypeParam(p.name, TYPE_VAR_KIND, bound, values)) + explicit_type_params.append( + TypeParam(p.name, TYPE_VAR_KIND, bound, values, default) + ) return explicit_type_params # Return(expr? value) @@ -2033,7 +2033,7 @@ def visit_UnaryOp(self, n: UnaryOp) -> Type: if ( isinstance(typ, RawExpressionType) # Use type() because we do not want to allow bools. - and type(typ.literal_value) is int # noqa: E721 + and type(typ.literal_value) is int ): if isinstance(n.op, USub): typ.literal_value *= -1 diff --git a/mypy/fscache.py b/mypy/fscache.py index 15679ad03e85..8251f4bd9488 100644 --- a/mypy/fscache.py +++ b/mypy/fscache.py @@ -51,8 +51,8 @@ def set_package_root(self, package_root: list[str]) -> None: def flush(self) -> None: """Start another transaction and empty all caches.""" - self.stat_cache: dict[str, os.stat_result] = {} - self.stat_error_cache: dict[str, OSError] = {} + self.stat_or_none_cache: dict[str, os.stat_result | None] = {} + self.listdir_cache: dict[str, list[str]] = {} self.listdir_error_cache: dict[str, OSError] = {} self.isfile_case_cache: dict[str, bool] = {} @@ -62,24 +62,21 @@ def flush(self) -> None: self.hash_cache: dict[str, str] = {} self.fake_package_cache: set[str] = set() - def stat(self, path: str) -> os.stat_result: - if path in self.stat_cache: - return self.stat_cache[path] - if path in self.stat_error_cache: - raise copy_os_error(self.stat_error_cache[path]) + def stat_or_none(self, path: str) -> os.stat_result | None: + if path in self.stat_or_none_cache: + return self.stat_or_none_cache[path] + + st = None try: st = os.stat(path) - except OSError as err: + except OSError: if self.init_under_package_root(path): try: - return self._fake_init(path) + st = self._fake_init(path) except OSError: pass - # Take a copy to get rid of associated traceback and frame objects. - # Just assigning to __traceback__ doesn't free them. - self.stat_error_cache[path] = copy_os_error(err) - raise err - self.stat_cache[path] = st + + self.stat_or_none_cache[path] = st return st def init_under_package_root(self, path: str) -> bool: @@ -112,9 +109,9 @@ def init_under_package_root(self, path: str) -> bool: if not os.path.basename(dirname).isidentifier(): # Can't put an __init__.py in a place that's not an identifier return False - try: - st = self.stat(dirname) - except OSError: + + st = self.stat_or_none(dirname) + if st is None: return False else: if not stat.S_ISDIR(st.st_mode): @@ -145,7 +142,7 @@ def _fake_init(self, path: str) -> os.stat_result: assert basename == "__init__.py", path assert not os.path.exists(path), path # Not cached! dirname = os.path.normpath(dirname) - st = self.stat(dirname) # May raise OSError + st = os.stat(dirname) # May raise OSError # Get stat result as a list so we can modify it. seq: list[float] = list(st) seq[stat.ST_MODE] = stat.S_IFREG | 0o444 @@ -153,7 +150,6 @@ def _fake_init(self, path: str) -> os.stat_result: seq[stat.ST_NLINK] = 1 seq[stat.ST_SIZE] = 0 st = os.stat_result(seq) - self.stat_cache[path] = st # Make listdir() and read() also pretend this file exists. self.fake_package_cache.add(dirname) return st @@ -181,9 +177,8 @@ def listdir(self, path: str) -> list[str]: return results def isfile(self, path: str) -> bool: - try: - st = self.stat(path) - except OSError: + st = self.stat_or_none(path) + if st is None: return False return stat.S_ISREG(st.st_mode) @@ -248,18 +243,14 @@ def exists_case(self, path: str, prefix: str) -> bool: return res def isdir(self, path: str) -> bool: - try: - st = self.stat(path) - except OSError: + st = self.stat_or_none(path) + if st is None: return False return stat.S_ISDIR(st.st_mode) def exists(self, path: str) -> bool: - try: - self.stat(path) - except FileNotFoundError: - return False - return True + st = self.stat_or_none(path) + return st is not None def read(self, path: str) -> bytes: if path in self.read_cache: @@ -269,7 +260,7 @@ def read(self, path: str) -> bytes: # Need to stat first so that the contents of file are from no # earlier instant than the mtime reported by self.stat(). - self.stat(path) + self.stat_or_none(path) dirname, basename = os.path.split(path) dirname = os.path.normpath(dirname) @@ -294,8 +285,10 @@ def hash_digest(self, path: str) -> str: return self.hash_cache[path] def samefile(self, f1: str, f2: str) -> bool: - s1 = self.stat(f1) - s2 = self.stat(f2) + s1 = self.stat_or_none(f1) + s2 = self.stat_or_none(f2) + if s1 is None or s2 is None: + return False return os.path.samestat(s1, s2) diff --git a/mypy/fswatcher.py b/mypy/fswatcher.py index a574a36a0cc5..97a62ca9f9f7 100644 --- a/mypy/fswatcher.py +++ b/mypy/fswatcher.py @@ -2,6 +2,7 @@ from __future__ import annotations +import os from typing import AbstractSet, Iterable, NamedTuple from mypy.fscache import FileSystemCache @@ -56,8 +57,7 @@ def remove_watched_paths(self, paths: Iterable[str]) -> None: del self._file_data[path] self._paths -= set(paths) - def _update(self, path: str) -> None: - st = self.fs.stat(path) + def _update(self, path: str, st: os.stat_result) -> None: hash_digest = self.fs.hash_digest(path) self._file_data[path] = FileData(st.st_mtime, st.st_size, hash_digest) @@ -65,9 +65,8 @@ def _find_changed(self, paths: Iterable[str]) -> AbstractSet[str]: changed = set() for path in paths: old = self._file_data[path] - try: - st = self.fs.stat(path) - except FileNotFoundError: + st = self.fs.stat_or_none(path) + if st is None: if old is not None: # File was deleted. changed.add(path) @@ -76,13 +75,13 @@ def _find_changed(self, paths: Iterable[str]) -> AbstractSet[str]: if old is None: # File is new. changed.add(path) - self._update(path) + self._update(path, st) # Round mtimes down, to match the mtimes we write to meta files elif st.st_size != old.st_size or int(st.st_mtime) != int(old.st_mtime): # Only look for changes if size or mtime has changed as an # optimization, since calculating hash is expensive. new_hash = self.fs.hash_digest(path) - self._update(path) + self._update(path, st) if st.st_size != old.st_size or new_hash != old.hash: # Changed file. changed.add(path) diff --git a/mypy/gclogger.py b/mypy/gclogger.py index 75f754ddf4d5..d111e609223c 100644 --- a/mypy/gclogger.py +++ b/mypy/gclogger.py @@ -38,10 +38,11 @@ def __exit__(self, *args: object) -> None: def get_stats(self) -> Mapping[str, float]: end_time = time.time() - result = {} - result["gc_time"] = self.gc_time - result["gc_calls"] = self.gc_calls - result["gc_collected"] = self.gc_collected - result["gc_uncollectable"] = self.gc_uncollectable - result["build_time"] = end_time - self.start_time + result = { + "gc_time": self.gc_time, + "gc_calls": self.gc_calls, + "gc_collected": self.gc_collected, + "gc_uncollectable": self.gc_uncollectable, + "build_time": end_time - self.start_time, + } return result diff --git a/mypy/inspections.py b/mypy/inspections.py index 3e660a0bd7a6..0baf0896f7e5 100644 --- a/mypy/inspections.py +++ b/mypy/inspections.py @@ -469,8 +469,7 @@ def missing_type(self, expression: Expression) -> str: def missing_node(self, expression: Expression) -> str: return ( - f'Cannot find definition for "{type(expression).__name__}"' - f" at {expr_span(expression)}" + f'Cannot find definition for "{type(expression).__name__}" at {expr_span(expression)}' ) def add_prefixes(self, result: str, expression: Expression) -> str: diff --git a/mypy/ipc.py b/mypy/ipc.py index ab01f1b79e7d..991f9ac56652 100644 --- a/mypy/ipc.py +++ b/mypy/ipc.py @@ -17,9 +17,8 @@ if sys.platform == "win32": # This may be private, but it is needed for IPC on Windows, and is basically stable - import ctypes - import _winapi + import ctypes _IPCHandle = int diff --git a/mypy/join.py b/mypy/join.py index 865dd073d081..2ada7479789b 100644 --- a/mypy/join.py +++ b/mypy/join.py @@ -317,7 +317,7 @@ def visit_none_type(self, t: NoneType) -> ProperType: if state.strict_optional: if isinstance(self.s, (NoneType, UninhabitedType)): return t - elif isinstance(self.s, UnboundType): + elif isinstance(self.s, (UnboundType, AnyType)): return AnyType(TypeOfAny.special_form) else: return mypy.typeops.make_simplified_union([self.s, t]) diff --git a/mypy/main.py b/mypy/main.py index f177bb1c2062..7032682c9fd0 100644 --- a/mypy/main.py +++ b/mypy/main.py @@ -22,7 +22,14 @@ from mypy.errors import CompileError from mypy.find_sources import InvalidSourceList, create_source_list from mypy.fscache import FileSystemCache -from mypy.modulefinder import BuildSource, FindModuleCache, SearchPaths, get_search_dirs, mypy_path +from mypy.modulefinder import ( + BuildSource, + FindModuleCache, + ModuleNotFoundReason, + SearchPaths, + get_search_dirs, + mypy_path, +) from mypy.options import INCOMPLETE_FEATURES, BuildType, Options from mypy.split_namespace import SplitNamespace from mypy.version import __version__ @@ -545,15 +552,16 @@ def add_invertible_flag( ) config_group.add_argument( "--config-file", - help="Configuration file, must have a [mypy] section " - "(defaults to {})".format(", ".join(defaults.CONFIG_FILES)), + help=( + f"Configuration file, must have a [mypy] section " + f"(defaults to {', '.join(defaults.CONFIG_FILES)})" + ), ) add_invertible_flag( "--warn-unused-configs", default=False, strict_flag=True, - help="Warn about unused '[mypy-]' or '[[tool.mypy.overrides]]' " - "config sections", + help="Warn about unused '[mypy-]' or '[[tool.mypy.overrides]]' config sections", group=config_group, ) @@ -572,6 +580,11 @@ def add_invertible_flag( action="store_true", help="Silently ignore imports of missing modules", ) + imports_group.add_argument( + "--follow-untyped-imports", + action="store_true", + help="Typecheck modules without stubs or py.typed marker", + ) imports_group.add_argument( "--follow-imports", choices=["normal", "silent", "skip", "error"], @@ -582,8 +595,7 @@ def add_invertible_flag( "--python-executable", action="store", metavar="EXECUTABLE", - help="Python executable used for finding PEP 561 compliant installed" - " packages and stubs", + help="Python executable used for finding PEP 561 compliant installed packages and stubs", dest="special-opts:python_executable", ) imports_group.add_argument( @@ -616,8 +628,7 @@ def add_invertible_flag( "--platform", action="store", metavar="PLATFORM", - help="Type check special-cased code for the given OS platform " - "(defaults to sys.platform)", + help="Type check special-cased code for the given OS platform (defaults to sys.platform)", ) platform_group.add_argument( "--always-true", @@ -638,12 +649,6 @@ def add_invertible_flag( title="Disallow dynamic typing", description="Disallow the use of the dynamic 'Any' type under certain conditions.", ) - disallow_any_group.add_argument( - "--disallow-any-unimported", - default=False, - action="store_true", - help="Disallow Any types resulting from unfollowed imports", - ) disallow_any_group.add_argument( "--disallow-any-expr", default=False, @@ -654,8 +659,7 @@ def add_invertible_flag( "--disallow-any-decorated", default=False, action="store_true", - help="Disallow functions that have Any in their signature " - "after decorator transformation", + help="Disallow functions that have Any in their signature after decorator transformation", ) disallow_any_group.add_argument( "--disallow-any-explicit", @@ -670,6 +674,12 @@ def add_invertible_flag( help="Disallow usage of generic types that do not specify explicit type parameters", group=disallow_any_group, ) + add_invertible_flag( + "--disallow-any-unimported", + default=False, + help="Disallow Any types resulting from unfollowed imports", + group=disallow_any_group, + ) add_invertible_flag( "--disallow-subclassing-any", default=False, @@ -799,6 +809,13 @@ def add_invertible_flag( help="Warn about statements or expressions inferred to be unreachable", group=lint_group, ) + add_invertible_flag( + "--report-deprecated-as-note", + default=False, + strict_flag=False, + help="Report importing or using deprecated features as notes instead of errors", + group=lint_group, + ) # Note: this group is intentionally added here even though we don't add # --strict to this group near the end. @@ -1406,7 +1423,15 @@ def set_strict_flags() -> None: fail(f"Package name '{p}' cannot have a slash in it.", stderr, options) p_targets = cache.find_modules_recursive(p) if not p_targets: - fail(f"Can't find package '{p}'", stderr, options) + reason = cache.find_module(p) + if reason is ModuleNotFoundReason.FOUND_WITHOUT_TYPE_HINTS: + fail( + f"Package '{p}' cannot be type checked due to missing py.typed marker. See https://mypy.readthedocs.io/en/stable/installed_packages.html for more details", + stderr, + options, + ) + else: + fail(f"Can't find package '{p}'", stderr, options) targets.extend(p_targets) for m in special_opts.modules: targets.append(BuildSource(None, m, None)) @@ -1457,7 +1482,7 @@ def process_package_roots( root = "" package_root.append(root) options.package_root = package_root - # Pass the package root on the the filesystem cache. + # Pass the package root on the filesystem cache. fscache.set_package_root(package_root) diff --git a/mypy/meet.py b/mypy/meet.py index 9f5c2d72a8cb..cbe3e99cdcd8 100644 --- a/mypy/meet.py +++ b/mypy/meet.py @@ -223,7 +223,11 @@ def get_possible_variants(typ: Type) -> list[Type]: else: return [typ.upper_bound] elif isinstance(typ, ParamSpecType): - return [typ.upper_bound] + # Extract 'object' from the final mro item + upper_bound = get_proper_type(typ.upper_bound) + if isinstance(upper_bound, Instance): + return [Instance(upper_bound.type.mro[-1], [])] + return [AnyType(TypeOfAny.implementation_artifact)] elif isinstance(typ, TypeVarTupleType): return [typ.upper_bound] elif isinstance(typ, UnionType): @@ -243,8 +247,8 @@ def is_enum_overlapping_union(x: ProperType, y: ProperType) -> bool: and x.type.is_enum and isinstance(y, UnionType) and any( - isinstance(p, LiteralType) and x.type == p.fallback.type - for p in (get_proper_type(z) for z in y.relevant_items()) + isinstance(p := get_proper_type(z), LiteralType) and x.type == p.fallback.type + for z in y.relevant_items() ) ) @@ -687,7 +691,7 @@ def __init__(self, s: ProperType) -> None: def visit_unbound_type(self, t: UnboundType) -> ProperType: if isinstance(self.s, NoneType): if state.strict_optional: - return AnyType(TypeOfAny.special_form) + return UninhabitedType() else: return self.s elif isinstance(self.s, UninhabitedType): diff --git a/mypy/message_registry.py b/mypy/message_registry.py index 507af6fdad74..346a677a8e85 100644 --- a/mypy/message_registry.py +++ b/mypy/message_registry.py @@ -196,8 +196,7 @@ def with_additional_msg(self, info: str) -> ErrorMessage: TYPEVAR_ARG_MUST_BE_TYPE: Final = '{} "{}" must be a type' TYPEVAR_UNEXPECTED_ARGUMENT: Final = 'Unexpected argument to "TypeVar()"' UNBOUND_TYPEVAR: Final = ( - "A function returning TypeVar should receive at least " - "one argument containing the same TypeVar" + "A function returning TypeVar should receive at least one argument containing the same TypeVar" ) TYPE_PARAMETERS_SHOULD_BE_DECLARED: Final = ( "All type parameters should be declared ({} not declared)" @@ -351,6 +350,10 @@ def with_additional_msg(self, info: str) -> ErrorMessage: "Await expression cannot be used as a type variable bound", codes.SYNTAX ) +TYPE_VAR_GENERIC_CONSTRAINT_TYPE: Final = ErrorMessage( + "TypeVar constraint type cannot be parametrized by type variables", codes.MISC +) + TYPE_ALIAS_WITH_YIELD_EXPRESSION: Final = ErrorMessage( "Yield expression cannot be used within a type alias", codes.SYNTAX ) @@ -362,8 +365,3 @@ def with_additional_msg(self, info: str) -> ErrorMessage: TYPE_ALIAS_WITH_AWAIT_EXPRESSION: Final = ErrorMessage( "Await expression cannot be used within a type alias", codes.SYNTAX ) - -TYPE_PARAM_DEFAULT_NOT_SUPPORTED: Final = ErrorMessage( - "Type parameter default types not supported when using Python 3.12 type parameter syntax", - codes.MISC, -) diff --git a/mypy/messages.py b/mypy/messages.py index adf150eab50a..6b0760cd79c6 100644 --- a/mypy/messages.py +++ b/mypy/messages.py @@ -675,8 +675,7 @@ def incompatible_argument( arg_type, callee.arg_types[n - 1], options=self.options ) info = ( - f" (expression has type {arg_type_str}, " - f"target has type {callee_type_str})" + f" (expression has type {arg_type_str}, target has type {callee_type_str})" ) error_msg = ( message_registry.INCOMPATIBLE_TYPES_IN_ASSIGNMENT.with_additional_msg(info) @@ -871,7 +870,10 @@ def incompatible_argument_note( ) if call: self.note_call(original_caller_type, call, context, code=code) - + if isinstance(callee_type, Instance) and callee_type.type.is_protocol: + call = find_member("__call__", callee_type, callee_type, is_operator=True) + if call: + self.note_call(callee_type, call, context, code=code) self.maybe_note_concatenate_pos_args(original_caller_type, callee_type, context, code) def maybe_note_concatenate_pos_args( @@ -1395,7 +1397,7 @@ def could_not_infer_type_arguments( self.fail("Cannot infer function type argument", context) def invalid_var_arg(self, typ: Type, context: Context) -> None: - self.fail("List or tuple expected as variadic arguments", context) + self.fail("Expected iterable as variadic argument", context) def invalid_keyword_var_arg(self, typ: Type, is_mapping: bool, context: Context) -> None: typ = get_proper_type(typ) @@ -1433,8 +1435,7 @@ def first_argument_for_super_must_be_type(self, actual: Type, context: Context) def unsafe_super(self, method: str, cls: str, ctx: Context) -> None: self.fail( - 'Call to abstract method "{}" of "{}" with trivial body' - " via super() is unsafe".format(method, cls), + f'Call to abstract method "{method}" of "{cls}" with trivial body via super() is unsafe', ctx, code=codes.SAFE_SUPER, ) @@ -1588,8 +1589,10 @@ def final_cant_override_writable(self, name: str, ctx: Context) -> None: def cant_override_final(self, name: str, base_name: str, ctx: Context) -> None: self.fail( - 'Cannot override final attribute "{}"' - ' (previously declared in base class "{}")'.format(name, base_name), + ( + f'Cannot override final attribute "{name}" ' + f'(previously declared in base class "{base_name}")' + ), ctx, ) @@ -1676,15 +1679,16 @@ def overloaded_signatures_typevar_specific(self, index: int, context: Context) - def overloaded_signatures_arg_specific(self, index: int, context: Context) -> None: self.fail( - "Overloaded function implementation does not accept all possible arguments " - "of signature {}".format(index), + ( + f"Overloaded function implementation does not accept all possible arguments " + f"of signature {index}" + ), context, ) def overloaded_signatures_ret_specific(self, index: int, context: Context) -> None: self.fail( - "Overloaded function implementation cannot produce return type " - "of signature {}".format(index), + f"Overloaded function implementation cannot produce return type of signature {index}", context, ) @@ -1707,8 +1711,7 @@ def operator_method_signatures_overlap( context: Context, ) -> None: self.fail( - 'Signatures of "{}" of "{}" and "{}" of {} ' - "are unsafely overlapping".format( + 'Signatures of "{}" of "{}" and "{}" of {} are unsafely overlapping'.format( reverse_method, reverse_class.name, forward_method, @@ -1997,8 +2000,7 @@ def bad_proto_variance( self, actual: int, tvar_name: str, expected: int, context: Context ) -> None: msg = capitalize( - '{} type variable "{}" used in protocol where' - " {} one is expected".format( + '{} type variable "{}" used in protocol where {} one is expected'.format( variance_string(actual), tvar_name, variance_string(expected) ) ) @@ -2246,15 +2248,17 @@ def report_protocol_problems( for name, subflags, superflags in conflict_flags[:MAX_ITEMS]: if not class_obj and IS_CLASSVAR in subflags and IS_CLASSVAR not in superflags: self.note( - "Protocol member {}.{} expected instance variable," - " got class variable".format(supertype.type.name, name), + "Protocol member {}.{} expected instance variable, got class variable".format( + supertype.type.name, name + ), context, code=code, ) if not class_obj and IS_CLASSVAR in superflags and IS_CLASSVAR not in subflags: self.note( - "Protocol member {}.{} expected class variable," - " got instance variable".format(supertype.type.name, name), + "Protocol member {}.{} expected class variable, got instance variable".format( + supertype.type.name, name + ), context, code=code, ) diff --git a/mypy/metastore.py b/mypy/metastore.py index 4caa7d7f0534..ece397360e5b 100644 --- a/mypy/metastore.py +++ b/mypy/metastore.py @@ -27,20 +27,20 @@ class MetadataStore: @abstractmethod def getmtime(self, name: str) -> float: - """Read the mtime of a metadata entry.. + """Read the mtime of a metadata entry. Raises FileNotFound if the entry does not exist. """ @abstractmethod - def read(self, name: str) -> str: + def read(self, name: str) -> bytes: """Read the contents of a metadata entry. Raises FileNotFound if the entry does not exist. """ @abstractmethod - def write(self, name: str, data: str, mtime: float | None = None) -> bool: + def write(self, name: str, data: bytes, mtime: float | None = None) -> bool: """Write a metadata entry. If mtime is specified, set it as the mtime of the entry. Otherwise, @@ -86,16 +86,16 @@ def getmtime(self, name: str) -> float: return int(os.path.getmtime(os.path.join(self.cache_dir_prefix, name))) - def read(self, name: str) -> str: + def read(self, name: str) -> bytes: assert os.path.normpath(name) != os.path.abspath(name), "Don't use absolute paths!" if not self.cache_dir_prefix: raise FileNotFoundError() - with open(os.path.join(self.cache_dir_prefix, name)) as f: + with open(os.path.join(self.cache_dir_prefix, name), "rb") as f: return f.read() - def write(self, name: str, data: str, mtime: float | None = None) -> bool: + def write(self, name: str, data: bytes, mtime: float | None = None) -> bool: assert os.path.normpath(name) != os.path.abspath(name), "Don't use absolute paths!" if not self.cache_dir_prefix: @@ -105,7 +105,7 @@ def write(self, name: str, data: str, mtime: float | None = None) -> bool: tmp_filename = path + "." + random_string() try: os.makedirs(os.path.dirname(path), exist_ok=True) - with open(tmp_filename, "w") as f: + with open(tmp_filename, "wb") as f: f.write(data) os.replace(tmp_filename, path) if mtime is not None: @@ -131,19 +131,17 @@ def list_all(self) -> Iterable[str]: for dir, _, files in os.walk(self.cache_dir_prefix): dir = os.path.relpath(dir, self.cache_dir_prefix) for file in files: - yield os.path.join(dir, file) + yield os.path.normpath(os.path.join(dir, file)) SCHEMA = """ -CREATE TABLE IF NOT EXISTS files ( +CREATE TABLE IF NOT EXISTS files2 ( path TEXT UNIQUE NOT NULL, mtime REAL, - data TEXT + data BLOB ); -CREATE INDEX IF NOT EXISTS path_idx on files(path); +CREATE INDEX IF NOT EXISTS path_idx on files2(path); """ -# No migrations yet -MIGRATIONS: list[str] = [] def connect_db(db_file: str) -> sqlite3.Connection: @@ -151,11 +149,6 @@ def connect_db(db_file: str) -> sqlite3.Connection: db = sqlite3.dbapi2.connect(db_file) db.executescript(SCHEMA) - for migr in MIGRATIONS: - try: - db.executescript(migr) - except sqlite3.OperationalError: - pass return db @@ -176,7 +169,7 @@ def _query(self, name: str, field: str) -> Any: if not self.db: raise FileNotFoundError() - cur = self.db.execute(f"SELECT {field} FROM files WHERE path = ?", (name,)) + cur = self.db.execute(f"SELECT {field} FROM files2 WHERE path = ?", (name,)) results = cur.fetchall() if not results: raise FileNotFoundError() @@ -188,12 +181,12 @@ def getmtime(self, name: str) -> float: assert isinstance(mtime, float) return mtime - def read(self, name: str) -> str: + def read(self, name: str) -> bytes: data = self._query(name, "data") - assert isinstance(data, str) + assert isinstance(data, bytes) return data - def write(self, name: str, data: str, mtime: float | None = None) -> bool: + def write(self, name: str, data: bytes, mtime: float | None = None) -> bool: import sqlite3 if not self.db: @@ -202,7 +195,7 @@ def write(self, name: str, data: str, mtime: float | None = None) -> bool: if mtime is None: mtime = time.time() self.db.execute( - "INSERT OR REPLACE INTO files(path, mtime, data) VALUES(?, ?, ?)", + "INSERT OR REPLACE INTO files2(path, mtime, data) VALUES(?, ?, ?)", (name, mtime, data), ) except sqlite3.OperationalError: @@ -213,7 +206,7 @@ def remove(self, name: str) -> None: if not self.db: raise FileNotFoundError() - self.db.execute("DELETE FROM files WHERE path = ?", (name,)) + self.db.execute("DELETE FROM files2 WHERE path = ?", (name,)) def commit(self) -> None: if self.db: @@ -221,5 +214,5 @@ def commit(self) -> None: def list_all(self) -> Iterable[str]: if self.db: - for row in self.db.execute("SELECT path FROM files"): + for row in self.db.execute("SELECT path FROM files2"): yield row[0] diff --git a/mypy/modulefinder.py b/mypy/modulefinder.py index 452cfef20f4c..fdd89837002f 100644 --- a/mypy/modulefinder.py +++ b/mypy/modulefinder.py @@ -13,7 +13,7 @@ import subprocess import sys from enum import Enum, unique -from typing import Dict, Final, List, NamedTuple, Optional, Tuple, Union +from typing import Dict, Final, List, Optional, Tuple, Union from typing_extensions import TypeAlias as _TypeAlias from mypy import pyinfo @@ -21,15 +21,35 @@ from mypy.fscache import FileSystemCache from mypy.nodes import MypyFile from mypy.options import Options -from mypy.stubinfo import approved_stub_package_exists +from mypy.stubinfo import stub_distribution_name +from mypy.util import os_path_join # Paths to be searched in find_module(). -class SearchPaths(NamedTuple): - python_path: tuple[str, ...] # where user code is found - mypy_path: tuple[str, ...] # from $MYPYPATH or config variable - package_path: tuple[str, ...] # from get_site_packages_dirs() - typeshed_path: tuple[str, ...] # paths in typeshed +class SearchPaths: + def __init__( + self, + python_path: tuple[str, ...], + mypy_path: tuple[str, ...], + package_path: tuple[str, ...], + typeshed_path: tuple[str, ...], + ) -> None: + # where user code is found + self.python_path = tuple(map(os.path.abspath, python_path)) + # from $MYPYPATH or config variable + self.mypy_path = tuple(map(os.path.abspath, mypy_path)) + # from get_site_packages_dirs() + self.package_path = tuple(map(os.path.abspath, package_path)) + # paths in typeshed + self.typeshed_path = tuple(map(os.path.abspath, typeshed_path)) + + def asdict(self) -> dict[str, tuple[str, ...]]: + return { + "python_path": self.python_path, + "mypy_path": self.mypy_path, + "package_path": self.package_path, + "typeshed_path": self.typeshed_path, + } # Package dirs are a two-tuple of path to search and whether to verify the module @@ -72,8 +92,7 @@ def error_message_templates(self, daemon: bool) -> tuple[str, list[str]]: elif self is ModuleNotFoundReason.WRONG_WORKING_DIRECTORY: msg = 'Cannot find implementation or library stub for module named "{module}"' notes = [ - "You may be running mypy in a subpackage, " - "mypy should be run on the package root" + "You may be running mypy in a subpackage, mypy should be run on the package root" ] elif self is ModuleNotFoundReason.FOUND_WITHOUT_TYPE_HINTS: msg = ( @@ -205,7 +224,7 @@ def find_module_via_source_set(self, id: str) -> ModuleSearchResult | None: d = os.path.dirname(p) for _ in range(id.count(".")): if not any( - self.fscache.isfile(os.path.join(d, "__init__" + x)) for x in PYTHON_EXTENSIONS + self.fscache.isfile(os_path_join(d, "__init__" + x)) for x in PYTHON_EXTENSIONS ): return None d = os.path.dirname(d) @@ -239,17 +258,17 @@ def find_module_via_source_set(self, id: str) -> ModuleSearchResult | None: return None def find_lib_path_dirs(self, id: str, lib_path: tuple[str, ...]) -> PackageDirs: - """Find which elements of a lib_path have the directory a module needs to exist. - - This is run for the python_path, mypy_path, and typeshed_path search paths. - """ + """Find which elements of a lib_path have the directory a module needs to exist.""" components = id.split(".") dir_chain = os.sep.join(components[:-1]) # e.g., 'foo/bar' dirs = [] for pathitem in self.get_toplevel_possibilities(lib_path, components[0]): # e.g., '/usr/lib/python3.4/foo/bar' - dir = os.path.normpath(os.path.join(pathitem, dir_chain)) + if dir_chain: + dir = os_path_join(pathitem, dir_chain) + else: + dir = pathitem if self.fscache.isdir(dir): dirs.append((dir, True)) return dirs @@ -315,13 +334,14 @@ def _typeshed_has_version(self, module: str) -> bool: return version >= min_version and (max_version is None or version <= max_version) def _find_module_non_stub_helper( - self, components: list[str], pkg_dir: str + self, id: str, pkg_dir: str ) -> OnePackageDir | ModuleNotFoundReason: plausible_match = False dir_path = pkg_dir + components = id.split(".") for index, component in enumerate(components): - dir_path = os.path.join(dir_path, component) - if self.fscache.isfile(os.path.join(dir_path, "py.typed")): + dir_path = os_path_join(dir_path, component) + if self.fscache.isfile(os_path_join(dir_path, "py.typed")): return os.path.join(pkg_dir, *components[:-1]), index == 0 elif not plausible_match and ( self.fscache.isdir(dir_path) or self.fscache.isfile(dir_path + ".py") @@ -330,10 +350,11 @@ def _find_module_non_stub_helper( # If this is not a directory then we can't traverse further into it if not self.fscache.isdir(dir_path): break - for i in range(len(components), 0, -1): - if approved_stub_package_exists(".".join(components[:i])): - return ModuleNotFoundReason.APPROVED_STUBS_NOT_INSTALLED if plausible_match: + if self.options: + module_specific_options = self.options.clone_for_module(id) + if module_specific_options.follow_untyped_imports: + return os.path.join(pkg_dir, *components[:-1]), False return ModuleNotFoundReason.FOUND_WITHOUT_TYPE_HINTS else: return ModuleNotFoundReason.NOT_FOUND @@ -414,13 +435,19 @@ def _find_module(self, id: str, use_typeshed: bool) -> ModuleSearchResult: third_party_inline_dirs: PackageDirs = [] third_party_stubs_dirs: PackageDirs = [] found_possible_third_party_missing_type_hints = False - need_installed_stubs = False # Third-party stub/typed packages + candidate_package_dirs = { + package_dir[0] + for component in (components[0], components[0] + "-stubs") + for package_dir in self.find_lib_path_dirs(component, self.search_paths.package_path) + } for pkg_dir in self.search_paths.package_path: + if pkg_dir not in candidate_package_dirs: + continue stub_name = components[0] + "-stubs" - stub_dir = os.path.join(pkg_dir, stub_name) + stub_dir = os_path_join(pkg_dir, stub_name) if fscache.isdir(stub_dir): - stub_typed_file = os.path.join(stub_dir, "py.typed") + stub_typed_file = os_path_join(stub_dir, "py.typed") stub_components = [stub_name] + components[1:] path = os.path.join(pkg_dir, *stub_components[:-1]) if fscache.isdir(path): @@ -430,7 +457,7 @@ def _find_module(self, id: str, use_typeshed: bool) -> ModuleSearchResult: # Partial here means that mypy should look at the runtime # package if installed. if fscache.read(stub_typed_file).decode().strip() == "partial": - runtime_path = os.path.join(pkg_dir, dir_chain) + runtime_path = os_path_join(pkg_dir, dir_chain) third_party_inline_dirs.append((runtime_path, True)) # if the package is partial, we don't verify the module, as # the partial stub package may not have a __init__.pyi @@ -441,15 +468,14 @@ def _find_module(self, id: str, use_typeshed: bool) -> ModuleSearchResult: third_party_stubs_dirs.append((path, True)) else: third_party_stubs_dirs.append((path, True)) - non_stub_match = self._find_module_non_stub_helper(components, pkg_dir) + non_stub_match = self._find_module_non_stub_helper(id, pkg_dir) if isinstance(non_stub_match, ModuleNotFoundReason): if non_stub_match is ModuleNotFoundReason.FOUND_WITHOUT_TYPE_HINTS: found_possible_third_party_missing_type_hints = True - elif non_stub_match is ModuleNotFoundReason.APPROVED_STUBS_NOT_INSTALLED: - need_installed_stubs = True else: third_party_inline_dirs.append(non_stub_match) self._update_ns_ancestors(components, non_stub_match) + if self.options and self.options.use_builtins_fixtures: # Everything should be in fixtures. third_party_inline_dirs.clear() @@ -548,15 +574,28 @@ def _find_module(self, id: str, use_typeshed: bool) -> ModuleSearchResult: if ancestor is not None: return ancestor - if need_installed_stubs: - return ModuleNotFoundReason.APPROVED_STUBS_NOT_INSTALLED - elif found_possible_third_party_missing_type_hints: - return ModuleNotFoundReason.FOUND_WITHOUT_TYPE_HINTS - else: + approved_dist_name = stub_distribution_name(id) + if approved_dist_name: + if len(components) == 1: + return ModuleNotFoundReason.APPROVED_STUBS_NOT_INSTALLED + # If we're a missing submodule of an already installed approved stubs, we don't want to + # error with APPROVED_STUBS_NOT_INSTALLED, but rather want to return NOT_FOUND. + for i in range(1, len(components)): + parent_id = ".".join(components[:i]) + if stub_distribution_name(parent_id) == approved_dist_name: + break + else: + return ModuleNotFoundReason.APPROVED_STUBS_NOT_INSTALLED + if self.find_module(parent_id) is ModuleNotFoundReason.APPROVED_STUBS_NOT_INSTALLED: + return ModuleNotFoundReason.APPROVED_STUBS_NOT_INSTALLED return ModuleNotFoundReason.NOT_FOUND + if found_possible_third_party_missing_type_hints: + return ModuleNotFoundReason.FOUND_WITHOUT_TYPE_HINTS + return ModuleNotFoundReason.NOT_FOUND + def find_modules_recursive(self, module: str) -> list[BuildSource]: - module_path = self.find_module(module) + module_path = self.find_module(module, fast_path=True) if isinstance(module_path, ModuleNotFoundReason): return [] sources = [BuildSource(module_path, module, None)] @@ -580,7 +619,7 @@ def find_modules_recursive(self, module: str) -> list[BuildSource]: # Skip certain names altogether if name in ("__pycache__", "site-packages", "node_modules") or name.startswith("."): continue - subpath = os.path.join(package_path, name) + subpath = os_path_join(package_path, name) if self.options and matches_exclude( subpath, self.options.exclude, self.fscache, self.options.verbosity >= 2 @@ -590,8 +629,8 @@ def find_modules_recursive(self, module: str) -> list[BuildSource]: if self.fscache.isdir(subpath): # Only recurse into packages if (self.options and self.options.namespace_packages) or ( - self.fscache.isfile(os.path.join(subpath, "__init__.py")) - or self.fscache.isfile(os.path.join(subpath, "__init__.pyi")) + self.fscache.isfile(os_path_join(subpath, "__init__.py")) + or self.fscache.isfile(os_path_join(subpath, "__init__.pyi")) ): seen.add(name) sources.extend(self.find_modules_recursive(module + "." + name)) @@ -636,7 +675,7 @@ def verify_module(fscache: FileSystemCache, id: str, path: str, prefix: str) -> for i in range(id.count(".")): path = os.path.dirname(path) if not any( - fscache.isfile_case(os.path.join(path, f"__init__{extension}"), prefix) + fscache.isfile_case(os_path_join(path, f"__init__{extension}"), prefix) for extension in PYTHON_EXTENSIONS ): return False @@ -651,7 +690,7 @@ def highest_init_level(fscache: FileSystemCache, id: str, path: str, prefix: str for i in range(id.count(".")): path = os.path.dirname(path) if any( - fscache.isfile_case(os.path.join(path, f"__init__{extension}"), prefix) + fscache.isfile_case(os_path_join(path, f"__init__{extension}"), prefix) for extension in PYTHON_EXTENSIONS ): level = i + 1 @@ -668,10 +707,13 @@ def mypy_path() -> list[str]: def default_lib_path( data_dir: str, pyversion: tuple[int, int], custom_typeshed_dir: str | None ) -> list[str]: - """Return default standard library search paths.""" + """Return default standard library search paths. Guaranteed to be normalised.""" + + data_dir = os.path.abspath(data_dir) path: list[str] = [] if custom_typeshed_dir: + custom_typeshed_dir = os.path.abspath(custom_typeshed_dir) typeshed_dir = os.path.join(custom_typeshed_dir, "stdlib") mypy_extensions_dir = os.path.join(custom_typeshed_dir, "stubs", "mypy-extensions") versions_file = os.path.join(typeshed_dir, "VERSIONS") @@ -711,7 +753,7 @@ def default_lib_path( @functools.lru_cache(maxsize=None) def get_search_dirs(python_executable: str | None) -> tuple[list[str], list[str]]: - """Find package directories for given python. + """Find package directories for given python. Guaranteed to return absolute paths. This runs a subprocess call, which generates a list of the directories in sys.path. To avoid repeatedly calling a subprocess (which can be slow!) we @@ -740,6 +782,7 @@ def get_search_dirs(python_executable: str | None) -> tuple[list[str], list[str] print(err.stdout) raise except OSError as err: + assert err.errno is not None reason = os.strerror(err.errno) raise CompileError( [f"mypy: Invalid python executable '{python_executable}': {reason}"] @@ -773,6 +816,7 @@ def compute_search_paths( root_dir = os.getenv("MYPY_TEST_PREFIX", None) if not root_dir: root_dir = os.path.dirname(os.path.dirname(__file__)) + root_dir = os.path.abspath(root_dir) lib_path.appendleft(os.path.join(root_dir, "test-data", "unit", "lib-stub")) # alt_lib_path is used by some tests to bypass the normal lib_path mechanics. # If we don't have one, grab directories of source files. @@ -842,11 +886,11 @@ def load_stdlib_py_versions(custom_typeshed_dir: str | None) -> StdlibVersions: None means there is no maximum version. """ - typeshed_dir = custom_typeshed_dir or os.path.join(os.path.dirname(__file__), "typeshed") - stdlib_dir = os.path.join(typeshed_dir, "stdlib") + typeshed_dir = custom_typeshed_dir or os_path_join(os.path.dirname(__file__), "typeshed") + stdlib_dir = os_path_join(typeshed_dir, "stdlib") result = {} - versions_path = os.path.join(stdlib_dir, "VERSIONS") + versions_path = os_path_join(stdlib_dir, "VERSIONS") assert os.path.isfile(versions_path), (custom_typeshed_dir, versions_path, __file__) with open(versions_path) as f: for line in f: diff --git a/mypy/nodes.py b/mypy/nodes.py index 39cbee3c8525..9e26103e2f58 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -561,17 +561,19 @@ class OverloadedFuncDef(FuncBase, SymbolNode, Statement): Overloaded variants must be consecutive in the source file. """ - __slots__ = ("items", "unanalyzed_items", "impl") + __slots__ = ("items", "unanalyzed_items", "impl", "deprecated") items: list[OverloadPart] unanalyzed_items: list[OverloadPart] impl: OverloadPart | None + deprecated: str | None def __init__(self, items: list[OverloadPart]) -> None: super().__init__() self.items = items self.unanalyzed_items = items.copy() self.impl = None + self.deprecated = None if items: # TODO: figure out how to reliably set end position (we don't know the impl here). self.set_line(items[0].line, items[0].column) @@ -596,6 +598,7 @@ def serialize(self) -> JsonDict: "fullname": self._fullname, "impl": None if self.impl is None else self.impl.serialize(), "flags": get_flags(self, FUNCBASE_FLAGS), + "deprecated": self.deprecated, } @classmethod @@ -615,6 +618,7 @@ def deserialize(cls, data: JsonDict) -> OverloadedFuncDef: res.type = typ res._fullname = data["fullname"] set_flags(res, data["flags"]) + res.deprecated = data["deprecated"] # NOTE: res.info will be set in the fixup phase. return res @@ -666,7 +670,7 @@ def set_line( class TypeParam: - __slots__ = ("name", "kind", "upper_bound", "values") + __slots__ = ("name", "kind", "upper_bound", "values", "default") def __init__( self, @@ -674,11 +678,13 @@ def __init__( kind: int, upper_bound: mypy.types.Type | None, values: list[mypy.types.Type], + default: mypy.types.Type | None, ) -> None: self.name = name self.kind = kind self.upper_bound = upper_bound self.values = values + self.default = default FUNCITEM_FLAGS: Final = FUNCBASE_FLAGS + [ @@ -778,9 +784,10 @@ class FuncDef(FuncItem, SymbolNode, Statement): "deco_line", "is_trivial_body", "is_mypy_only", - # Present only when a function is decorated with @typing.datasclass_transform or similar + # Present only when a function is decorated with @typing.dataclass_transform or similar "dataclass_transform_spec", "docstring", + "deprecated", ) __match_args__ = ("name", "arguments", "type", "body") @@ -810,6 +817,7 @@ def __init__( self.is_mypy_only = False self.dataclass_transform_spec: DataclassTransformSpec | None = None self.docstring: str | None = None + self.deprecated: str | None = None @property def name(self) -> str: @@ -840,6 +848,7 @@ def serialize(self) -> JsonDict: if self.dataclass_transform_spec is None else self.dataclass_transform_spec.serialize() ), + "deprecated": self.deprecated, } @classmethod @@ -867,6 +876,7 @@ def deserialize(cls, data: JsonDict) -> FuncDef: if data["dataclass_transform_spec"] is not None else None ) + ret.deprecated = data["deprecated"] # Leave these uninitialized so that future uses will trigger an error del ret.arguments del ret.max_pos @@ -959,6 +969,7 @@ def is_dynamic(self) -> bool: "is_classvar", "is_abstract_var", "is_final", + "is_index_var", "final_unset_in_class", "final_set_in_init", "explicit_self_type", @@ -995,6 +1006,7 @@ class Var(SymbolNode): "is_classvar", "is_abstract_var", "is_final", + "is_index_var", "final_unset_in_class", "final_set_in_init", "is_suppressed_import", @@ -1029,6 +1041,7 @@ def __init__(self, name: str, type: mypy.types.Type | None = None) -> None: self.is_settable_property = False self.is_classvar = False self.is_abstract_var = False + self.is_index_var = False # Set to true when this variable refers to a module we were unable to # parse for some reason (eg a silenced module) self.is_suppressed_import = False @@ -1250,7 +1263,7 @@ class Block(Statement): __match_args__ = ("body", "is_unreachable") - def __init__(self, body: list[Statement]) -> None: + def __init__(self, body: list[Statement], *, is_unreachable: bool = False) -> None: super().__init__() self.body = body # True if we can determine that this block is not executed during semantic @@ -1258,7 +1271,7 @@ def __init__(self, body: list[Statement]) -> None: # something like "if PY3:" when using Python 2. However, some code is # only considered unreachable during type checking and this is not true # in those cases. - self.is_unreachable = False + self.is_unreachable = is_unreachable def accept(self, visitor: StatementVisitor[T]) -> T: return visitor.visit_block(self) @@ -1649,7 +1662,7 @@ def accept(self, visitor: StatementVisitor[T]) -> T: class TypeAliasStmt(Statement): - __slots__ = ("name", "type_args", "value", "invalid_recursive_alias") + __slots__ = ("name", "type_args", "value", "invalid_recursive_alias", "alias_node") __match_args__ = ("name", "type_args", "value") @@ -1657,6 +1670,7 @@ class TypeAliasStmt(Statement): type_args: list[TypeParam] value: LambdaExpr # Return value will get translated into a type invalid_recursive_alias: bool + alias_node: TypeAlias | None def __init__(self, name: NameExpr, type_args: list[TypeParam], value: LambdaExpr) -> None: super().__init__() @@ -1664,6 +1678,7 @@ def __init__(self, name: NameExpr, type_args: list[TypeParam], value: LambdaExpr self.type_args = type_args self.value = value self.invalid_recursive_alias = False + self.alias_node = None def accept(self, visitor: StatementVisitor[T]) -> T: return visitor.visit_type_alias_stmt(self) @@ -1712,7 +1727,7 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: return visitor.visit_str_expr(self) -def is_StrExpr_list(seq: list[Expression]) -> TypeGuard[list[StrExpr]]: +def is_StrExpr_list(seq: list[Expression]) -> TypeGuard[list[StrExpr]]: # noqa: N802 return all(isinstance(item, StrExpr) for item in seq) @@ -2887,6 +2902,10 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: } ) +# Attributes that can optionally be defined in the body of a subclass of +# enum.Enum but are removed from the class __dict__ by EnumMeta. +EXCLUDED_ENUM_ATTRIBUTES: Final = frozenset({"_ignore_", "_order_", "__order__"}) + class TypeInfo(SymbolNode): """The type structure of a single class. @@ -2942,6 +2961,7 @@ class is generic then it will be a type constructor of higher kind. "self_type", "dataclass_transform_spec", "is_type_check_only", + "deprecated", ) _fullname: str # Fully qualified name @@ -3095,6 +3115,9 @@ class is generic then it will be a type constructor of higher kind. # Is set to `True` when class is decorated with `@typing.type_check_only` is_type_check_only: bool + # The type's deprecation message (in case it is deprecated) + deprecated: str | None + FLAGS: Final = [ "is_abstract", "is_enum", @@ -3152,6 +3175,7 @@ def __init__(self, names: SymbolTable, defn: ClassDef, module_name: str) -> None self.self_type = None self.dataclass_transform_spec = None self.is_type_check_only = False + self.deprecated = None def add_type_vars(self) -> None: self.has_type_var_tuple_type = False @@ -3209,6 +3233,19 @@ def protocol_members(self) -> list[str]: members.add(name) return sorted(members) + @property + def enum_members(self) -> list[str]: + return [ + name + for name, sym in self.names.items() + if ( + isinstance(sym.node, Var) + and name not in EXCLUDED_ENUM_ATTRIBUTES + and not name.startswith("__") + and sym.node.has_explicit_value + ) + ] + def __getitem__(self, name: str) -> SymbolTableNode: n = self.get(name) if n: @@ -3374,6 +3411,7 @@ def serialize(self) -> JsonDict: if self.dataclass_transform_spec is not None else None ), + "deprecated": self.deprecated, } return data @@ -3441,6 +3479,7 @@ def deserialize(cls, data: JsonDict) -> TypeInfo: ti.dataclass_transform_spec = DataclassTransformSpec.deserialize( data["dataclass_transform_spec"] ) + ti.deprecated = data.get("deprecated") return ti diff --git a/mypy/options.py b/mypy/options.py index 56bd92957b41..33a2c75d164e 100644 --- a/mypy/options.py +++ b/mypy/options.py @@ -42,6 +42,7 @@ class BuildType: "extra_checks", "follow_imports_for_stubs", "follow_imports", + "follow_untyped_imports", "ignore_errors", "ignore_missing_imports", "implicit_optional", @@ -113,6 +114,8 @@ def __init__(self) -> None: self.ignore_missing_imports = False # Is ignore_missing_imports set in a per-module section self.ignore_missing_imports_per_module = False + # Typecheck modules without stubs or py.typed marker + self.follow_untyped_imports = False self.follow_imports = "normal" # normal|silent|skip|error # Whether to respect the follow_imports setting even for stub files. # Intended to be used for disabling specific stubs. @@ -173,6 +176,9 @@ def __init__(self) -> None: # declared with a precise type self.warn_return_any = False + # Report importing or using deprecated features as errors instead of notes. + self.report_deprecated_as_note = False + # Warn about unused '# type: ignore' comments self.warn_unused_ignores = False @@ -397,17 +403,12 @@ def use_or_syntax(self) -> bool: def use_star_unpack(self) -> bool: return self.python_version >= (3, 11) - # To avoid breaking plugin compatibility, keep providing new_semantic_analyzer - @property - def new_semantic_analyzer(self) -> bool: - return True - def snapshot(self) -> dict[str, object]: """Produce a comparable snapshot of this Option""" # Under mypyc, we don't have a __dict__, so we need to do worse things. d = dict(getattr(self, "__dict__", ())) for k in get_class_descriptors(Options): - if hasattr(self, k) and k != "new_semantic_analyzer": + if hasattr(self, k): d[k] = getattr(self, k) # Remove private attributes from snapshot d = {k: v for k, v in d.items() if not k.startswith("_")} diff --git a/mypy/plugin.py b/mypy/plugin.py index a1af7fa76350..fcbbc32f6237 100644 --- a/mypy/plugin.py +++ b/mypy/plugin.py @@ -114,9 +114,6 @@ class C: pass Note that a forward reference in a function signature won't trigger another pass, since all functions are processed only after the top level has been fully analyzed. - -You can use `api.options.new_semantic_analyzer` to check whether the new -semantic analyzer is enabled (it's always true in mypy 0.730 and later). """ from __future__ import annotations @@ -495,6 +492,7 @@ class MethodContext(NamedTuple): class AttributeContext(NamedTuple): type: ProperType # Type of object with attribute default_attr_type: Type # Original attribute type + is_lvalue: bool # Whether the attribute is the target of an assignment context: Context # Relevant location context (e.g. for error messages) api: CheckerPluginInterface diff --git a/mypy/plugins/dataclasses.py b/mypy/plugins/dataclasses.py index edfc6840fc37..349eca7f0143 100644 --- a/mypy/plugins/dataclasses.py +++ b/mypy/plugins/dataclasses.py @@ -400,7 +400,11 @@ def transform(self) -> bool: def _add_dunder_replace(self, attributes: list[DataclassAttribute]) -> None: """Add a `__replace__` method to the class, which is used to replace attributes in the `copy` module.""" - args = [attr.to_argument(self._cls.info, of="replace") for attr in attributes] + args = [ + attr.to_argument(self._cls.info, of="replace") + for attr in attributes + if attr.is_in_init + ] type_vars = [tv for tv in self._cls.type_vars] add_method_to_class( self._api, @@ -444,8 +448,7 @@ def add_slots( # This means that version is lower than `3.10`, # it is just a non-existent argument for `dataclass` function. self._api.fail( - 'Keyword argument "slots" for "dataclass" ' - "is only valid in Python 3.10 and higher", + 'Keyword argument "slots" for "dataclass" is only valid in Python 3.10 and higher', self._reason, ) return diff --git a/mypy/plugins/functools.py b/mypy/plugins/functools.py index 6650af637519..6a063174bfcb 100644 --- a/mypy/plugins/functools.py +++ b/mypy/plugins/functools.py @@ -8,16 +8,21 @@ import mypy.plugin import mypy.semanal from mypy.argmap import map_actuals_to_formals -from mypy.nodes import ARG_POS, ARG_STAR2, ArgKind, Argument, CallExpr, FuncItem, Var +from mypy.nodes import ARG_POS, ARG_STAR2, ArgKind, Argument, CallExpr, FuncItem, NameExpr, Var from mypy.plugins.common import add_method_to_class +from mypy.typeops import get_all_type_vars from mypy.types import ( AnyType, CallableType, Instance, Overloaded, + ParamSpecFlavor, + ParamSpecType, Type, TypeOfAny, + TypeVarType, UnboundType, + UnionType, get_proper_type, ) @@ -130,7 +135,19 @@ def partial_new_callback(ctx: mypy.plugin.FunctionContext) -> Type: if isinstance(get_proper_type(ctx.arg_types[0][0]), Overloaded): # TODO: handle overloads, just fall back to whatever the non-plugin code does return ctx.default_return_type - fn_type = ctx.api.extract_callable_type(ctx.arg_types[0][0], ctx=ctx.default_return_type) + return handle_partial_with_callee(ctx, callee=ctx.arg_types[0][0]) + + +def handle_partial_with_callee(ctx: mypy.plugin.FunctionContext, callee: Type) -> Type: + if not isinstance(ctx.api, mypy.checker.TypeChecker): # use internals + return ctx.default_return_type + + if isinstance(callee_proper := get_proper_type(callee), UnionType): + return UnionType.make_union( + [handle_partial_with_callee(ctx, item) for item in callee_proper.items] + ) + + fn_type = ctx.api.extract_callable_type(callee, ctx=ctx.default_return_type) if fn_type is None: return ctx.default_return_type @@ -151,21 +168,6 @@ def partial_new_callback(ctx: mypy.plugin.FunctionContext) -> Type: ctx.api.type_context[-1] = None wrapped_return = False - defaulted = fn_type.copy_modified( - arg_kinds=[ - ( - ArgKind.ARG_OPT - if k == ArgKind.ARG_POS - else (ArgKind.ARG_NAMED_OPT if k == ArgKind.ARG_NAMED else k) - ) - for k in fn_type.arg_kinds - ], - ret_type=ret_type, - ) - if defaulted.line < 0: - # Make up a line number if we don't have one - defaulted.set_line(ctx.default_return_type) - # Flatten actual to formal mapping, since this is what check_call() expects. actual_args = [] actual_arg_kinds = [] @@ -186,6 +188,45 @@ def partial_new_callback(ctx: mypy.plugin.FunctionContext) -> Type: actual_arg_names.append(ctx.arg_names[i][j]) actual_types.append(ctx.arg_types[i][j]) + formal_to_actual = map_actuals_to_formals( + actual_kinds=actual_arg_kinds, + actual_names=actual_arg_names, + formal_kinds=fn_type.arg_kinds, + formal_names=fn_type.arg_names, + actual_arg_type=lambda i: actual_types[i], + ) + + # We need to remove any type variables that appear only in formals that have + # no actuals, to avoid eagerly binding them in check_call() below. + can_infer_ids = set() + for i, arg_type in enumerate(fn_type.arg_types): + if not formal_to_actual[i]: + continue + can_infer_ids.update({tv.id for tv in get_all_type_vars(arg_type)}) + + # special_sig="partial" allows omission of args/kwargs typed with ParamSpec + defaulted = fn_type.copy_modified( + arg_kinds=[ + ( + ArgKind.ARG_OPT + if k == ArgKind.ARG_POS + else (ArgKind.ARG_NAMED_OPT if k == ArgKind.ARG_NAMED else k) + ) + for k in fn_type.arg_kinds + ], + ret_type=ret_type, + variables=[ + tv + for tv in fn_type.variables + # Keep TypeVarTuple/ParamSpec to avoid spurious errors on empty args. + if tv.id in can_infer_ids or not isinstance(tv, TypeVarType) + ], + special_sig="partial", + ) + if defaulted.line < 0: + # Make up a line number if we don't have one + defaulted.set_line(ctx.default_return_type) + # Create a valid context for various ad-hoc inspections in check_call(). call_expr = CallExpr( callee=ctx.args[0][0], @@ -218,14 +259,6 @@ def partial_new_callback(ctx: mypy.plugin.FunctionContext) -> Type: return ctx.default_return_type bound = bound.copy_modified(ret_type=ret_type.args[0]) - formal_to_actual = map_actuals_to_formals( - actual_kinds=actual_arg_kinds, - actual_names=actual_arg_names, - formal_kinds=fn_type.arg_kinds, - formal_names=fn_type.arg_names, - actual_arg_type=lambda i: actual_types[i], - ) - partial_kinds = [] partial_types = [] partial_names = [] @@ -267,10 +300,19 @@ def partial_new_callback(ctx: mypy.plugin.FunctionContext) -> Type: arg_kinds=partial_kinds, arg_names=partial_names, ret_type=ret_type, + special_sig="partial", ) ret = ctx.api.named_generic_type(PARTIAL, [ret_type]) ret = ret.copy_with_extra_attr("__mypy_partial", partially_applied) + if partially_applied.param_spec(): + assert ret.extra_attrs is not None # copy_with_extra_attr above ensures this + attrs = ret.extra_attrs.copy() + if ArgKind.ARG_STAR in actual_arg_kinds: + attrs.immutable.add("__mypy_partial_paramspec_args_bound") + if ArgKind.ARG_STAR2 in actual_arg_kinds: + attrs.immutable.add("__mypy_partial_paramspec_kwargs_bound") + ret.extra_attrs = attrs return ret @@ -285,7 +327,8 @@ def partial_call_callback(ctx: mypy.plugin.MethodContext) -> Type: ): return ctx.default_return_type - partial_type = ctx.type.extra_attrs.attrs["__mypy_partial"] + extra_attrs = ctx.type.extra_attrs + partial_type = get_proper_type(extra_attrs.attrs["__mypy_partial"]) if len(ctx.arg_types) != 2: # *args, **kwargs return ctx.default_return_type @@ -303,11 +346,36 @@ def partial_call_callback(ctx: mypy.plugin.MethodContext) -> Type: actual_arg_kinds.append(ctx.arg_kinds[i][j]) actual_arg_names.append(ctx.arg_names[i][j]) - result = ctx.api.expr_checker.check_call( + result, _ = ctx.api.expr_checker.check_call( callee=partial_type, args=actual_args, arg_kinds=actual_arg_kinds, arg_names=actual_arg_names, context=ctx.context, ) - return result[0] + if not isinstance(partial_type, CallableType) or partial_type.param_spec() is None: + return result + + args_bound = "__mypy_partial_paramspec_args_bound" in extra_attrs.immutable + kwargs_bound = "__mypy_partial_paramspec_kwargs_bound" in extra_attrs.immutable + + passed_paramspec_parts = [ + arg.node.type + for arg in actual_args + if isinstance(arg, NameExpr) + and isinstance(arg.node, Var) + and isinstance(arg.node.type, ParamSpecType) + ] + # ensure *args: P.args + args_passed = any(part.flavor == ParamSpecFlavor.ARGS for part in passed_paramspec_parts) + if not args_bound and not args_passed: + ctx.api.expr_checker.msg.too_few_arguments(partial_type, ctx.context, actual_arg_names) + elif args_bound and args_passed: + ctx.api.expr_checker.msg.too_many_arguments(partial_type, ctx.context) + + # ensure **kwargs: P.kwargs + kwargs_passed = any(part.flavor == ParamSpecFlavor.KWARGS for part in passed_paramspec_parts) + if not kwargs_bound and not kwargs_passed: + ctx.api.expr_checker.msg.too_few_arguments(partial_type, ctx.context, actual_arg_names) + + return result diff --git a/mypy/semanal.py b/mypy/semanal.py index 27abf2c1dc4c..edcc50e66e30 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -249,6 +249,7 @@ from mypy.types import ( ASSERT_TYPE_NAMES, DATACLASS_TRANSFORM_NAMES, + DEPRECATED_TYPE_NAMES, FINAL_DECORATOR_NAMES, FINAL_TYPE_NAMES, IMPORTED_REVEAL_TYPE_NAMES, @@ -289,6 +290,7 @@ UnpackType, get_proper_type, get_proper_types, + has_type_vars, is_named_instance, remove_dups, type_vars_as_args, @@ -483,6 +485,12 @@ def __init__( # Used to pass information about current overload index to visit_func_def(). self.current_overload_item: int | None = None + # Used to track whether currently inside an except* block. This helps + # to invoke errors when continue/break/return is used inside except* block. + self.inside_except_star_block: bool = False + # Used to track edge case when return is still inside except* if it enters a loop + self.return_stmt_inside_except_star_block: bool = False + # mypyc doesn't properly handle implementing an abstractproperty # with a regular attribute so we make them properties @property @@ -510,6 +518,25 @@ def allow_unbound_tvars_set(self) -> Iterator[None]: finally: self.allow_unbound_tvars = old + @contextmanager + def inside_except_star_block_set( + self, value: bool, entering_loop: bool = False + ) -> Iterator[None]: + old = self.inside_except_star_block + self.inside_except_star_block = value + + # Return statement would still be in except* scope if entering loops + if not entering_loop: + old_return_stmt_flag = self.return_stmt_inside_except_star_block + self.return_stmt_inside_except_star_block = value + + try: + yield + finally: + self.inside_except_star_block = old + if not entering_loop: + self.return_stmt_inside_except_star_block = old_return_stmt_flag + # # Preparing module (performed before semantic analysis) # @@ -876,7 +903,8 @@ def visit_func_def(self, defn: FuncDef) -> None: return with self.scope.function_scope(defn): - self.analyze_func_def(defn) + with self.inside_except_star_block_set(value=False): + self.analyze_func_def(defn) def function_fullname(self, fullname: str) -> str: if self.current_overload_item is None: @@ -1260,10 +1288,51 @@ def analyze_overloaded_func_def(self, defn: OverloadedFuncDef) -> None: return # We know this is an overload def. Infer properties and perform some checks. + self.process_deprecated_overload(defn) self.process_final_in_overload(defn) self.process_static_or_class_method_in_overload(defn) self.process_overload_impl(defn) + def process_deprecated_overload(self, defn: OverloadedFuncDef) -> None: + if defn.is_property: + return + + if isinstance(impl := defn.impl, Decorator) and ( + (deprecated := impl.func.deprecated) is not None + ): + defn.deprecated = deprecated + for item in defn.items: + if isinstance(item, Decorator): + item.func.deprecated = deprecated + + for item in defn.items: + deprecation = False + if isinstance(item, Decorator): + for d in item.decorators: + if deprecation and refers_to_fullname(d, OVERLOAD_NAMES): + self.msg.note("@overload should be placed before @deprecated", d) + elif (deprecated := self.get_deprecated(d)) is not None: + deprecation = True + if isinstance(typ := item.func.type, CallableType): + typestr = f" {typ} " + else: + typestr = " " + item.func.deprecated = ( + f"overload{typestr}of function {defn.fullname} is deprecated: " + f"{deprecated}" + ) + + @staticmethod + def get_deprecated(expression: Expression) -> str | None: + if ( + isinstance(expression, CallExpr) + and refers_to_fullname(expression.callee, DEPRECATED_TYPE_NAMES) + and (len(args := expression.args) >= 1) + and isinstance(deprecated := args[0], StrExpr) + ): + return deprecated.value + return None + def process_overload_impl(self, defn: OverloadedFuncDef) -> None: """Set flags for an overload implementation. @@ -1440,15 +1509,17 @@ def analyze_property_with_multi_part_definition(self, defn: OverloadedFuncDef) - for i, item in enumerate(items[1:]): if isinstance(item, Decorator): if len(item.decorators) >= 1: - node = item.decorators[0] - if isinstance(node, MemberExpr): - if node.name == "setter": + first_node = item.decorators[0] + if isinstance(first_node, MemberExpr): + if first_node.name == "setter": # The first item represents the entire property. first_item.var.is_settable_property = True # Get abstractness from the original definition. item.func.abstract_status = first_item.func.abstract_status - if node.name == "deleter": + if first_node.name == "deleter": item.func.abstract_status = first_item.func.abstract_status + for other_node in item.decorators[1:]: + other_node.accept(self) else: self.fail( f"Only supported top decorator is @{first_item.func.name}.setter", item @@ -1460,6 +1531,14 @@ def analyze_property_with_multi_part_definition(self, defn: OverloadedFuncDef) - for i in reversed(deleted_items): del items[i] + for item in items[1:]: + if isinstance(item, Decorator): + for d in item.decorators: + if (deprecated := self.get_deprecated(d)) is not None: + item.func.deprecated = ( + f"function {item.fullname} is deprecated: {deprecated}" + ) + def add_function_to_symbol_table(self, func: FuncDef | OverloadedFuncDef) -> None: if self.is_class_scope(): assert self.type is not None @@ -1632,6 +1711,7 @@ def visit_decorator(self, dec: Decorator) -> None: "abc.abstractproperty", "functools.cached_property", "enum.property", + "types.DynamicClassAttribute", ), ): removed.append(i) @@ -1663,6 +1743,8 @@ def visit_decorator(self, dec: Decorator) -> None: d.callee, DATACLASS_TRANSFORM_NAMES ): dec.func.dataclass_transform_spec = self.parse_dataclass_transform_spec(d) + elif (deprecated := self.get_deprecated(d)) is not None: + dec.func.deprecated = f"function {dec.fullname} is deprecated: {deprecated}" elif not dec.var.is_property: # We have seen a "non-trivial" decorator before seeing @property, if # we will see a @property later, give an error, as we don't support this. @@ -1754,15 +1836,38 @@ def analyze_type_param( upper_bound = self.named_type("builtins.tuple", [self.object_type()]) else: upper_bound = self.object_type() - default = AnyType(TypeOfAny.from_omitted_generics) + if type_param.default: + default = self.anal_type( + type_param.default, + allow_placeholder=True, + allow_unbound_tvars=True, + report_invalid_types=False, + allow_param_spec_literals=type_param.kind == PARAM_SPEC_KIND, + allow_tuple_literal=type_param.kind == PARAM_SPEC_KIND, + allow_unpack=type_param.kind == TYPE_VAR_TUPLE_KIND, + ) + if default is None: + default = PlaceholderType(None, [], context.line) + elif type_param.kind == TYPE_VAR_KIND: + default = self.check_typevar_default(default, type_param.default) + elif type_param.kind == PARAM_SPEC_KIND: + default = self.check_paramspec_default(default, type_param.default) + elif type_param.kind == TYPE_VAR_TUPLE_KIND: + default = self.check_typevartuple_default(default, type_param.default) + else: + default = AnyType(TypeOfAny.from_omitted_generics) if type_param.kind == TYPE_VAR_KIND: - values = [] + values: list[Type] = [] if type_param.values: for value in type_param.values: analyzed = self.anal_type(value, allow_placeholder=True) if analyzed is None: analyzed = PlaceholderType(None, [], context.line) - values.append(analyzed) + if has_type_vars(analyzed): + self.fail(message_registry.TYPE_VAR_GENERIC_CONSTRAINT_TYPE, context) + values.append(AnyType(TypeOfAny.from_error)) + else: + values.append(analyzed) return TypeVarExpr( name=type_param.name, fullname=fullname, @@ -2099,6 +2204,8 @@ def analyze_class_decorator_common( info.is_final = True elif refers_to_fullname(decorator, TYPE_CHECK_ONLY_NAMES): info.is_type_check_only = True + elif (deprecated := self.get_deprecated(decorator)) is not None: + info.deprecated = f"class {defn.fullname} is deprecated: {deprecated}" def clean_up_bases_and_infer_type_variables( self, defn: ClassDef, base_type_exprs: list[Expression], context: Context @@ -2187,21 +2294,7 @@ class Foo(Bar, Generic[T]): ... # grained incremental mode. defn.removed_base_type_exprs.append(defn.base_type_exprs[i]) del base_type_exprs[i] - tvar_defs: list[TypeVarLikeType] = [] - last_tvar_name_with_default: str | None = None - for name, tvar_expr in declared_tvars: - tvar_expr.default = tvar_expr.default.accept( - TypeVarDefaultTranslator(self, tvar_expr.name, context) - ) - tvar_def = self.tvar_scope.bind_new(name, tvar_expr) - if last_tvar_name_with_default is not None and not tvar_def.has_default(): - self.msg.tvar_without_default_type( - tvar_def.name, last_tvar_name_with_default, context - ) - tvar_def.default = AnyType(TypeOfAny.from_error) - elif tvar_def.has_default(): - last_tvar_name_with_default = tvar_def.name - tvar_defs.append(tvar_def) + tvar_defs = self.tvar_defs_from_tvars(declared_tvars, context) return base_type_exprs, tvar_defs, is_protocol def analyze_class_typevar_declaration(self, base: Type) -> tuple[TypeVarLikeList, bool] | None: @@ -2302,6 +2395,26 @@ def get_all_bases_tvars( tvars.extend(base_tvars) return remove_dups(tvars) + def tvar_defs_from_tvars( + self, tvars: TypeVarLikeList, context: Context + ) -> list[TypeVarLikeType]: + tvar_defs: list[TypeVarLikeType] = [] + last_tvar_name_with_default: str | None = None + for name, tvar_expr in tvars: + tvar_expr.default = tvar_expr.default.accept( + TypeVarDefaultTranslator(self, tvar_expr.name, context) + ) + tvar_def = self.tvar_scope.bind_new(name, tvar_expr) + if last_tvar_name_with_default is not None and not tvar_def.has_default(): + self.msg.tvar_without_default_type( + tvar_def.name, last_tvar_name_with_default, context + ) + tvar_def.default = AnyType(TypeOfAny.from_error) + elif tvar_def.has_default(): + last_tvar_name_with_default = tvar_def.name + tvar_defs.append(tvar_def) + return tvar_defs + def get_and_bind_all_tvars(self, type_exprs: list[Expression]) -> list[TypeVarLikeType]: """Return all type variable references in item type expressions. @@ -2555,8 +2668,7 @@ def calculate_class_mro( calculate_mro(defn.info, obj_type) except MroError: self.fail( - "Cannot determine consistent method resolution " - 'order (MRO) for "%s"' % defn.name, + f'Cannot determine consistent method resolution order (MRO) for "{defn.name}"', defn, ) self.set_dummy_mro(defn.info) @@ -3777,21 +3889,8 @@ def analyze_alias( tvar_defs: list[TypeVarLikeType] = [] namespace = self.qualified_name(name) alias_type_vars = found_type_vars if declared_type_vars is None else declared_type_vars - last_tvar_name_with_default: str | None = None with self.tvar_scope_frame(self.tvar_scope.class_frame(namespace)): - for name, tvar_expr in alias_type_vars: - tvar_expr.default = tvar_expr.default.accept( - TypeVarDefaultTranslator(self, tvar_expr.name, typ) - ) - tvar_def = self.tvar_scope.bind_new(name, tvar_expr) - if last_tvar_name_with_default is not None and not tvar_def.has_default(): - self.msg.tvar_without_default_type( - tvar_def.name, last_tvar_name_with_default, typ - ) - tvar_def.default = AnyType(TypeOfAny.from_error) - elif tvar_def.has_default(): - last_tvar_name_with_default = tvar_def.name - tvar_defs.append(tvar_def) + tvar_defs = self.tvar_defs_from_tvars(alias_type_vars, typ) if python_3_12_type_alias: with self.allow_unbound_tvars_set(): @@ -3803,6 +3902,7 @@ def analyze_alias( self.tvar_scope, self.plugin, self.options, + self.cur_mod_node, self.is_typeshed_stub_file, allow_placeholder=allow_placeholder, in_dynamic_func=dynamic, @@ -3958,8 +4058,10 @@ def check_and_set_up_type_alias(self, s: AssignmentStmt) -> bool: # so we need to replace it with non-explicit Anys. res = make_any_non_explicit(res) if self.options.disallow_any_unimported and has_any_from_unimported_type(res): - self.msg.unimported_type_becomes_any("Type alias target", res, s) - res = make_any_non_unimported(res) + # Only show error message once, when the type is fully analyzed. + if not has_placeholder(res): + self.msg.unimported_type_becomes_any("Type alias target", res, s) + res = make_any_non_unimported(res) # Note: with the new (lazy) type alias representation we only need to set no_args to True # if the expected number of arguments is non-zero, so that aliases like `A = List` work # but not aliases like `A = TypeAliasType("A", List)` as these need explicit type params. @@ -4013,6 +4115,8 @@ def check_and_set_up_type_alias(self, s: AssignmentStmt) -> bool: existing.node.alias_tvars = alias_tvars existing.node.no_args = no_args updated = True + # Invalidate recursive status cache in case it was previously set. + existing.node._is_recursive = None else: # Otherwise just replace existing placeholder with type alias. existing.node = alias_node @@ -4153,6 +4257,7 @@ def analyze_lvalue( is_final: bool = False, escape_comprehensions: bool = False, has_explicit_value: bool = False, + is_index_var: bool = False, ) -> None: """Analyze an lvalue or assignment target. @@ -4163,6 +4268,7 @@ def analyze_lvalue( escape_comprehensions: If we are inside a comprehension, set the variable in the enclosing scope instead. This implements https://www.python.org/dev/peps/pep-0572/#scope-of-the-target + is_index_var: If lval is the index variable in a for loop """ if escape_comprehensions: assert isinstance(lval, NameExpr), "assignment expression target must be NameExpr" @@ -4173,6 +4279,7 @@ def analyze_lvalue( is_final, escape_comprehensions, has_explicit_value=has_explicit_value, + is_index_var=is_index_var, ) elif isinstance(lval, MemberExpr): self.analyze_member_lvalue(lval, explicit_type, is_final, has_explicit_value) @@ -4199,6 +4306,7 @@ def analyze_name_lvalue( is_final: bool, escape_comprehensions: bool, has_explicit_value: bool, + is_index_var: bool, ) -> None: """Analyze an lvalue that targets a name expression. @@ -4235,9 +4343,18 @@ def analyze_name_lvalue( lvalue, ) + if explicit_type and has_explicit_value: + self.fail("Enum members must be left unannotated", lvalue) + self.note( + "See https://typing.readthedocs.io/en/latest/spec/enums.html#defining-members", + lvalue, + ) + if (not existing or isinstance(existing.node, PlaceholderNode)) and not outer: # Define new variable. - var = self.make_name_lvalue_var(lvalue, kind, not explicit_type, has_explicit_value) + var = self.make_name_lvalue_var( + lvalue, kind, not explicit_type, has_explicit_value, is_index_var + ) added = self.add_symbol(name, var, lvalue, escape_comprehensions=escape_comprehensions) # Only bind expression if we successfully added name to symbol table. if added: @@ -4289,7 +4406,12 @@ def is_alias_for_final_name(self, name: str) -> bool: return existing is not None and is_final_node(existing.node) def make_name_lvalue_var( - self, lvalue: NameExpr, kind: int, inferred: bool, has_explicit_value: bool + self, + lvalue: NameExpr, + kind: int, + inferred: bool, + has_explicit_value: bool, + is_index_var: bool, ) -> Var: """Return a Var node for an lvalue that is a name expression.""" name = lvalue.name @@ -4308,6 +4430,7 @@ def make_name_lvalue_var( v._fullname = name v.is_ready = False # Type not inferred yet v.has_explicit_value = has_explicit_value + v.is_index_var = is_index_var return v def make_name_lvalue_point_to_existing_def( @@ -4555,6 +4678,40 @@ def process_typevar_declaration(self, s: AssignmentStmt) -> bool: self.add_symbol(name, call.analyzed, s) return True + def check_typevar_default(self, default: Type, context: Context) -> Type: + typ = get_proper_type(default) + if isinstance(typ, AnyType) and typ.is_from_error: + self.fail( + message_registry.TYPEVAR_ARG_MUST_BE_TYPE.format("TypeVar", "default"), context + ) + return default + + def check_paramspec_default(self, default: Type, context: Context) -> Type: + typ = get_proper_type(default) + if isinstance(typ, Parameters): + for i, arg_type in enumerate(typ.arg_types): + arg_ptype = get_proper_type(arg_type) + if isinstance(arg_ptype, AnyType) and arg_ptype.is_from_error: + self.fail(f"Argument {i} of ParamSpec default must be a type", context) + elif ( + isinstance(typ, AnyType) + and typ.is_from_error + or not isinstance(typ, (AnyType, UnboundType)) + ): + self.fail( + "The default argument to ParamSpec must be a list expression, ellipsis, or a ParamSpec", + context, + ) + default = AnyType(TypeOfAny.from_error) + return default + + def check_typevartuple_default(self, default: Type, context: Context) -> Type: + typ = get_proper_type(default) + if not isinstance(typ, UnpackType): + self.fail("The default argument to TypeVarTuple must be an Unpacked tuple", context) + default = AnyType(TypeOfAny.from_error) + return default + def check_typevarlike_name(self, call: CallExpr, name: str, context: Context) -> bool: """Checks that the name of a TypeVar or ParamSpec matches its variable.""" name = unmangle(name) @@ -4762,23 +4919,7 @@ def process_paramspec_declaration(self, s: AssignmentStmt) -> bool: report_invalid_typevar_arg=False, ) default = tv_arg or AnyType(TypeOfAny.from_error) - if isinstance(tv_arg, Parameters): - for i, arg_type in enumerate(tv_arg.arg_types): - typ = get_proper_type(arg_type) - if isinstance(typ, AnyType) and typ.is_from_error: - self.fail( - f"Argument {i} of ParamSpec default must be a type", param_value - ) - elif ( - isinstance(default, AnyType) - and default.is_from_error - or not isinstance(default, (AnyType, UnboundType)) - ): - self.fail( - "The default argument to ParamSpec must be a list expression, ellipsis, or a ParamSpec", - param_value, - ) - default = AnyType(TypeOfAny.from_error) + default = self.check_paramspec_default(default, param_value) else: # ParamSpec is different from a regular TypeVar: # arguments are not semantically valid. But, allowed in runtime. @@ -4839,12 +4980,7 @@ def process_typevartuple_declaration(self, s: AssignmentStmt) -> bool: allow_unpack=True, ) default = tv_arg or AnyType(TypeOfAny.from_error) - if not isinstance(default, UnpackType): - self.fail( - "The default argument to TypeVarTuple must be an Unpacked tuple", - param_value, - ) - default = AnyType(TypeOfAny.from_error) + default = self.check_typevartuple_default(default, param_value) else: self.fail(f'Unexpected keyword argument "{param_name}" for "TypeVarTuple"', s) @@ -4913,7 +5049,11 @@ def analyze_value_types(self, items: list[Expression]) -> list[Type]: # soon, even if some value is not ready yet, see process_typevar_parameters() # for an example. analyzed = PlaceholderType(None, [], node.line) - result.append(analyzed) + if has_type_vars(analyzed): + self.fail(message_registry.TYPE_VAR_GENERIC_CONSTRAINT_TYPE, node) + result.append(AnyType(TypeOfAny.from_error)) + else: + result.append(analyzed) except TypeTranslationError: self.fail("Type expected", node) result.append(AnyType(TypeOfAny.from_error)) @@ -5159,6 +5299,8 @@ def visit_return_stmt(self, s: ReturnStmt) -> None: self.statement = s if not self.is_func_scope(): self.fail('"return" outside function', s) + if self.return_stmt_inside_except_star_block: + self.fail('"return" not allowed in except* block', s, serious=True) if s.expr: s.expr.accept(self) @@ -5192,7 +5334,8 @@ def visit_while_stmt(self, s: WhileStmt) -> None: self.statement = s s.expr.accept(self) self.loop_depth[-1] += 1 - s.body.accept(self) + with self.inside_except_star_block_set(value=False, entering_loop=True): + s.body.accept(self) self.loop_depth[-1] -= 1 self.visit_block_maybe(s.else_body) @@ -5205,7 +5348,7 @@ def visit_for_stmt(self, s: ForStmt) -> None: s.expr.accept(self) # Bind index variables and check if they define new names. - self.analyze_lvalue(s.index, explicit_type=s.index_type is not None) + self.analyze_lvalue(s.index, explicit_type=s.index_type is not None, is_index_var=True) if s.index_type: if self.is_classvar(s.index_type): self.fail_invalid_classvar(s.index) @@ -5216,20 +5359,24 @@ def visit_for_stmt(self, s: ForStmt) -> None: s.index_type = analyzed self.loop_depth[-1] += 1 - self.visit_block(s.body) + with self.inside_except_star_block_set(value=False, entering_loop=True): + self.visit_block(s.body) self.loop_depth[-1] -= 1 - self.visit_block_maybe(s.else_body) def visit_break_stmt(self, s: BreakStmt) -> None: self.statement = s if self.loop_depth[-1] == 0: self.fail('"break" outside loop', s, serious=True, blocker=True) + if self.inside_except_star_block: + self.fail('"break" not allowed in except* block', s, serious=True) def visit_continue_stmt(self, s: ContinueStmt) -> None: self.statement = s if self.loop_depth[-1] == 0: self.fail('"continue" outside loop', s, serious=True, blocker=True) + if self.inside_except_star_block: + self.fail('"continue" not allowed in except* block', s, serious=True) def visit_if_stmt(self, s: IfStmt) -> None: self.statement = s @@ -5250,7 +5397,8 @@ def analyze_try_stmt(self, s: TryStmt, visitor: NodeVisitor[None]) -> None: type.accept(visitor) if var: self.analyze_lvalue(var) - handler.accept(visitor) + with self.inside_except_star_block_set(self.inside_except_star_block or s.is_star): + handler.accept(visitor) if s.else_body: s.else_body.accept(visitor) if s.finally_body: @@ -5443,6 +5591,7 @@ def visit_type_alias_stmt(self, s: TypeAliasStmt) -> None: eager=eager, python_3_12_type_alias=True, ) + s.alias_node = alias_node if ( existing @@ -6405,18 +6554,46 @@ def lookup_fully_qualified_or_none(self, fullname: str) -> SymbolTableNode | Non Note that this can't be used for names nested in class namespaces. """ # TODO: unify/clean-up/simplify lookup methods, see #4157. - # TODO: support nested classes (but consider performance impact, - # we might keep the module level only lookup for thing like 'builtins.int'). - assert "." in fullname module, name = fullname.rsplit(".", maxsplit=1) - if module not in self.modules: - return None - filenode = self.modules[module] - result = filenode.names.get(name) - if result is None and self.is_incomplete_namespace(module): - # TODO: More explicit handling of incomplete refs? - self.record_incomplete_ref() - return result + + if module in self.modules: + # If the module exists, look up the name in the module. + # This is the common case. + filenode = self.modules[module] + result = filenode.names.get(name) + if result is None and self.is_incomplete_namespace(module): + # TODO: More explicit handling of incomplete refs? + self.record_incomplete_ref() + return result + else: + # Else, try to find the longest prefix of the module name that is in the modules dictionary. + splitted_modules = fullname.split(".") + names = [] + + while splitted_modules and ".".join(splitted_modules) not in self.modules: + names.append(splitted_modules.pop()) + + if not splitted_modules or not names: + # If no module or name is found, return None. + return None + + # Reverse the names list to get the correct order of names. + names.reverse() + + module = ".".join(splitted_modules) + filenode = self.modules[module] + result = filenode.names.get(names[0]) + + if result is None and self.is_incomplete_namespace(module): + # TODO: More explicit handling of incomplete refs? + self.record_incomplete_ref() + + for part in names[1:]: + if result is not None and isinstance(result.node, TypeInfo): + result = result.node.names.get(part) + else: + return None + return result def object_type(self) -> Instance: return self.named_type("builtins.object") @@ -7183,6 +7360,7 @@ def type_analyzer( tvar_scope, self.plugin, self.options, + self.cur_mod_node, self.is_typeshed_stub_file, allow_unbound_tvars=allow_unbound_tvars, allow_tuple_literal=allow_tuple_literal, diff --git a/mypy/semanal_enum.py b/mypy/semanal_enum.py index 30e0bd56c312..b1e267b4c781 100644 --- a/mypy/semanal_enum.py +++ b/mypy/semanal_enum.py @@ -10,6 +10,7 @@ from mypy.nodes import ( ARG_NAMED, ARG_POS, + EXCLUDED_ENUM_ATTRIBUTES, MDEF, AssignmentStmt, CallExpr, @@ -30,7 +31,7 @@ ) from mypy.options import Options from mypy.semanal_shared import SemanticAnalyzerInterface -from mypy.types import ENUM_REMOVED_PROPS, LiteralType, get_proper_type +from mypy.types import LiteralType, get_proper_type # Note: 'enum.EnumMeta' is deliberately excluded from this list. Classes that directly use # enum.EnumMeta do not necessarily automatically have the 'name' and 'value' attributes. @@ -43,7 +44,7 @@ "value", "_name_", "_value_", - *ENUM_REMOVED_PROPS, + *EXCLUDED_ENUM_ATTRIBUTES, # Also attributes from `object`: "__module__", "__annotations__", @@ -143,6 +144,12 @@ def build_enum_call_typeinfo( var = Var(item) var.info = info var.is_property = True + # When an enum is created by its functional form `Enum(name, values)` + # - if it is a string it is first split by commas/whitespace + # - if it is an iterable of single items each item is assigned a value starting at `start` + # - if it is an iterable of (name, value) then the given values will be used + # either way, each item should be treated as if it has an explicit value. + var.has_explicit_value = True var._fullname = f"{info.fullname}.{item}" info.names[item] = SymbolTableNode(MDEF, var) return info diff --git a/mypy/semanal_namedtuple.py b/mypy/semanal_namedtuple.py index 768dd265b338..7c6da7721e8f 100644 --- a/mypy/semanal_namedtuple.py +++ b/mypy/semanal_namedtuple.py @@ -380,8 +380,7 @@ def parse_namedtuple_args( rename = arg.name == "True" else: self.fail( - 'Boolean literal expected as the "rename" argument to ' - f"{type_name}()", + f'Boolean literal expected as the "rename" argument to {type_name}()', arg, code=ARG_TYPE, ) diff --git a/mypy/server/astdiff.py b/mypy/server/astdiff.py index fc868d288b4d..85f77a269e43 100644 --- a/mypy/server/astdiff.py +++ b/mypy/server/astdiff.py @@ -219,7 +219,9 @@ def snapshot_symbol_table(name_prefix: str, table: SymbolTable) -> dict[str, Sym assert symbol.kind != UNBOUND_IMPORTED if node and get_prefix(node.fullname) != name_prefix: # This is a cross-reference to a node defined in another module. - result[name] = ("CrossRef", common) + # Include the node kind (FuncDef, Decorator, TypeInfo, ...), so that we will + # reprocess when a *new* node is created instead of merging an existing one. + result[name] = ("CrossRef", common, type(node).__name__) else: result[name] = snapshot_definition(node, common) return result @@ -254,6 +256,7 @@ def snapshot_definition(node: SymbolNode | None, common: SymbolSnapshot) -> Symb signature, is_trivial_body, dataclass_transform_spec.serialize() if dataclass_transform_spec is not None else None, + node.deprecated if isinstance(node, FuncDef) else None, ) elif isinstance(node, Var): return ("Var", common, snapshot_optional_type(node.type), node.is_final) @@ -300,6 +303,7 @@ def snapshot_definition(node: SymbolNode | None, common: SymbolSnapshot) -> Symb [snapshot_type(base) for base in node.bases], [snapshot_type(p) for p in node._promote], dataclass_transform_spec.serialize() if dataclass_transform_spec is not None else None, + node.deprecated, ) prefix = node.fullname symbol_table = snapshot_symbol_table(prefix, node.names) diff --git a/mypy/server/astmerge.py b/mypy/server/astmerge.py index 174c2922c767..5dc254422328 100644 --- a/mypy/server/astmerge.py +++ b/mypy/server/astmerge.py @@ -160,7 +160,7 @@ def replacement_map_from_symbol_table( ): new_node = new[name] if ( - type(new_node.node) == type(node.node) # noqa: E721 + type(new_node.node) == type(node.node) and new_node.node and node.node and new_node.node.fullname == node.node.fullname diff --git a/mypy/server/deps.py b/mypy/server/deps.py index 9ed2d4549629..6376600ffc0c 100644 --- a/mypy/server/deps.py +++ b/mypy/server/deps.py @@ -56,7 +56,7 @@ class 'mod.Cls'. This can also refer to an attribute inherited from a * 'mod.Cls' represents each method in class 'mod.Cls' + the top-level of the module 'mod'. (To simplify the implementation, there is no location that only includes the body of a class without the entire surrounding module top level.) -* Trigger '<...>' as a location is an indirect way of referring to to all +* Trigger '<...>' as a location is an indirect way of referring to all locations triggered by the trigger. These indirect locations keep the dependency map smaller and easier to manage. diff --git a/mypy/server/update.py b/mypy/server/update.py index 0cc7a2229514..fdc311bbfa6b 100644 --- a/mypy/server/update.py +++ b/mypy/server/update.py @@ -146,11 +146,7 @@ TypeInfo, ) from mypy.options import Options -from mypy.semanal_main import ( - core_modules, - semantic_analysis_for_scc, - semantic_analysis_for_targets, -) +from mypy.semanal_main import semantic_analysis_for_scc, semantic_analysis_for_targets from mypy.server.astdiff import ( SymbolSnapshot, compare_symbol_table_snapshots, @@ -162,11 +158,12 @@ from mypy.server.target import trigger_to_target from mypy.server.trigger import WILDCARD_TAG, make_trigger from mypy.typestate import type_state -from mypy.util import module_prefix, split_target +from mypy.util import is_stdlib_file, module_prefix, split_target MAX_ITER: Final = 1000 -SENSITIVE_INTERNAL_MODULES = tuple(core_modules) + ("mypy_extensions", "typing_extensions") +# These are modules beyond stdlib that have some special meaning for mypy. +SENSITIVE_INTERNAL_MODULES = ("mypy_extensions", "typing_extensions") class FineGrainedBuildManager: @@ -406,7 +403,10 @@ def update_module( # builtins and friends could potentially get triggered because # of protocol stuff, but nothing good could possibly come from # actually updating them. - if module in SENSITIVE_INTERNAL_MODULES: + if ( + is_stdlib_file(self.manager.options.abs_custom_typeshed_dir, path) + or module in SENSITIVE_INTERNAL_MODULES + ): return [], (module, path), None manager = self.manager @@ -1059,8 +1059,7 @@ def find_symbol_tables_recursive(prefix: str, symbols: SymbolTable) -> dict[str, Returns a dictionary from full name to corresponding symbol table. """ - result = {} - result[prefix] = symbols + result = {prefix: symbols} for name, node in symbols.items(): if isinstance(node.node, TypeInfo) and node.node.fullname.startswith(prefix + "."): more = find_symbol_tables_recursive(prefix + "." + name, node.node.names) diff --git a/mypy/state.py b/mypy/state.py index cd3a360dd15f..533dceeb1f24 100644 --- a/mypy/state.py +++ b/mypy/state.py @@ -24,5 +24,5 @@ def strict_optional_set(self, value: bool) -> Iterator[None]: self.strict_optional = saved -state: Final = StrictOptionalState(strict_optional=False) +state: Final = StrictOptionalState(strict_optional=True) find_occurrences: tuple[str, str] | None = None diff --git a/mypy/strconv.py b/mypy/strconv.py index a96a27c45d75..2d595d4b67b0 100644 --- a/mypy/strconv.py +++ b/mypy/strconv.py @@ -112,7 +112,7 @@ def visit_mypy_file(self, o: mypy.nodes.MypyFile) -> str: if o.path != "main": # Insert path. Normalize directory separators to / to unify test # case# output in all platforms. - a.insert(0, o.path.replace(os.sep, "/")) + a.insert(0, o.path.replace(os.getcwd() + os.sep, "").replace(os.sep, "/")) if o.ignored_lines: a.append("IgnoredLines(%s)" % ", ".join(str(line) for line in sorted(o.ignored_lines))) return self.dump(a, o) @@ -349,6 +349,8 @@ def type_param(self, p: mypy.nodes.TypeParam) -> list[Any]: a.append(p.upper_bound) if p.values: a.append(("Values", p.values)) + if p.default: + a.append(("Default", [p.default])) return [("TypeParam", a)] # Expressions diff --git a/mypy/stubdoc.py b/mypy/stubdoc.py index 928d024514f3..434de0ea3bcb 100644 --- a/mypy/stubdoc.py +++ b/mypy/stubdoc.py @@ -76,6 +76,7 @@ class FunctionSig(NamedTuple): name: str args: list[ArgSig] ret_type: str | None + type_args: str = "" # TODO implement in stubgenc and remove the default def is_special_method(self) -> bool: return bool( @@ -141,9 +142,7 @@ def format_sig( retfield = " -> " + ret_type prefix = "async " if is_async else "" - sig = "{indent}{prefix}def {name}({args}){ret}:".format( - indent=indent, prefix=prefix, name=self.name, args=", ".join(args), ret=retfield - ) + sig = f"{indent}{prefix}def {self.name}{self.type_args}({', '.join(args)}){retfield}:" if docstring: suffix = f"\n{indent} {mypy.util.quote_docstring(docstring)}" else: diff --git a/mypy/stubgen.py b/mypy/stubgen.py index 02c0c1e58ab5..fdad5c2ddd89 100755 --- a/mypy/stubgen.py +++ b/mypy/stubgen.py @@ -106,6 +106,7 @@ StrExpr, TempNode, TupleExpr, + TypeAliasStmt, TypeInfo, UnaryExpr, Var, @@ -398,6 +399,9 @@ def visit_assignment_stmt(self, o: AssignmentStmt) -> None: for name in get_assigned_names(o.lvalues): self.names.add(name) + def visit_type_alias_stmt(self, o: TypeAliasStmt) -> None: + self.names.add(o.name.name) + def find_referenced_names(file: MypyFile) -> set[str]: finder = ReferenceFinder() @@ -468,7 +472,7 @@ def __init__( self._vars: list[list[str]] = [[]] # What was generated previously in the stub file. self._state = EMPTY - self._current_class: ClassDef | None = None + self._class_stack: list[ClassDef] = [] # Was the tree semantically analysed before? self.analyzed = analyzed # Short names of methods defined in the body of the current class @@ -476,6 +480,10 @@ def __init__( self.processing_enum = False self.processing_dataclass = False + @property + def _current_class(self) -> ClassDef | None: + return self._class_stack[-1] if self._class_stack else None + def visit_mypy_file(self, o: MypyFile) -> None: self.module_name = o.fullname # Current module being processed self.path = o.path @@ -507,7 +515,8 @@ def visit_overloaded_func_def(self, o: OverloadedFuncDef) -> None: def get_default_function_sig(self, func_def: FuncDef, ctx: FunctionContext) -> FunctionSig: args = self._get_func_args(func_def, ctx) retname = self._get_func_return(func_def, ctx) - return FunctionSig(func_def.name, args, retname) + type_args = self.format_type_args(func_def) + return FunctionSig(func_def.name, args, retname, type_args) def _get_func_args(self, o: FuncDef, ctx: FunctionContext) -> list[ArgSig]: args: list[ArgSig] = [] @@ -646,12 +655,14 @@ def visit_func_def(self, o: FuncDef) -> None: if init_code: self.add(init_code) - if self._current_class is not None: + if self._class_stack: if len(o.arguments): self_var = o.arguments[0].variable.name else: self_var = "self" - class_info = ClassInfo(self._current_class.name, self_var) + class_info: ClassInfo | None = None + for class_def in self._class_stack: + class_info = ClassInfo(class_def.name, self_var, parent=class_info) else: class_info = None @@ -741,7 +752,7 @@ def get_fullname(self, expr: Expression) -> str: return self.resolve_name(name) def visit_class_def(self, o: ClassDef) -> None: - self._current_class = o + self._class_stack.append(o) self.method_names = find_method_names(o.defs.body) sep: int | None = None if self.is_top_level() and self._state != EMPTY: @@ -765,7 +776,8 @@ def visit_class_def(self, o: ClassDef) -> None: self.import_tracker.add_import("abc") self.import_tracker.require_name("abc") bases = f"({', '.join(base_types)})" if base_types else "" - self.add(f"{self._indent}class {o.name}{bases}:\n") + type_args = self.format_type_args(o) + self.add(f"{self._indent}class {o.name}{type_args}{bases}:\n") self.indent() if self._include_docstrings and o.docstring: docstring = mypy.util.quote_docstring(o.docstring) @@ -786,8 +798,8 @@ def visit_class_def(self, o: ClassDef) -> None: self._state = CLASS self.method_names = set() self.processing_dataclass = False + self._class_stack.pop(-1) self.processing_enum = False - self._current_class = None def get_base_types(self, cdef: ClassDef) -> list[str]: """Get list of base classes for a class.""" @@ -1101,6 +1113,16 @@ def process_typealias(self, lvalue: NameExpr, rvalue: Expression) -> None: self.record_name(lvalue.name) self._vars[-1].append(lvalue.name) + def visit_type_alias_stmt(self, o: TypeAliasStmt) -> None: + """Type aliases defined with the `type` keyword (PEP 695).""" + p = AliasPrinter(self) + name = o.name.name + rvalue = o.value.expr() + type_args = self.format_type_args(o) + self.add(f"{self._indent}type {name}{type_args} = {rvalue.accept(p)}\n") + self.record_name(name) + self._vars[-1].append(name) + def visit_if_stmt(self, o: IfStmt) -> None: # Ignore if __name__ == '__main__'. expr = o.expr[0] @@ -1777,7 +1799,9 @@ def generate_stubs(options: Options) -> None: def parse_options(args: list[str]) -> Options: - parser = argparse.ArgumentParser(prog="stubgen", usage=HEADER, description=DESCRIPTION) + parser = argparse.ArgumentParser( + prog="stubgen", usage=HEADER, description=DESCRIPTION, fromfile_prefix_chars="@" + ) parser.add_argument( "--ignore-errors", diff --git a/mypy/stubgenc.py b/mypy/stubgenc.py index 7ab500b4fe12..1cd709b9d603 100755 --- a/mypy/stubgenc.py +++ b/mypy/stubgenc.py @@ -787,7 +787,9 @@ def get_base_types(self, obj: type) -> list[str]: bases.append(base) return [self.strip_or_import(self.get_type_fullname(base)) for base in bases] - def generate_class_stub(self, class_name: str, cls: type, output: list[str]) -> None: + def generate_class_stub( + self, class_name: str, cls: type, output: list[str], parent_class: ClassInfo | None = None + ) -> None: """Generate stub for a single class using runtime introspection. The result lines will be appended to 'output'. If necessary, any @@ -808,7 +810,9 @@ def generate_class_stub(self, class_name: str, cls: type, output: list[str]) -> self.record_name(class_name) self.indent() - class_info = ClassInfo(class_name, "", getattr(cls, "__doc__", None), cls) + class_info = ClassInfo( + class_name, "", getattr(cls, "__doc__", None), cls, parent=parent_class + ) for attr, value in items: # use unevaluated descriptors when dealing with property inspection @@ -843,7 +847,7 @@ def generate_class_stub(self, class_name: str, cls: type, output: list[str]) -> class_info, ) elif inspect.isclass(value) and self.is_defined_in_module(value): - self.generate_class_stub(attr, value, types) + self.generate_class_stub(attr, value, types, parent_class=class_info) else: attrs.append((attr, value)) diff --git a/mypy/stubinfo.py b/mypy/stubinfo.py index 9d8dfbe43f37..8d89a2a4bede 100644 --- a/mypy/stubinfo.py +++ b/mypy/stubinfo.py @@ -1,22 +1,37 @@ from __future__ import annotations -def is_legacy_bundled_package(prefix: str) -> bool: - return prefix in legacy_bundled_packages +def is_module_from_legacy_bundled_package(module: str) -> bool: + top_level = module.split(".", 1)[0] + return top_level in legacy_bundled_packages -def approved_stub_package_exists(prefix: str) -> bool: - return is_legacy_bundled_package(prefix) or prefix in non_bundled_packages +def stub_distribution_name(module: str) -> str | None: + top_level = module.split(".", 1)[0] + dist = legacy_bundled_packages.get(top_level) + if dist: + return dist + dist = non_bundled_packages_flat.get(top_level) + if dist: + return dist -def stub_distribution_name(prefix: str) -> str: - return legacy_bundled_packages.get(prefix) or non_bundled_packages[prefix] + if top_level in non_bundled_packages_namespace: + namespace = non_bundled_packages_namespace[top_level] + components = module.split(".") + for i in range(len(components), 0, -1): + module = ".".join(components[:i]) + dist = namespace.get(module) + if dist: + return dist + + return None # Stubs for these third-party packages used to be shipped with mypy. # # Map package name to PyPI stub distribution name. -legacy_bundled_packages = { +legacy_bundled_packages: dict[str, str] = { "aiofiles": "types-aiofiles", "bleach": "types-bleach", "boto": "types-boto", @@ -32,7 +47,6 @@ def stub_distribution_name(prefix: str) -> str: "docutils": "types-docutils", "first": "types-first", "gflags": "types-python-gflags", - "google.protobuf": "types-protobuf", "markdown": "types-Markdown", "mock": "types-mock", "OpenSSL": "types-pyOpenSSL", @@ -66,20 +80,17 @@ def stub_distribution_name(prefix: str) -> str: # include packages that have a release that includes PEP 561 type # information. # -# Package name can have one or two components ('a' or 'a.b'). -# # Note that these packages are omitted for now: # pika: typeshed's stubs are on PyPI as types-pika-ts. # types-pika already exists on PyPI, and is more complete in many ways, # but is a non-typeshed stubs package. -non_bundled_packages = { +non_bundled_packages_flat: dict[str, str] = { "MySQLdb": "types-mysqlclient", "PIL": "types-Pillow", "PyInstaller": "types-pyinstaller", "Xlib": "types-python-xlib", "aws_xray_sdk": "types-aws-xray-sdk", "babel": "types-babel", - "backports.ssl_match_hostname": "types-backports.ssl_match_hostname", "braintree": "types-braintree", "bs4": "types-beautifulsoup4", "bugbear": "types-flake8-bugbear", @@ -107,7 +118,6 @@ def stub_distribution_name(prefix: str) -> str: "flask_migrate": "types-Flask-Migrate", "fpdf": "types-fpdf2", "gdb": "types-gdb", - "google.cloud.ndb": "types-google-cloud-ndb", "hdbcli": "types-hdbcli", "html5lib": "types-html5lib", "httplib2": "types-httplib2", @@ -123,7 +133,6 @@ def stub_distribution_name(prefix: str) -> str: "oauthlib": "types-oauthlib", "openpyxl": "types-openpyxl", "opentracing": "types-opentracing", - "paho.mqtt": "types-paho-mqtt", "parsimonious": "types-parsimonious", "passlib": "types-passlib", "passpy": "types-passpy", @@ -171,3 +180,10 @@ def stub_distribution_name(prefix: str) -> str: "pandas": "pandas-stubs", # https://github.com/pandas-dev/pandas-stubs "lxml": "lxml-stubs", # https://github.com/lxml/lxml-stubs } + + +non_bundled_packages_namespace: dict[str, dict[str, str]] = { + "backports": {"backports.ssl_match_hostname": "types-backports.ssl_match_hostname"}, + "google": {"google.cloud.ndb": "types-google-cloud-ndb", "google.protobuf": "types-protobuf"}, + "paho": {"paho.mqtt": "types-paho-mqtt"}, +} diff --git a/mypy/stubtest.py b/mypy/stubtest.py index c54f83f33b00..36cd0a213d4d 100644 --- a/mypy/stubtest.py +++ b/mypy/stubtest.py @@ -133,7 +133,7 @@ def is_missing_stub(self) -> bool: def is_positional_only_related(self) -> bool: """Whether or not the error is for something being (or not being) positional-only.""" # TODO: This is hacky, use error codes or something more resilient - return "leading double underscore" in self.message + return "should be positional" in self.message def get_description(self, concise: bool = False) -> str: """Returns a description of the error. @@ -348,6 +348,8 @@ def verify_mypyfile( # Only verify the contents of the stub's __all__ # if the stub actually defines __all__ yield from _verify_exported_names(object_path, stub, runtime_all_as_set) + else: + yield Error(object_path + ["__all__"], "is not present in stub", MISSING, runtime) else: runtime_all_as_set = None @@ -700,7 +702,7 @@ def _verify_arg_default_value( stub_default != runtime_arg.default # We want the types to match exactly, e.g. in case the stub has # True and the runtime has 1 (or vice versa). - or type(stub_default) is not type(runtime_arg.default) # noqa: E721 + or type(stub_default) is not type(runtime_arg.default) ) ): yield ( @@ -909,7 +911,7 @@ def _verify_signature( ): yield ( f'stub argument "{stub_arg.variable.name}" should be positional-only ' - f'(rename with a leading double underscore, i.e. "__{runtime_arg.name}")' + f'(add "/", e.g. "{runtime_arg.name}, /")' ) if ( runtime_arg.kind != inspect.Parameter.POSITIONAL_ONLY @@ -919,7 +921,7 @@ def _verify_signature( ): yield ( f'stub argument "{stub_arg.variable.name}" should be positional or keyword ' - "(remove leading double underscore)" + '(remove "/")' ) # Check unmatched positional args @@ -1891,6 +1893,8 @@ class _Arguments: custom_typeshed_dir: str | None check_typeshed: bool version: str + show_traceback: bool + pdb: bool # typeshed added a stub for __main__, but that causes stubtest to check itself @@ -1936,6 +1940,8 @@ def test_stubs(args: _Arguments, use_builtins_fixtures: bool = False) -> int: options.abs_custom_typeshed_dir = os.path.abspath(options.custom_typeshed_dir) options.config_file = args.mypy_config_file options.use_builtins_fixtures = use_builtins_fixtures + options.show_traceback = args.show_traceback + options.pdb = args.pdb if options.config_file: @@ -2089,6 +2095,10 @@ def parse_options(args: list[str]) -> _Arguments: parser.add_argument( "--version", action="version", version="%(prog)s " + mypy.version.__version__ ) + parser.add_argument("--pdb", action="store_true", help="Invoke pdb on fatal error") + parser.add_argument( + "--show-traceback", "--tb", action="store_true", help="Show traceback on fatal error" + ) return parser.parse_args(args, namespace=_Arguments()) diff --git a/mypy/stubutil.py b/mypy/stubutil.py index 04b36e149957..c11843c57f2a 100644 --- a/mypy/stubutil.py +++ b/mypy/stubutil.py @@ -16,6 +16,7 @@ import mypy.options from mypy.modulefinder import ModuleNotFoundReason from mypy.moduleinspect import InspectError, ModuleInspect +from mypy.nodes import PARAM_SPEC_KIND, TYPE_VAR_TUPLE_KIND, ClassDef, FuncDef, TypeAliasStmt from mypy.stubdoc import ArgSig, FunctionSig from mypy.types import AnyType, NoneType, Type, TypeList, TypeStrVisitor, UnboundType, UnionType @@ -306,12 +307,18 @@ def args_str(self, args: Iterable[Type]) -> str: class ClassInfo: def __init__( - self, name: str, self_var: str, docstring: str | None = None, cls: type | None = None + self, + name: str, + self_var: str, + docstring: str | None = None, + cls: type | None = None, + parent: ClassInfo | None = None, ) -> None: self.name = name self.self_var = self_var self.docstring = docstring self.cls = cls + self.parent = parent class FunctionContext: @@ -334,7 +341,13 @@ def __init__( def fullname(self) -> str: if self._fullname is None: if self.class_info: - self._fullname = f"{self.module_name}.{self.class_info.name}.{self.name}" + parents = [] + class_info: ClassInfo | None = self.class_info + while class_info is not None: + parents.append(class_info.name) + class_info = class_info.parent + namespace = ".".join(reversed(parents)) + self._fullname = f"{self.module_name}.{namespace}.{self.name}" else: self._fullname = f"{self.module_name}.{self.name}" return self._fullname @@ -777,6 +790,31 @@ def format_func_def( ) return lines + def format_type_args(self, o: TypeAliasStmt | FuncDef | ClassDef) -> str: + if not o.type_args: + return "" + p = AnnotationPrinter(self) + type_args_list: list[str] = [] + for type_arg in o.type_args: + if type_arg.kind == PARAM_SPEC_KIND: + prefix = "**" + elif type_arg.kind == TYPE_VAR_TUPLE_KIND: + prefix = "*" + else: + prefix = "" + if type_arg.upper_bound: + bound_or_values = f": {type_arg.upper_bound.accept(p)}" + elif type_arg.values: + bound_or_values = f": ({', '.join(v.accept(p) for v in type_arg.values)})" + else: + bound_or_values = "" + if type_arg.default: + default = f" = {type_arg.default.accept(p)}" + else: + default = "" + type_args_list.append(f"{prefix}{type_arg.name}{bound_or_values}{default}") + return "[" + ", ".join(type_args_list) + "]" + def print_annotation( self, t: Type, @@ -794,6 +832,8 @@ def is_not_in_all(self, name: str) -> bool: return False def is_private_name(self, name: str, fullname: str | None = None) -> bool: + if "__mypy-" in name: + return True # Never include mypy generated symbols if self._include_private: return False if fullname in self.EXTRA_EXPORTED: diff --git a/mypy/subtypes.py b/mypy/subtypes.py index 787d5cb89b0a..a26aaf798b58 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -625,8 +625,8 @@ def visit_instance(self, left: Instance) -> bool: return is_named_instance(item, "builtins.object") if isinstance(right, LiteralType) and left.last_known_value is not None: return self._is_subtype(left.last_known_value, right) - if isinstance(right, CallableType): - # Special case: Instance can be a subtype of Callable. + if isinstance(right, FunctionLike): + # Special case: Instance can be a subtype of Callable / Overloaded. call = find_member("__call__", left, left, is_operator=True) if call: return self._is_subtype(call, right) @@ -892,32 +892,35 @@ def visit_typeddict_type(self, left: TypedDictType) -> bool: return False for name, l, r in left.zip(right): # TODO: should we pass on the full subtype_context here and below? - if self.proper_subtype: - check = is_same_type(l, r) + right_readonly = name in right.readonly_keys + if not right_readonly: + if self.proper_subtype: + check = is_same_type(l, r) + else: + check = is_equivalent( + l, + r, + ignore_type_params=self.subtype_context.ignore_type_params, + options=self.options, + ) else: - check = is_equivalent( - l, - r, - ignore_type_params=self.subtype_context.ignore_type_params, - options=self.options, - ) + # Read-only items behave covariantly + check = self._is_subtype(l, r) if not check: return False # Non-required key is not compatible with a required key since # indexing may fail unexpectedly if a required key is missing. - # Required key is not compatible with a non-required key since - # the prior doesn't support 'del' but the latter should support - # it. - # - # NOTE: 'del' support is currently not implemented (#3550). We - # don't want to have to change subtyping after 'del' support - # lands so here we are anticipating that change. - if (name in left.required_keys) != (name in right.required_keys): + # Required key is not compatible with a non-read-only non-required + # key since the prior doesn't support 'del' but the latter should + # support it. + # Required key is compatible with a read-only non-required key. + required_differ = (name in left.required_keys) != (name in right.required_keys) + if not right_readonly and required_differ: return False # Readonly fields check: # # A = TypedDict('A', {'x': ReadOnly[int]}) - # B = TypedDict('A', {'x': int}) + # B = TypedDict('B', {'x': int}) # def reset_x(b: B) -> None: # b['x'] = 0 # diff --git a/mypy/test/data.py b/mypy/test/data.py index ee567afe2125..bc17178d20e0 100644 --- a/mypy/test/data.py +++ b/mypy/test/data.py @@ -304,7 +304,7 @@ def __init__( self.data = data self.line = line self.old_cwd: str | None = None - self.tmpdir: tempfile.TemporaryDirectory[str] | None = None + self.tmpdir: str | None = None def runtest(self) -> None: if self.skip: @@ -323,19 +323,19 @@ def runtest(self) -> None: save_dir: str | None = self.config.getoption("--save-failures-to", None) if save_dir: assert self.tmpdir is not None - target_dir = os.path.join(save_dir, os.path.basename(self.tmpdir.name)) + target_dir = os.path.join(save_dir, os.path.basename(self.tmpdir)) print(f"Copying data from test {self.name} to {target_dir}") if not os.path.isabs(target_dir): assert self.old_cwd target_dir = os.path.join(self.old_cwd, target_dir) - shutil.copytree(self.tmpdir.name, target_dir) + shutil.copytree(self.tmpdir, target_dir) raise def setup(self) -> None: parse_test_case(case=self) self.old_cwd = os.getcwd() - self.tmpdir = tempfile.TemporaryDirectory(prefix="mypy-test-") - os.chdir(self.tmpdir.name) + self.tmpdir = tempfile.mkdtemp(prefix="mypy-test-") + os.chdir(self.tmpdir) os.mkdir(test_temp_dir) # Precalculate steps for find_steps() @@ -371,10 +371,7 @@ def teardown(self) -> None: if self.old_cwd is not None: os.chdir(self.old_cwd) if self.tmpdir is not None: - try: - self.tmpdir.cleanup() - except OSError: - pass + shutil.rmtree(self.tmpdir, ignore_errors=True) self.old_cwd = None self.tmpdir = None diff --git a/mypy/test/testfinegrained.py b/mypy/test/testfinegrained.py index 800ba2dff087..cb8672dfaf29 100644 --- a/mypy/test/testfinegrained.py +++ b/mypy/test/testfinegrained.py @@ -101,8 +101,8 @@ def run_case(self, testcase: DataDrivenTestCase) -> None: if messages: a.extend(normalize_messages(messages)) - assert testcase.tmpdir - a.extend(self.maybe_suggest(step, server, main_src, testcase.tmpdir.name)) + assert testcase.tmpdir is not None + a.extend(self.maybe_suggest(step, server, main_src, testcase.tmpdir)) a.extend(self.maybe_inspect(step, server, main_src)) if server.fine_grained_manager: @@ -248,8 +248,8 @@ def perform_step( new_messages = normalize_messages(new_messages) a = new_messages - assert testcase.tmpdir - a.extend(self.maybe_suggest(step, server, main_src, testcase.tmpdir.name)) + assert testcase.tmpdir is not None + a.extend(self.maybe_suggest(step, server, main_src, testcase.tmpdir)) a.extend(self.maybe_inspect(step, server, main_src)) return a, triggered diff --git a/mypy/test/testmodulefinder.py b/mypy/test/testmodulefinder.py index 943913d6cadb..65d9a66c5fa0 100644 --- a/mypy/test/testmodulefinder.py +++ b/mypy/test/testmodulefinder.py @@ -53,12 +53,12 @@ def test__no_namespace_packages__find_a_in_pkg1(self) -> None: Find find pkg1/a.py for "a" with namespace_packages False. """ found_module = self.fmc_nons.find_module("a") - expected = os.path.join(data_path, "pkg1", "a.py") + expected = os.path.abspath(os.path.join(data_path, "pkg1", "a.py")) assert_equal(expected, found_module) def test__no_namespace_packages__find_b_in_pkg2(self) -> None: found_module = self.fmc_ns.find_module("b") - expected = os.path.join(data_path, "pkg2", "b", "__init__.py") + expected = os.path.abspath(os.path.join(data_path, "pkg2", "b", "__init__.py")) assert_equal(expected, found_module) def test__find_nsx_as_namespace_pkg_in_pkg1(self) -> None: @@ -67,7 +67,7 @@ def test__find_nsx_as_namespace_pkg_in_pkg1(self) -> None: the path to the first one found in mypypath. """ found_module = self.fmc_ns.find_module("nsx") - expected = os.path.join(data_path, "nsx-pkg1", "nsx") + expected = os.path.abspath(os.path.join(data_path, "nsx-pkg1", "nsx")) assert_equal(expected, found_module) def test__find_nsx_a_init_in_pkg1(self) -> None: @@ -75,7 +75,7 @@ def test__find_nsx_a_init_in_pkg1(self) -> None: Find nsx-pkg1/nsx/a/__init__.py for "nsx.a" in namespace mode. """ found_module = self.fmc_ns.find_module("nsx.a") - expected = os.path.join(data_path, "nsx-pkg1", "nsx", "a", "__init__.py") + expected = os.path.abspath(os.path.join(data_path, "nsx-pkg1", "nsx", "a", "__init__.py")) assert_equal(expected, found_module) def test__find_nsx_b_init_in_pkg2(self) -> None: @@ -83,7 +83,7 @@ def test__find_nsx_b_init_in_pkg2(self) -> None: Find nsx-pkg2/nsx/b/__init__.py for "nsx.b" in namespace mode. """ found_module = self.fmc_ns.find_module("nsx.b") - expected = os.path.join(data_path, "nsx-pkg2", "nsx", "b", "__init__.py") + expected = os.path.abspath(os.path.join(data_path, "nsx-pkg2", "nsx", "b", "__init__.py")) assert_equal(expected, found_module) def test__find_nsx_c_c_in_pkg3(self) -> None: @@ -91,7 +91,7 @@ def test__find_nsx_c_c_in_pkg3(self) -> None: Find nsx-pkg3/nsx/c/c.py for "nsx.c.c" in namespace mode. """ found_module = self.fmc_ns.find_module("nsx.c.c") - expected = os.path.join(data_path, "nsx-pkg3", "nsx", "c", "c.py") + expected = os.path.abspath(os.path.join(data_path, "nsx-pkg3", "nsx", "c", "c.py")) assert_equal(expected, found_module) def test__find_nsy_a__init_pyi(self) -> None: @@ -99,7 +99,7 @@ def test__find_nsy_a__init_pyi(self) -> None: Prefer nsy-pkg1/a/__init__.pyi file over __init__.py. """ found_module = self.fmc_ns.find_module("nsy.a") - expected = os.path.join(data_path, "nsy-pkg1", "nsy", "a", "__init__.pyi") + expected = os.path.abspath(os.path.join(data_path, "nsy-pkg1", "nsy", "a", "__init__.pyi")) assert_equal(expected, found_module) def test__find_nsy_b__init_py(self) -> None: @@ -109,7 +109,7 @@ def test__find_nsy_b__init_py(self) -> None: a package is preferred over a module. """ found_module = self.fmc_ns.find_module("nsy.b") - expected = os.path.join(data_path, "nsy-pkg2", "nsy", "b", "__init__.py") + expected = os.path.abspath(os.path.join(data_path, "nsy-pkg2", "nsy", "b", "__init__.py")) assert_equal(expected, found_module) def test__find_nsy_c_pyi(self) -> None: @@ -119,17 +119,17 @@ def test__find_nsy_c_pyi(self) -> None: .pyi is preferred over .py. """ found_module = self.fmc_ns.find_module("nsy.c") - expected = os.path.join(data_path, "nsy-pkg2", "nsy", "c.pyi") + expected = os.path.abspath(os.path.join(data_path, "nsy-pkg2", "nsy", "c.pyi")) assert_equal(expected, found_module) def test__find_a_in_pkg1(self) -> None: found_module = self.fmc_ns.find_module("a") - expected = os.path.join(data_path, "pkg1", "a.py") + expected = os.path.abspath(os.path.join(data_path, "pkg1", "a.py")) assert_equal(expected, found_module) def test__find_b_init_in_pkg2(self) -> None: found_module = self.fmc_ns.find_module("b") - expected = os.path.join(data_path, "pkg2", "b", "__init__.py") + expected = os.path.abspath(os.path.join(data_path, "pkg2", "b", "__init__.py")) assert_equal(expected, found_module) def test__find_d_nowhere(self) -> None: @@ -165,7 +165,7 @@ def setUp(self) -> None: self.fmc_nons = FindModuleCache(self.search_paths, fscache=None, options=options) def path(self, *parts: str) -> str: - return os.path.join(self.package_dir, *parts) + return os.path.abspath(os.path.join(self.package_dir, *parts)) def test__packages_with_ns(self) -> None: cases = [ @@ -214,7 +214,7 @@ def test__packages_with_ns(self) -> None: # A regular package with an installed set of stubs ("foo.bar", self.path("foo-stubs", "bar.pyi")), # A regular, non-site-packages module - ("a", os.path.join(data_path, "pkg1", "a.py")), + ("a", os.path.abspath(os.path.join(data_path, "pkg1", "a.py"))), ] for module, expected in cases: template = "Find(" + module + ") got {}; expected {}" @@ -269,7 +269,7 @@ def test__packages_without_ns(self) -> None: # A regular package with an installed set of stubs ("foo.bar", self.path("foo-stubs", "bar.pyi")), # A regular, non-site-packages module - ("a", os.path.join(data_path, "pkg1", "a.py")), + ("a", os.path.abspath(os.path.join(data_path, "pkg1", "a.py"))), ] for module, expected in cases: template = "Find(" + module + ") got {}; expected {}" diff --git a/mypy/test/testparse.py b/mypy/test/testparse.py index e215920a6797..074ccfb379d0 100644 --- a/mypy/test/testparse.py +++ b/mypy/test/testparse.py @@ -25,6 +25,8 @@ class ParserSuite(DataSuite): files.remove("parse-python310.test") if sys.version_info < (3, 12): files.remove("parse-python312.test") + if sys.version_info < (3, 13): + files.remove("parse-python313.test") def run_case(self, testcase: DataDrivenTestCase) -> None: test_parser(testcase) @@ -43,6 +45,8 @@ def test_parser(testcase: DataDrivenTestCase) -> None: options.python_version = (3, 10) elif testcase.file.endswith("python312.test"): options.python_version = (3, 12) + elif testcase.file.endswith("python313.test"): + options.python_version = (3, 13) else: options.python_version = defaults.PYTHON3_VERSION diff --git a/mypy/test/teststubgen.py b/mypy/test/teststubgen.py index e65a16c8f395..dffa1aa80c5d 100644 --- a/mypy/test/teststubgen.py +++ b/mypy/test/teststubgen.py @@ -38,6 +38,7 @@ from mypy.stubgenc import InspectionStubGenerator, infer_c_method_args from mypy.stubutil import ( ClassInfo, + FunctionContext, common_dir_prefix, infer_method_ret_type, remove_misplaced_type_comments, @@ -612,6 +613,16 @@ def test_common_dir_prefix_win(self) -> None: assert common_dir_prefix([r"foo\bar/x.pyi"]) == r"foo\bar" assert common_dir_prefix([r"foo/bar/x.pyi"]) == r"foo\bar" + def test_function_context_nested_classes(self) -> None: + ctx = FunctionContext( + module_name="spangle", + name="foo", + class_info=ClassInfo( + name="Nested", self_var="self", parent=ClassInfo(name="Parent", self_var="self") + ), + ) + assert ctx.fullname == "spangle.Parent.Nested.foo" + class StubgenHelpersSuite(unittest.TestCase): def test_is_blacklisted_path(self) -> None: @@ -976,7 +987,7 @@ def test(cls, arg0: str) -> None: def test_generate_c_type_classmethod_with_overloads(self) -> None: class TestClass: @classmethod - def test(self, arg0: str) -> None: + def test(cls, arg0: str) -> None: """ test(cls, arg0: str) test(cls, arg0: int) diff --git a/mypy/test/teststubinfo.py b/mypy/test/teststubinfo.py index eccee90244f3..518194d35e1d 100644 --- a/mypy/test/teststubinfo.py +++ b/mypy/test/teststubinfo.py @@ -2,11 +2,33 @@ import unittest -from mypy.stubinfo import is_legacy_bundled_package +from mypy.stubinfo import ( + is_module_from_legacy_bundled_package, + legacy_bundled_packages, + non_bundled_packages_flat, + stub_distribution_name, +) class TestStubInfo(unittest.TestCase): def test_is_legacy_bundled_packages(self) -> None: - assert not is_legacy_bundled_package("foobar_asdf") - assert is_legacy_bundled_package("pycurl") - assert is_legacy_bundled_package("dataclasses") + assert not is_module_from_legacy_bundled_package("foobar_asdf") + assert not is_module_from_legacy_bundled_package("PIL") + assert is_module_from_legacy_bundled_package("pycurl") + assert is_module_from_legacy_bundled_package("dataclasses") + + def test_stub_distribution_name(self) -> None: + assert stub_distribution_name("foobar_asdf") is None + assert stub_distribution_name("pycurl") == "types-pycurl" + assert stub_distribution_name("babel") == "types-babel" + assert stub_distribution_name("google.cloud.ndb") == "types-google-cloud-ndb" + assert stub_distribution_name("google.cloud.ndb.submodule") == "types-google-cloud-ndb" + assert stub_distribution_name("google.cloud.unknown") is None + assert stub_distribution_name("google.protobuf") == "types-protobuf" + assert stub_distribution_name("google.protobuf.submodule") == "types-protobuf" + assert stub_distribution_name("google") is None + + def test_period_in_top_level(self) -> None: + for packages in (non_bundled_packages_flat, legacy_bundled_packages): + for top_level_module in packages: + assert "." not in top_level_module diff --git a/mypy/test/teststubtest.py b/mypy/test/teststubtest.py index 70687b499651..fcbf07b4d371 100644 --- a/mypy/test/teststubtest.py +++ b/mypy/test/teststubtest.py @@ -1267,9 +1267,9 @@ def test_enum(self) -> Iterator[Case]: yield Case( stub=""" class X(enum.Enum): - a: int - b: str - c: str + a = ... + b = "asdf" + c = "oops" """, runtime=""" class X(enum.Enum): @@ -1282,8 +1282,8 @@ class X(enum.Enum): yield Case( stub=""" class Flags1(enum.Flag): - a: int - b: int + a = ... + b = 2 def foo(x: Flags1 = ...) -> None: ... """, runtime=""" @@ -1297,8 +1297,8 @@ def foo(x=Flags1.a|Flags1.b): pass yield Case( stub=""" class Flags2(enum.Flag): - a: int - b: int + a = ... + b = 2 def bar(x: Flags2 | None = None) -> None: ... """, runtime=""" @@ -1312,8 +1312,8 @@ def bar(x=Flags2.a|Flags2.b): pass yield Case( stub=""" class Flags3(enum.Flag): - a: int - b: int + a = ... + b = 2 def baz(x: Flags3 | None = ...) -> None: ... """, runtime=""" @@ -1346,8 +1346,8 @@ class WeirdEnum(enum.Enum): yield Case( stub=""" class Flags4(enum.Flag): - a: int - b: int + a = 1 + b = 2 def spam(x: Flags4 | None = None) -> None: ... """, runtime=""" @@ -1362,7 +1362,7 @@ def spam(x=Flags4(0)): pass stub=""" from typing_extensions import Final, Literal class BytesEnum(bytes, enum.Enum): - a: bytes + a = b'foo' FOO: Literal[BytesEnum.a] BAR: Final = BytesEnum.a BAZ: BytesEnum @@ -1403,7 +1403,7 @@ def test_all_at_runtime_not_stub(self) -> Iterator[Case]: runtime=""" __all__ = [] Z = 5""", - error=None, + error="__all__", ) @collect_cases @@ -1443,7 +1443,7 @@ def h(x: str): ... runtime="", error="h", ) - yield Case(stub="", runtime="__all__ = []", error=None) # dummy case + yield Case(stub="", runtime="__all__ = []", error="__all__") # dummy case yield Case(stub="", runtime="__all__ += ['y']\ny = 5", error="y") yield Case(stub="", runtime="__all__ += ['g']\ndef g(): pass", error="g") # Here we should only check that runtime has B, since the stub explicitly re-exports it @@ -1897,7 +1897,7 @@ def test_good_literal(self) -> Iterator[Case]: import enum class Color(enum.Enum): - RED: int + RED = ... NUM: Literal[1] CHAR: Literal['a'] diff --git a/mypy/test/testsubtypes.py b/mypy/test/testsubtypes.py index 480fe38a90a7..175074a2b140 100644 --- a/mypy/test/testsubtypes.py +++ b/mypy/test/testsubtypes.py @@ -4,7 +4,7 @@ from mypy.subtypes import is_subtype from mypy.test.helpers import Suite from mypy.test.typefixture import InterfaceTypeFixture, TypeFixture -from mypy.types import Instance, Type, UnpackType +from mypy.types import Instance, Type, UninhabitedType, UnpackType class SubtypingSuite(Suite): @@ -87,7 +87,7 @@ def test_basic_callable_subtyping(self) -> None: ) self.assert_strict_subtype( - self.fx.callable(self.fx.a, self.fx.nonet), self.fx.callable(self.fx.a, self.fx.a) + self.fx.callable(self.fx.a, UninhabitedType()), self.fx.callable(self.fx.a, self.fx.a) ) self.assert_unrelated( diff --git a/mypy/test/testtypes.py b/mypy/test/testtypes.py index 0218d33cc124..0380d1aa82d1 100644 --- a/mypy/test/testtypes.py +++ b/mypy/test/testtypes.py @@ -766,18 +766,19 @@ def test_type_vars(self) -> None: self.assert_join(self.fx.t, self.fx.s, self.fx.o) def test_none(self) -> None: - # Any type t joined with None results in t. - for t in [ - NoneType(), - self.fx.a, - self.fx.o, - UnboundType("x"), - self.fx.t, - self.tuple(), - self.callable(self.fx.a, self.fx.b), - self.fx.anyt, - ]: - self.assert_join(t, NoneType(), t) + with state.strict_optional_set(False): + # Any type t joined with None results in t. + for t in [ + NoneType(), + self.fx.a, + self.fx.o, + UnboundType("x"), + self.fx.t, + self.tuple(), + self.callable(self.fx.a, self.fx.b), + self.fx.anyt, + ]: + self.assert_join(t, NoneType(), t) def test_unbound_type(self) -> None: self.assert_join(UnboundType("x"), UnboundType("x"), self.fx.anyt) @@ -798,6 +799,9 @@ def test_unbound_type(self) -> None: def test_any_type(self) -> None: # Join against 'Any' type always results in 'Any'. + with state.strict_optional_set(False): + self.assert_join(NoneType(), self.fx.anyt, self.fx.anyt) + for t in [ self.fx.anyt, self.fx.a, @@ -834,7 +838,11 @@ def test_other_mixed_types(self) -> None: self.assert_join(t1, t2, self.fx.o) def test_simple_generics(self) -> None: - self.assert_join(self.fx.ga, self.fx.nonet, self.fx.ga) + with state.strict_optional_set(False): + self.assert_join(self.fx.ga, self.fx.nonet, self.fx.ga) + with state.strict_optional_set(True): + self.assert_join(self.fx.ga, self.fx.nonet, UnionType([self.fx.ga, NoneType()])) + self.assert_join(self.fx.ga, self.fx.anyt, self.fx.anyt) for t in [ @@ -1105,8 +1113,8 @@ def test_class_subtyping(self) -> None: self.assert_meet(self.fx.a, self.fx.o, self.fx.a) self.assert_meet(self.fx.a, self.fx.b, self.fx.b) self.assert_meet(self.fx.b, self.fx.o, self.fx.b) - self.assert_meet(self.fx.a, self.fx.d, NoneType()) - self.assert_meet(self.fx.b, self.fx.c, NoneType()) + self.assert_meet(self.fx.a, self.fx.d, UninhabitedType()) + self.assert_meet(self.fx.b, self.fx.c, UninhabitedType()) def test_tuples(self) -> None: self.assert_meet(self.tuple(), self.tuple(), self.tuple()) @@ -1114,13 +1122,15 @@ def test_tuples(self) -> None: self.assert_meet( self.tuple(self.fx.b, self.fx.c), self.tuple(self.fx.a, self.fx.d), - self.tuple(self.fx.b, NoneType()), + self.tuple(self.fx.b, UninhabitedType()), ) self.assert_meet( self.tuple(self.fx.a, self.fx.a), self.fx.std_tuple, self.tuple(self.fx.a, self.fx.a) ) - self.assert_meet(self.tuple(self.fx.a), self.tuple(self.fx.a, self.fx.a), NoneType()) + self.assert_meet( + self.tuple(self.fx.a), self.tuple(self.fx.a, self.fx.a), UninhabitedType() + ) def test_function_types(self) -> None: self.assert_meet( @@ -1143,7 +1153,7 @@ def test_function_types(self) -> None: def test_type_vars(self) -> None: self.assert_meet(self.fx.t, self.fx.t, self.fx.t) self.assert_meet(self.fx.s, self.fx.s, self.fx.s) - self.assert_meet(self.fx.t, self.fx.s, NoneType()) + self.assert_meet(self.fx.t, self.fx.s, UninhabitedType()) def test_none(self) -> None: self.assert_meet(NoneType(), NoneType(), NoneType()) @@ -1151,15 +1161,27 @@ def test_none(self) -> None: self.assert_meet(NoneType(), self.fx.anyt, NoneType()) # Any type t joined with None results in None, unless t is Any. - for t in [ - self.fx.a, - self.fx.o, - UnboundType("x"), - self.fx.t, - self.tuple(), - self.callable(self.fx.a, self.fx.b), - ]: - self.assert_meet(t, NoneType(), NoneType()) + with state.strict_optional_set(False): + for t in [ + self.fx.a, + self.fx.o, + UnboundType("x"), + self.fx.t, + self.tuple(), + self.callable(self.fx.a, self.fx.b), + ]: + self.assert_meet(t, NoneType(), NoneType()) + + with state.strict_optional_set(True): + self.assert_meet(self.fx.o, NoneType(), NoneType()) + for t in [ + self.fx.a, + UnboundType("x"), + self.fx.t, + self.tuple(), + self.callable(self.fx.a, self.fx.b), + ]: + self.assert_meet(t, NoneType(), UninhabitedType()) def test_unbound_type(self) -> None: self.assert_meet(UnboundType("x"), UnboundType("x"), self.fx.anyt) @@ -1197,28 +1219,28 @@ def test_simple_generics(self) -> None: self.assert_meet(self.fx.ga, self.fx.ga, self.fx.ga) self.assert_meet(self.fx.ga, self.fx.o, self.fx.ga) self.assert_meet(self.fx.ga, self.fx.gb, self.fx.gb) - self.assert_meet(self.fx.ga, self.fx.gd, self.fx.nonet) - self.assert_meet(self.fx.ga, self.fx.g2a, self.fx.nonet) + self.assert_meet(self.fx.ga, self.fx.gd, UninhabitedType()) + self.assert_meet(self.fx.ga, self.fx.g2a, UninhabitedType()) - self.assert_meet(self.fx.ga, self.fx.nonet, self.fx.nonet) + self.assert_meet(self.fx.ga, self.fx.nonet, UninhabitedType()) self.assert_meet(self.fx.ga, self.fx.anyt, self.fx.ga) for t in [self.fx.a, self.fx.t, self.tuple(), self.callable(self.fx.a, self.fx.b)]: - self.assert_meet(t, self.fx.ga, self.fx.nonet) + self.assert_meet(t, self.fx.ga, UninhabitedType()) def test_generics_with_multiple_args(self) -> None: self.assert_meet(self.fx.hab, self.fx.hab, self.fx.hab) self.assert_meet(self.fx.hab, self.fx.haa, self.fx.hab) - self.assert_meet(self.fx.hab, self.fx.had, self.fx.nonet) + self.assert_meet(self.fx.hab, self.fx.had, UninhabitedType()) self.assert_meet(self.fx.hab, self.fx.hbb, self.fx.hbb) def test_generics_with_inheritance(self) -> None: self.assert_meet(self.fx.gsab, self.fx.gb, self.fx.gsab) - self.assert_meet(self.fx.gsba, self.fx.gb, self.fx.nonet) + self.assert_meet(self.fx.gsba, self.fx.gb, UninhabitedType()) def test_generics_with_inheritance_and_shared_supertype(self) -> None: - self.assert_meet(self.fx.gsba, self.fx.gs2a, self.fx.nonet) - self.assert_meet(self.fx.gsab, self.fx.gs2a, self.fx.nonet) + self.assert_meet(self.fx.gsba, self.fx.gs2a, UninhabitedType()) + self.assert_meet(self.fx.gsab, self.fx.gs2a, UninhabitedType()) def test_generic_types_and_dynamic(self) -> None: self.assert_meet(self.fx.gdyn, self.fx.ga, self.fx.ga) @@ -1232,33 +1254,33 @@ def test_callables_with_dynamic(self) -> None: def test_meet_interface_types(self) -> None: self.assert_meet(self.fx.f, self.fx.f, self.fx.f) - self.assert_meet(self.fx.f, self.fx.f2, self.fx.nonet) + self.assert_meet(self.fx.f, self.fx.f2, UninhabitedType()) self.assert_meet(self.fx.f, self.fx.f3, self.fx.f3) def test_meet_interface_and_class_types(self) -> None: self.assert_meet(self.fx.o, self.fx.f, self.fx.f) - self.assert_meet(self.fx.a, self.fx.f, self.fx.nonet) + self.assert_meet(self.fx.a, self.fx.f, UninhabitedType()) self.assert_meet(self.fx.e, self.fx.f, self.fx.e) def test_meet_class_types_with_shared_interfaces(self) -> None: # These have nothing special with respect to meets, unlike joins. These # are for completeness only. - self.assert_meet(self.fx.e, self.fx.e2, self.fx.nonet) - self.assert_meet(self.fx.e2, self.fx.e3, self.fx.nonet) + self.assert_meet(self.fx.e, self.fx.e2, UninhabitedType()) + self.assert_meet(self.fx.e2, self.fx.e3, UninhabitedType()) def test_meet_with_generic_interfaces(self) -> None: fx = InterfaceTypeFixture() self.assert_meet(fx.gfa, fx.m1, fx.m1) self.assert_meet(fx.gfa, fx.gfa, fx.gfa) - self.assert_meet(fx.gfb, fx.m1, fx.nonet) + self.assert_meet(fx.gfb, fx.m1, UninhabitedType()) def test_type_type(self) -> None: self.assert_meet(self.fx.type_a, self.fx.type_b, self.fx.type_b) self.assert_meet(self.fx.type_b, self.fx.type_any, self.fx.type_b) self.assert_meet(self.fx.type_b, self.fx.type_type, self.fx.type_b) - self.assert_meet(self.fx.type_b, self.fx.type_c, self.fx.nonet) - self.assert_meet(self.fx.type_c, self.fx.type_d, self.fx.nonet) + self.assert_meet(self.fx.type_b, self.fx.type_c, self.fx.type_never) + self.assert_meet(self.fx.type_c, self.fx.type_d, self.fx.type_never) self.assert_meet(self.fx.type_type, self.fx.type_any, self.fx.type_any) self.assert_meet(self.fx.type_b, self.fx.anyt, self.fx.type_b) diff --git a/mypy/test/typefixture.py b/mypy/test/typefixture.py index 5a813f70117c..d6c904732b17 100644 --- a/mypy/test/typefixture.py +++ b/mypy/test/typefixture.py @@ -216,6 +216,7 @@ def make_type_var( self.type_d = TypeType.make_normalized(self.d) self.type_t = TypeType.make_normalized(self.t) self.type_any = TypeType.make_normalized(self.anyt) + self.type_never = TypeType.make_normalized(UninhabitedType()) self._add_bool_dunder(self.bool_type_info) self._add_bool_dunder(self.ai) diff --git a/mypy/traverser.py b/mypy/traverser.py index 6f162c9ec576..9c333c587f7c 100644 --- a/mypy/traverser.py +++ b/mypy/traverser.py @@ -958,9 +958,3 @@ def visit_assignment_stmt(self, stmt: AssignmentStmt) -> None: def visit_yield_from_expr(self, expr: YieldFromExpr) -> None: self.yield_from_expressions.append((expr, self.in_assignment)) - - -def all_yield_from_expressions(node: Node) -> list[tuple[YieldFromExpr, bool]]: - v = YieldFromCollector() - node.accept(v) - return v.yield_from_expressions diff --git a/mypy/treetransform.py b/mypy/treetransform.py index bb34d8de2884..aafa4e95d530 100644 --- a/mypy/treetransform.py +++ b/mypy/treetransform.py @@ -276,7 +276,7 @@ def visit_nonlocal_decl(self, node: NonlocalDecl) -> NonlocalDecl: return NonlocalDecl(node.names.copy()) def visit_block(self, node: Block) -> Block: - return Block(self.statements(node.body)) + return Block(self.statements(node.body), is_unreachable=node.is_unreachable) def visit_decorator(self, node: Decorator) -> Decorator: # Note that a Decorator must be transformed to a Decorator. diff --git a/mypy/typeanal.py b/mypy/typeanal.py index 0a6b7689136e..2f85e83bb3c3 100644 --- a/mypy/typeanal.py +++ b/mypy/typeanal.py @@ -34,6 +34,7 @@ ArgKind, Context, Decorator, + ImportFrom, MypyFile, ParamSpecExpr, PlaceholderNode, @@ -148,6 +149,7 @@ def analyze_type_alias( tvar_scope: TypeVarLikeScope, plugin: Plugin, options: Options, + cur_mod_node: MypyFile, is_typeshed_stub: bool, allow_placeholder: bool = False, in_dynamic_func: bool = False, @@ -167,6 +169,7 @@ def analyze_type_alias( tvar_scope, plugin, options, + cur_mod_node, is_typeshed_stub, defining_alias=True, allow_placeholder=allow_placeholder, @@ -177,7 +180,7 @@ def analyze_type_alias( ) analyzer.in_dynamic_func = in_dynamic_func analyzer.global_scope = global_scope - res = type.accept(analyzer) + res = analyzer.anal_type(type, nested=False) return res, analyzer.aliases_used @@ -213,6 +216,7 @@ def __init__( tvar_scope: TypeVarLikeScope, plugin: Plugin, options: Options, + cur_mod_node: MypyFile, is_typeshed_stub: bool, *, defining_alias: bool = False, @@ -266,6 +270,7 @@ def __init__( self.report_invalid_types = report_invalid_types self.plugin = plugin self.options = options + self.cur_mod_node = cur_mod_node self.is_typeshed_stub = is_typeshed_stub # Names of type aliases encountered while analysing a type will be collected here. self.aliases_used: set[str] = set() @@ -683,7 +688,9 @@ def try_analyze_special_unbound_type(self, t: UnboundType, fullname: str) -> Typ code=codes.VALID_TYPE, ) return AnyType(TypeOfAny.from_error) - return self.anal_type(t.args[0]) + return self.anal_type( + t.args[0], allow_typed_dict_special_forms=self.allow_typed_dict_special_forms + ) elif fullname in ("typing_extensions.Required", "typing.Required"): if not self.allow_typed_dict_special_forms: self.fail( @@ -771,6 +778,21 @@ def get_omitted_any(self, typ: Type, fullname: str | None = None) -> AnyType: disallow_any = not self.is_typeshed_stub and self.options.disallow_any_generics return get_omitted_any(disallow_any, self.fail, self.note, typ, self.options, fullname) + def check_and_warn_deprecated(self, info: TypeInfo, ctx: Context) -> None: + """Similar logic to `TypeChecker.check_deprecated` and `TypeChecker.warn_deprecated.""" + + if ( + (deprecated := info.deprecated) + and not self.is_typeshed_stub + and not (self.api.type and (self.api.type.fullname == info.fullname)) + ): + for imp in self.cur_mod_node.imports: + if isinstance(imp, ImportFrom) and any(info.name == n[0] for n in imp.names): + break + else: + warn = self.note if self.options.report_deprecated_as_note else self.fail + warn(deprecated, ctx, code=codes.DEPRECATED) + def analyze_type_with_type_info( self, info: TypeInfo, args: Sequence[Type], ctx: Context, empty_tuple_index: bool ) -> Type: @@ -779,6 +801,8 @@ def analyze_type_with_type_info( This handles simple cases like 'int', 'modname.UserClass[str]', etc. """ + self.check_and_warn_deprecated(info, ctx) + if len(args) > 0 and info.fullname == "builtins.tuple": fallback = Instance(info, [AnyType(TypeOfAny.special_form)], ctx.line) return TupleType(self.anal_array(args, allow_unpack=True), fallback, ctx.line) @@ -968,14 +992,12 @@ def analyze_unbound_type_without_type_info( message = 'Type variable "{}" is unbound' short = name.split(".")[-1] notes.append( - ( - '(Hint: Use "Generic[{}]" or "Protocol[{}]" base class' - ' to bind "{}" inside a class)' - ).format(short, short, short) + f'(Hint: Use "Generic[{short}]" or "Protocol[{short}]" base class' + f' to bind "{short}" inside a class)' ) notes.append( - '(Hint: Use "{}" in function signature to bind "{}"' - " inside a function)".format(short, short) + f'(Hint: Use "{short}" in function signature ' + f'to bind "{short}" inside a function)' ) else: message = 'Cannot interpret reference "{}" as a type' @@ -2255,7 +2277,8 @@ def set_any_tvars( env[tv.id] = arg t = TypeAliasType(node, args, newline, newcolumn) if not has_type_var_tuple_type: - fixed = expand_type(t, env) + with state.strict_optional_set(options.strict_optional): + fixed = expand_type(t, env) assert isinstance(fixed, TypeAliasType) t.args = fixed.args @@ -2278,15 +2301,6 @@ def set_any_tvars( return t -def flatten_tvars(lists: list[list[T]]) -> list[T]: - result: list[T] = [] - for lst in lists: - for item in lst: - if item not in result: - result.append(item) - return result - - class DivergingAliasDetector(TrivialSyntheticTypeTranslator): """See docstring of detect_diverging_alias() for details.""" diff --git a/mypy/typeops.py b/mypy/typeops.py index 0699cda53cfa..f190168a18d7 100644 --- a/mypy/typeops.py +++ b/mypy/typeops.py @@ -31,7 +31,6 @@ ) from mypy.state import state from mypy.types import ( - ENUM_REMOVED_PROPS, AnyType, CallableType, ExtraAttrs, @@ -651,8 +650,16 @@ def _remove_redundant_union_items(items: list[Type], keep_erased: bool) -> list[ def _get_type_method_ret_type(t: Type, *, name: str) -> Type | None: t = get_proper_type(t) + # For Enum literals the ret_type can change based on the Enum + # we need to check the type of the enum rather than the literal + if isinstance(t, LiteralType) and t.is_enum_literal(): + t = t.fallback + if isinstance(t, Instance): sym = t.type.get(name) + # Fallback to the metaclass for the lookup when necessary + if not sym and (m := t.type.metaclass_type): + sym = m.type.get(name) if sym: sym_type = get_proper_type(sym.type) if isinstance(sym_type, CallableType): @@ -959,24 +966,17 @@ class Status(Enum): try_expanding_sum_type_to_union(item, target_fullname) for item in typ.relevant_items() ] return make_simplified_union(items, contract_literals=False) - elif isinstance(typ, Instance) and typ.type.fullname == target_fullname: + + if isinstance(typ, Instance) and typ.type.fullname == target_fullname: + if typ.type.fullname == "builtins.bool": + items = [LiteralType(True, typ), LiteralType(False, typ)] + return make_simplified_union(items, contract_literals=False) + if typ.type.is_enum: - new_items = [] - for name, symbol in typ.type.names.items(): - if not isinstance(symbol.node, Var): - continue - # Skip these since Enum will remove it - if name in ENUM_REMOVED_PROPS: - continue - # Skip private attributes - if name.startswith("__"): - continue - new_items.append(LiteralType(name, typ)) - return make_simplified_union(new_items, contract_literals=False) - elif typ.type.fullname == "builtins.bool": - return make_simplified_union( - [LiteralType(True, typ), LiteralType(False, typ)], contract_literals=False - ) + items = [LiteralType(name, typ) for name in typ.type.enum_members] + if not items: + return typ + return make_simplified_union(items, contract_literals=False) return typ @@ -1002,7 +1002,7 @@ def try_contracting_literals_in_union(types: Sequence[Type]) -> list[ProperType] if fullname not in sum_types: sum_types[fullname] = ( ( - set(typ.fallback.get_enum_values()) + set(typ.fallback.type.enum_members) if typ.fallback.type.is_enum else {True, False} ), @@ -1035,7 +1035,7 @@ def coerce_to_literal(typ: Type) -> Type: if typ.last_known_value: return typ.last_known_value elif typ.type.is_enum: - enum_values = typ.get_enum_values() + enum_values = typ.type.enum_members if len(enum_values) == 1: return LiteralType(value=enum_values[0], fallback=typ) return original_type diff --git a/mypy/types.py b/mypy/types.py index dff7e2c0c829..e92ab0889991 100644 --- a/mypy/types.py +++ b/mypy/types.py @@ -150,10 +150,6 @@ OVERLOAD_NAMES: Final = ("typing.overload", "typing_extensions.overload") -# Attributes that can optionally be defined in the body of a subclass of -# enum.Enum but are removed from the class __dict__ by EnumMeta. -ENUM_REMOVED_PROPS: Final = ("_ignore_", "_order_", "__order__") - NEVER_NAMES: Final = ( "typing.NoReturn", "typing_extensions.NoReturn", @@ -1493,9 +1489,11 @@ def serialize(self) -> JsonDict | str: type_ref = self.type.fullname if not self.args and not self.last_known_value: return type_ref - data: JsonDict = {".class": "Instance"} - data["type_ref"] = type_ref - data["args"] = [arg.serialize() for arg in self.args] + data: JsonDict = { + ".class": "Instance", + "type_ref": type_ref, + "args": [arg.serialize() for arg in self.args], + } if self.last_known_value is not None: data["last_known_value"] = self.last_known_value.serialize() data["extra_attrs"] = self.extra_attrs.serialize() if self.extra_attrs else None @@ -1557,16 +1555,10 @@ def is_singleton_type(self) -> bool: # Also make this return True if the type corresponds to NotImplemented? return ( self.type.is_enum - and len(self.get_enum_values()) == 1 + and len(self.type.enum_members) == 1 or self.type.fullname in {"builtins.ellipsis", "types.EllipsisType"} ) - def get_enum_values(self) -> list[str]: - """Return the list of values for an Enum.""" - return [ - name for name, sym in self.type.names.items() if isinstance(sym.node, mypy.nodes.Var) - ] - class FunctionLike(ProperType): """Abstract base class for function types.""" @@ -1825,8 +1817,8 @@ class CallableType(FunctionLike): "implicit", # Was this type implicitly generated instead of explicitly # specified by the user? "special_sig", # Non-None for signatures that require special handling - # (currently only value is 'dict' for a signature similar to - # 'dict') + # (currently only values are 'dict' for a signature similar to + # 'dict' and 'partial' for a `functools.partial` evaluation) "from_type_type", # Was this callable generated by analyzing Type[...] # instantiation? "bound_args", # Bound type args, mostly unused but may be useful for @@ -2500,6 +2492,9 @@ def slice( if fallback is None: fallback = self.partial_fallback + if stride == 0: + return None + if any(isinstance(t, UnpackType) for t in self.items): total = len(self.items) unpack_index = find_unpack_in_list(self.items) @@ -2823,10 +2818,28 @@ def __init__( self.fallback = fallback self._hash = -1 # Cached hash value + # NOTE: Enum types are always truthy by default, but this can be changed + # in subclasses, so we need to get the truthyness from the Enum + # type rather than base it on the value (which is a non-empty + # string for enums, so always truthy) + # TODO: We should consider moving this branch to the `can_be_true` + # `can_be_false` properties instead, so the truthyness only + # needs to be determined once per set of Enum literals. + # However, the same can be said for `TypeAliasType` in some + # cases and we only set the default based on the type it is + # aliasing. So if we decide to change this, we may want to + # change that as well. perf_compare output was inconclusive + # but slightly favored this version, probably because we have + # almost no test cases where we would redundantly compute + # `can_be_false`/`can_be_true`. def can_be_false_default(self) -> bool: + if self.fallback.type.is_enum: + return self.fallback.can_be_false return not self.value def can_be_true_default(self) -> bool: + if self.fallback.type.is_enum: + return self.fallback.can_be_true return bool(self.value) def accept(self, visitor: TypeVisitor[T]) -> T: @@ -3599,6 +3612,8 @@ def visit_type_alias_type(self, typ: TypeAliasType) -> None: class HasTypeVars(BoolTypeQuery): + """Visitor for querying whether a type has a type variable component.""" + def __init__(self) -> None: super().__init__(ANY_STRATEGY) self.skip_alias_target = True diff --git a/mypy/typeshed/stdlib/VERSIONS b/mypy/typeshed/stdlib/VERSIONS index dfed62f694fc..7ff14c55d3a8 100644 --- a/mypy/typeshed/stdlib/VERSIONS +++ b/mypy/typeshed/stdlib/VERSIONS @@ -20,37 +20,54 @@ __future__: 3.0- __main__: 3.0- _ast: 3.0- +_asyncio: 3.0- _bisect: 3.0- +_blake2: 3.6- _bootlocale: 3.4-3.9 +_bz2: 3.3- _codecs: 3.0- _collections_abc: 3.3- _compat_pickle: 3.1- _compression: 3.5- +_contextvars: 3.7- _csv: 3.0- _ctypes: 3.0- _curses: 3.0- +_curses_panel: 3.0- +_dbm: 3.0- _decimal: 3.3- _dummy_thread: 3.0-3.8 _dummy_threading: 3.0-3.8 +_frozen_importlib: 3.0- +_frozen_importlib_external: 3.5- +_gdbm: 3.0- +_hashlib: 3.0- _heapq: 3.0- _imp: 3.0- _interpchannels: 3.13- _interpqueues: 3.13- _interpreters: 3.13- +_io: 3.0- _json: 3.0- _locale: 3.0- _lsprof: 3.0- +_lzma: 3.3- _markupbase: 3.0- _msi: 3.0-3.12 +_multibytecodec: 3.0- _operator: 3.4- _osx_support: 3.0- _posixsubprocess: 3.2- _py_abc: 3.7- _pydecimal: 3.5- +_queue: 3.7- _random: 3.0- _sitebuiltins: 3.4- _socket: 3.0- # present in 3.0 at runtime, but not in typeshed +_sqlite3: 3.0- +_ssl: 3.0- _stat: 3.4- +_struct: 3.0- _thread: 3.0- _threading_local: 3.0- _tkinter: 3.0- @@ -125,6 +142,12 @@ doctest: 3.0- dummy_threading: 3.0-3.8 email: 3.0- encodings: 3.0- +encodings.cp1125: 3.4- +encodings.cp273: 3.4- +encodings.cp858: 3.2- +encodings.koi8_t: 3.5- +encodings.kz1048: 3.5- +encodings.mac_centeuro: 3.0-3.8 ensurepip: 3.0- enum: 3.4- errno: 3.0- @@ -156,6 +179,8 @@ imghdr: 3.0-3.12 imp: 3.0-3.11 importlib: 3.0- importlib._abc: 3.10- +importlib._bootstrap: 3.0- +importlib._bootstrap_external: 3.5- importlib.metadata: 3.8- importlib.metadata._meta: 3.10- importlib.metadata.diagnose: 3.13- diff --git a/mypy/typeshed/stdlib/_ast.pyi b/mypy/typeshed/stdlib/_ast.pyi index 1dbceac428c1..8dc1bcbea32c 100644 --- a/mypy/typeshed/stdlib/_ast.pyi +++ b/mypy/typeshed/stdlib/_ast.pyi @@ -1,1676 +1,149 @@ import sys -import typing_extensions -from typing import Any, ClassVar, Generic, Literal, TypedDict, overload -from typing_extensions import Self, Unpack +from ast import ( + AST as AST, + Add as Add, + And as And, + AnnAssign as AnnAssign, + Assert as Assert, + Assign as Assign, + AsyncFor as AsyncFor, + AsyncFunctionDef as AsyncFunctionDef, + AsyncWith as AsyncWith, + Attribute as Attribute, + AugAssign as AugAssign, + Await as Await, + BinOp as BinOp, + BitAnd as BitAnd, + BitOr as BitOr, + BitXor as BitXor, + BoolOp as BoolOp, + Break as Break, + Call as Call, + ClassDef as ClassDef, + Compare as Compare, + Constant as Constant, + Continue as Continue, + Del as Del, + Delete as Delete, + Dict as Dict, + DictComp as DictComp, + Div as Div, + Eq as Eq, + ExceptHandler as ExceptHandler, + Expr as Expr, + Expression as Expression, + FloorDiv as FloorDiv, + For as For, + FormattedValue as FormattedValue, + FunctionDef as FunctionDef, + FunctionType as FunctionType, + GeneratorExp as GeneratorExp, + Global as Global, + Gt as Gt, + GtE as GtE, + If as If, + IfExp as IfExp, + Import as Import, + ImportFrom as ImportFrom, + In as In, + Interactive as Interactive, + Invert as Invert, + Is as Is, + IsNot as IsNot, + JoinedStr as JoinedStr, + Lambda as Lambda, + List as List, + ListComp as ListComp, + Load as Load, + LShift as LShift, + Lt as Lt, + LtE as LtE, + MatMult as MatMult, + Mod as Mod, + Module as Module, + Mult as Mult, + Name as Name, + NamedExpr as NamedExpr, + Nonlocal as Nonlocal, + Not as Not, + NotEq as NotEq, + NotIn as NotIn, + Or as Or, + Pass as Pass, + Pow as Pow, + Raise as Raise, + Return as Return, + RShift as RShift, + Set as Set, + SetComp as SetComp, + Slice as Slice, + Starred as Starred, + Store as Store, + Sub as Sub, + Subscript as Subscript, + Try as Try, + Tuple as Tuple, + TypeIgnore as TypeIgnore, + UAdd as UAdd, + UnaryOp as UnaryOp, + USub as USub, + While as While, + With as With, + Yield as Yield, + YieldFrom as YieldFrom, + alias as alias, + arg as arg, + arguments as arguments, + boolop as boolop, + cmpop as cmpop, + comprehension as comprehension, + excepthandler as excepthandler, + expr as expr, + expr_context as expr_context, + keyword as keyword, + mod as mod, + operator as operator, + stmt as stmt, + type_ignore as type_ignore, + unaryop as unaryop, + withitem as withitem, +) +from typing import Literal -PyCF_ONLY_AST: Literal[1024] -PyCF_TYPE_COMMENTS: Literal[4096] -PyCF_ALLOW_TOP_LEVEL_AWAIT: Literal[8192] - -if sys.version_info >= (3, 13): - PyCF_OPTIMIZED_AST: Literal[33792] - -# Used for node end positions in constructor keyword arguments -_EndPositionT = typing_extensions.TypeVar("_EndPositionT", int, int | None, default=int | None) - -# Alias used for fields that must always be valid identifiers -# A string `x` counts as a valid identifier if both the following are True -# (1) `x.isidentifier()` evaluates to `True` -# (2) `keyword.iskeyword(x)` evaluates to `False` -_Identifier: typing_extensions.TypeAlias = str - -# Corresponds to the names in the `_attributes` class variable which is non-empty in certain AST nodes -class _Attributes(TypedDict, Generic[_EndPositionT], total=False): - lineno: int - col_offset: int - end_lineno: _EndPositionT - end_col_offset: _EndPositionT - -class AST: - if sys.version_info >= (3, 10): - __match_args__ = () - _attributes: ClassVar[tuple[str, ...]] - _fields: ClassVar[tuple[str, ...]] - if sys.version_info >= (3, 13): - _field_types: ClassVar[dict[str, Any]] - - if sys.version_info >= (3, 14): - def __replace__(self) -> Self: ... - -class mod(AST): ... -class type_ignore(AST): ... - -class TypeIgnore(type_ignore): - if sys.version_info >= (3, 10): - __match_args__ = ("lineno", "tag") - lineno: int - tag: str - def __init__(self, lineno: int, tag: str) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, lineno: int = ..., tag: str = ...) -> Self: ... - -class FunctionType(mod): - if sys.version_info >= (3, 10): - __match_args__ = ("argtypes", "returns") - argtypes: list[expr] - returns: expr - if sys.version_info >= (3, 13): - @overload - def __init__(self, argtypes: list[expr], returns: expr) -> None: ... - @overload - def __init__(self, argtypes: list[expr] = ..., *, returns: expr) -> None: ... - else: - def __init__(self, argtypes: list[expr], returns: expr) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, argtypes: list[expr] = ..., returns: expr = ...) -> Self: ... - -class Module(mod): - if sys.version_info >= (3, 10): - __match_args__ = ("body", "type_ignores") - body: list[stmt] - type_ignores: list[TypeIgnore] - if sys.version_info >= (3, 13): - def __init__(self, body: list[stmt] = ..., type_ignores: list[TypeIgnore] = ...) -> None: ... - else: - def __init__(self, body: list[stmt], type_ignores: list[TypeIgnore]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, body: list[stmt] = ..., type_ignores: list[TypeIgnore] = ...) -> Self: ... - -class Interactive(mod): - if sys.version_info >= (3, 10): - __match_args__ = ("body",) - body: list[stmt] - if sys.version_info >= (3, 13): - def __init__(self, body: list[stmt] = ...) -> None: ... - else: - def __init__(self, body: list[stmt]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, body: list[stmt] = ...) -> Self: ... - -class Expression(mod): - if sys.version_info >= (3, 10): - __match_args__ = ("body",) - body: expr - def __init__(self, body: expr) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, body: expr = ...) -> Self: ... - -class stmt(AST): - lineno: int - col_offset: int - end_lineno: int | None - end_col_offset: int | None - def __init__(self, **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, **kwargs: Unpack[_Attributes]) -> Self: ... - -class FunctionDef(stmt): - if sys.version_info >= (3, 12): - __match_args__ = ("name", "args", "body", "decorator_list", "returns", "type_comment", "type_params") - elif sys.version_info >= (3, 10): - __match_args__ = ("name", "args", "body", "decorator_list", "returns", "type_comment") - name: _Identifier - args: arguments - body: list[stmt] - decorator_list: list[expr] - returns: expr | None - type_comment: str | None - if sys.version_info >= (3, 12): - type_params: list[type_param] - if sys.version_info >= (3, 13): - def __init__( - self, - name: _Identifier, - args: arguments, - body: list[stmt] = ..., - decorator_list: list[expr] = ..., - returns: expr | None = None, - type_comment: str | None = None, - type_params: list[type_param] = ..., - **kwargs: Unpack[_Attributes], - ) -> None: ... - elif sys.version_info >= (3, 12): - @overload - def __init__( - self, - name: _Identifier, - args: arguments, - body: list[stmt], - decorator_list: list[expr], - returns: expr | None, - type_comment: str | None, - type_params: list[type_param], - **kwargs: Unpack[_Attributes], - ) -> None: ... - @overload - def __init__( - self, - name: _Identifier, - args: arguments, - body: list[stmt], - decorator_list: list[expr], - returns: expr | None = None, - type_comment: str | None = None, - *, - type_params: list[type_param], - **kwargs: Unpack[_Attributes], - ) -> None: ... - else: - def __init__( - self, - name: _Identifier, - args: arguments, - body: list[stmt], - decorator_list: list[expr], - returns: expr | None = None, - type_comment: str | None = None, - **kwargs: Unpack[_Attributes], - ) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, - *, - name: _Identifier = ..., - args: arguments = ..., - body: list[stmt] = ..., - decorator_list: list[expr] = ..., - returns: expr | None = ..., - type_comment: str | None = ..., - type_params: list[type_param] = ..., - ) -> Self: ... - -class AsyncFunctionDef(stmt): - if sys.version_info >= (3, 12): - __match_args__ = ("name", "args", "body", "decorator_list", "returns", "type_comment", "type_params") - elif sys.version_info >= (3, 10): - __match_args__ = ("name", "args", "body", "decorator_list", "returns", "type_comment") - name: _Identifier - args: arguments - body: list[stmt] - decorator_list: list[expr] - returns: expr | None - type_comment: str | None - if sys.version_info >= (3, 12): - type_params: list[type_param] - if sys.version_info >= (3, 13): - def __init__( - self, - name: _Identifier, - args: arguments, - body: list[stmt] = ..., - decorator_list: list[expr] = ..., - returns: expr | None = None, - type_comment: str | None = None, - type_params: list[type_param] = ..., - **kwargs: Unpack[_Attributes], - ) -> None: ... - elif sys.version_info >= (3, 12): - @overload - def __init__( - self, - name: _Identifier, - args: arguments, - body: list[stmt], - decorator_list: list[expr], - returns: expr | None, - type_comment: str | None, - type_params: list[type_param], - **kwargs: Unpack[_Attributes], - ) -> None: ... - @overload - def __init__( - self, - name: _Identifier, - args: arguments, - body: list[stmt], - decorator_list: list[expr], - returns: expr | None = None, - type_comment: str | None = None, - *, - type_params: list[type_param], - **kwargs: Unpack[_Attributes], - ) -> None: ... - else: - def __init__( - self, - name: _Identifier, - args: arguments, - body: list[stmt], - decorator_list: list[expr], - returns: expr | None = None, - type_comment: str | None = None, - **kwargs: Unpack[_Attributes], - ) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, - *, - name: _Identifier = ..., - args: arguments = ..., - body: list[stmt], - decorator_list: list[expr], - returns: expr | None, - type_comment: str | None, - type_params: list[type_param], - ) -> Self: ... - -class ClassDef(stmt): - if sys.version_info >= (3, 12): - __match_args__ = ("name", "bases", "keywords", "body", "decorator_list", "type_params") - elif sys.version_info >= (3, 10): - __match_args__ = ("name", "bases", "keywords", "body", "decorator_list") - name: _Identifier - bases: list[expr] - keywords: list[keyword] - body: list[stmt] - decorator_list: list[expr] - if sys.version_info >= (3, 12): - type_params: list[type_param] - if sys.version_info >= (3, 13): - def __init__( - self, - name: _Identifier, - bases: list[expr] = ..., - keywords: list[keyword] = ..., - body: list[stmt] = ..., - decorator_list: list[expr] = ..., - type_params: list[type_param] = ..., - **kwargs: Unpack[_Attributes], - ) -> None: ... - elif sys.version_info >= (3, 12): - def __init__( - self, - name: _Identifier, - bases: list[expr], - keywords: list[keyword], - body: list[stmt], - decorator_list: list[expr], - type_params: list[type_param], - **kwargs: Unpack[_Attributes], - ) -> None: ... - else: - def __init__( - self, - name: _Identifier, - bases: list[expr], - keywords: list[keyword], - body: list[stmt], - decorator_list: list[expr], - **kwargs: Unpack[_Attributes], - ) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, - *, - name: _Identifier, - bases: list[expr], - keywords: list[keyword], - body: list[stmt], - decorator_list: list[expr], - type_params: list[type_param], - **kwargs: Unpack[_Attributes], - ) -> Self: ... - -class Return(stmt): - if sys.version_info >= (3, 10): - __match_args__ = ("value",) - value: expr | None - def __init__(self, value: expr | None = None, **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, value: expr | None = ..., **kwargs: Unpack[_Attributes]) -> Self: ... - -class Delete(stmt): - if sys.version_info >= (3, 10): - __match_args__ = ("targets",) - targets: list[expr] - if sys.version_info >= (3, 13): - def __init__(self, targets: list[expr] = ..., **kwargs: Unpack[_Attributes]) -> None: ... - else: - def __init__(self, targets: list[expr], **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, targets: list[expr] = ..., **kwargs: Unpack[_Attributes]) -> Self: ... - -class Assign(stmt): - if sys.version_info >= (3, 10): - __match_args__ = ("targets", "value", "type_comment") - targets: list[expr] - value: expr - type_comment: str | None - if sys.version_info >= (3, 13): - @overload - def __init__( - self, targets: list[expr], value: expr, type_comment: str | None = None, **kwargs: Unpack[_Attributes] - ) -> None: ... - @overload - def __init__( - self, targets: list[expr] = ..., *, value: expr, type_comment: str | None = None, **kwargs: Unpack[_Attributes] - ) -> None: ... - else: - def __init__( - self, targets: list[expr], value: expr, type_comment: str | None = None, **kwargs: Unpack[_Attributes] - ) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, *, targets: list[expr] = ..., value: expr = ..., type_comment: str | None = ..., **kwargs: Unpack[_Attributes] - ) -> Self: ... - -class AugAssign(stmt): - if sys.version_info >= (3, 10): - __match_args__ = ("target", "op", "value") - target: Name | Attribute | Subscript - op: operator - value: expr - def __init__( - self, target: Name | Attribute | Subscript, op: operator, value: expr, **kwargs: Unpack[_Attributes] - ) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, - *, - target: Name | Attribute | Subscript = ..., - op: operator = ..., - value: expr = ..., - **kwargs: Unpack[_Attributes], - ) -> Self: ... - -class AnnAssign(stmt): - if sys.version_info >= (3, 10): - __match_args__ = ("target", "annotation", "value", "simple") - target: Name | Attribute | Subscript - annotation: expr - value: expr | None - simple: int - @overload - def __init__( - self, - target: Name | Attribute | Subscript, - annotation: expr, - value: expr | None, - simple: int, - **kwargs: Unpack[_Attributes], - ) -> None: ... - @overload - def __init__( - self, - target: Name | Attribute | Subscript, - annotation: expr, - value: expr | None = None, - *, - simple: int, - **kwargs: Unpack[_Attributes], - ) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, - *, - target: Name | Attribute | Subscript = ..., - annotation: expr = ..., - value: expr | None = ..., - simple: int = ..., - **kwargs: Unpack[_Attributes], - ) -> Self: ... - -class For(stmt): - if sys.version_info >= (3, 10): - __match_args__ = ("target", "iter", "body", "orelse", "type_comment") - target: expr - iter: expr - body: list[stmt] - orelse: list[stmt] - type_comment: str | None - if sys.version_info >= (3, 13): - def __init__( - self, - target: expr, - iter: expr, - body: list[stmt] = ..., - orelse: list[stmt] = ..., - type_comment: str | None = None, - **kwargs: Unpack[_Attributes], - ) -> None: ... - else: - def __init__( - self, - target: expr, - iter: expr, - body: list[stmt], - orelse: list[stmt], - type_comment: str | None = None, - **kwargs: Unpack[_Attributes], - ) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, - *, - target: expr = ..., - iter: expr = ..., - body: list[stmt] = ..., - orelse: list[stmt] = ..., - type_comment: str | None = ..., - **kwargs: Unpack[_Attributes], - ) -> Self: ... - -class AsyncFor(stmt): - if sys.version_info >= (3, 10): - __match_args__ = ("target", "iter", "body", "orelse", "type_comment") - target: expr - iter: expr - body: list[stmt] - orelse: list[stmt] - type_comment: str | None - if sys.version_info >= (3, 13): - def __init__( - self, - target: expr, - iter: expr, - body: list[stmt] = ..., - orelse: list[stmt] = ..., - type_comment: str | None = None, - **kwargs: Unpack[_Attributes], - ) -> None: ... - else: - def __init__( - self, - target: expr, - iter: expr, - body: list[stmt], - orelse: list[stmt], - type_comment: str | None = None, - **kwargs: Unpack[_Attributes], - ) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, - *, - target: expr = ..., - iter: expr = ..., - body: list[stmt] = ..., - orelse: list[stmt] = ..., - type_comment: str | None = ..., - **kwargs: Unpack[_Attributes], - ) -> Self: ... - -class While(stmt): - if sys.version_info >= (3, 10): - __match_args__ = ("test", "body", "orelse") - test: expr - body: list[stmt] - orelse: list[stmt] - if sys.version_info >= (3, 13): - def __init__( - self, test: expr, body: list[stmt] = ..., orelse: list[stmt] = ..., **kwargs: Unpack[_Attributes] - ) -> None: ... - else: - def __init__(self, test: expr, body: list[stmt], orelse: list[stmt], **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, test: expr, body: list[stmt], orelse: list[stmt], **kwargs: Unpack[_Attributes]) -> Self: ... - -class If(stmt): - if sys.version_info >= (3, 10): - __match_args__ = ("test", "body", "orelse") - test: expr - body: list[stmt] - orelse: list[stmt] - if sys.version_info >= (3, 13): - def __init__( - self, test: expr, body: list[stmt] = ..., orelse: list[stmt] = ..., **kwargs: Unpack[_Attributes] - ) -> None: ... - else: - def __init__(self, test: expr, body: list[stmt], orelse: list[stmt], **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, *, test: expr = ..., body: list[stmt] = ..., orelse: list[stmt] = ..., **kwargs: Unpack[_Attributes] - ) -> Self: ... - -class With(stmt): - if sys.version_info >= (3, 10): - __match_args__ = ("items", "body", "type_comment") - items: list[withitem] - body: list[stmt] - type_comment: str | None - if sys.version_info >= (3, 13): - def __init__( - self, - items: list[withitem] = ..., - body: list[stmt] = ..., - type_comment: str | None = None, - **kwargs: Unpack[_Attributes], - ) -> None: ... - else: - def __init__( - self, items: list[withitem], body: list[stmt], type_comment: str | None = None, **kwargs: Unpack[_Attributes] - ) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, - *, - items: list[withitem] = ..., - body: list[stmt] = ..., - type_comment: str | None = ..., - **kwargs: Unpack[_Attributes], - ) -> Self: ... - -class AsyncWith(stmt): - if sys.version_info >= (3, 10): - __match_args__ = ("items", "body", "type_comment") - items: list[withitem] - body: list[stmt] - type_comment: str | None - if sys.version_info >= (3, 13): - def __init__( - self, - items: list[withitem] = ..., - body: list[stmt] = ..., - type_comment: str | None = None, - **kwargs: Unpack[_Attributes], - ) -> None: ... - else: - def __init__( - self, items: list[withitem], body: list[stmt], type_comment: str | None = None, **kwargs: Unpack[_Attributes] - ) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, - *, - items: list[withitem] = ..., - body: list[stmt] = ..., - type_comment: str | None = ..., - **kwargs: Unpack[_Attributes], - ) -> Self: ... - -class Raise(stmt): - if sys.version_info >= (3, 10): - __match_args__ = ("exc", "cause") - exc: expr | None - cause: expr | None - def __init__(self, exc: expr | None = None, cause: expr | None = None, **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, exc: expr | None = ..., cause: expr | None = ..., **kwargs: Unpack[_Attributes]) -> Self: ... - -class Try(stmt): - if sys.version_info >= (3, 10): - __match_args__ = ("body", "handlers", "orelse", "finalbody") - body: list[stmt] - handlers: list[ExceptHandler] - orelse: list[stmt] - finalbody: list[stmt] - if sys.version_info >= (3, 13): - def __init__( - self, - body: list[stmt] = ..., - handlers: list[ExceptHandler] = ..., - orelse: list[stmt] = ..., - finalbody: list[stmt] = ..., - **kwargs: Unpack[_Attributes], - ) -> None: ... - else: - def __init__( - self, - body: list[stmt], - handlers: list[ExceptHandler], - orelse: list[stmt], - finalbody: list[stmt], - **kwargs: Unpack[_Attributes], - ) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, - *, - body: list[stmt] = ..., - handlers: list[ExceptHandler] = ..., - orelse: list[stmt] = ..., - finalbody: list[stmt] = ..., - **kwargs: Unpack[_Attributes], - ) -> Self: ... +if sys.version_info >= (3, 12): + from ast import ParamSpec as ParamSpec, TypeVar as TypeVar, TypeVarTuple as TypeVarTuple, type_param as type_param if sys.version_info >= (3, 11): - class TryStar(stmt): - __match_args__ = ("body", "handlers", "orelse", "finalbody") - body: list[stmt] - handlers: list[ExceptHandler] - orelse: list[stmt] - finalbody: list[stmt] - if sys.version_info >= (3, 13): - def __init__( - self, - body: list[stmt] = ..., - handlers: list[ExceptHandler] = ..., - orelse: list[stmt] = ..., - finalbody: list[stmt] = ..., - **kwargs: Unpack[_Attributes], - ) -> None: ... - else: - def __init__( - self, - body: list[stmt], - handlers: list[ExceptHandler], - orelse: list[stmt], - finalbody: list[stmt], - **kwargs: Unpack[_Attributes], - ) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, - *, - body: list[stmt] = ..., - handlers: list[ExceptHandler] = ..., - orelse: list[stmt] = ..., - finalbody: list[stmt] = ..., - **kwargs: Unpack[_Attributes], - ) -> Self: ... - -class Assert(stmt): - if sys.version_info >= (3, 10): - __match_args__ = ("test", "msg") - test: expr - msg: expr | None - def __init__(self, test: expr, msg: expr | None = None, **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, test: expr, msg: expr | None, **kwargs: Unpack[_Attributes]) -> Self: ... - -class Import(stmt): - if sys.version_info >= (3, 10): - __match_args__ = ("names",) - names: list[alias] - if sys.version_info >= (3, 13): - def __init__(self, names: list[alias] = ..., **kwargs: Unpack[_Attributes]) -> None: ... - else: - def __init__(self, names: list[alias], **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, names: list[alias] = ..., **kwargs: Unpack[_Attributes]) -> Self: ... - -class ImportFrom(stmt): - if sys.version_info >= (3, 10): - __match_args__ = ("module", "names", "level") - module: str | None - names: list[alias] - level: int - if sys.version_info >= (3, 13): - @overload - def __init__(self, module: str | None, names: list[alias], level: int, **kwargs: Unpack[_Attributes]) -> None: ... - @overload - def __init__( - self, module: str | None = None, names: list[alias] = ..., *, level: int, **kwargs: Unpack[_Attributes] - ) -> None: ... - else: - @overload - def __init__(self, module: str | None, names: list[alias], level: int, **kwargs: Unpack[_Attributes]) -> None: ... - @overload - def __init__( - self, module: str | None = None, *, names: list[alias], level: int, **kwargs: Unpack[_Attributes] - ) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, *, module: str | None = ..., names: list[alias] = ..., level: int = ..., **kwargs: Unpack[_Attributes] - ) -> Self: ... - -class Global(stmt): - if sys.version_info >= (3, 10): - __match_args__ = ("names",) - names: list[_Identifier] - if sys.version_info >= (3, 13): - def __init__(self, names: list[_Identifier] = ..., **kwargs: Unpack[_Attributes]) -> None: ... - else: - def __init__(self, names: list[_Identifier], **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, names: list[_Identifier], **kwargs: Unpack[_Attributes]) -> Self: ... - -class Nonlocal(stmt): - if sys.version_info >= (3, 10): - __match_args__ = ("names",) - names: list[_Identifier] - if sys.version_info >= (3, 13): - def __init__(self, names: list[_Identifier] = ..., **kwargs: Unpack[_Attributes]) -> None: ... - else: - def __init__(self, names: list[_Identifier], **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, names: list[_Identifier] = ..., **kwargs: Unpack[_Attributes]) -> Self: ... - -class Expr(stmt): - if sys.version_info >= (3, 10): - __match_args__ = ("value",) - value: expr - def __init__(self, value: expr, **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, value: expr = ..., **kwargs: Unpack[_Attributes]) -> Self: ... - -class Pass(stmt): ... -class Break(stmt): ... -class Continue(stmt): ... - -class expr(AST): - lineno: int - col_offset: int - end_lineno: int | None - end_col_offset: int | None - def __init__(self, **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, **kwargs: Unpack[_Attributes]) -> Self: ... - -class BoolOp(expr): - if sys.version_info >= (3, 10): - __match_args__ = ("op", "values") - op: boolop - values: list[expr] - if sys.version_info >= (3, 13): - def __init__(self, op: boolop, values: list[expr] = ..., **kwargs: Unpack[_Attributes]) -> None: ... - else: - def __init__(self, op: boolop, values: list[expr], **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, op: boolop = ..., values: list[expr] = ..., **kwargs: Unpack[_Attributes]) -> Self: ... - -class BinOp(expr): - if sys.version_info >= (3, 10): - __match_args__ = ("left", "op", "right") - left: expr - op: operator - right: expr - def __init__(self, left: expr, op: operator, right: expr, **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, *, left: expr = ..., op: operator = ..., right: expr = ..., **kwargs: Unpack[_Attributes] - ) -> Self: ... - -class UnaryOp(expr): - if sys.version_info >= (3, 10): - __match_args__ = ("op", "operand") - op: unaryop - operand: expr - def __init__(self, op: unaryop, operand: expr, **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, op: unaryop = ..., operand: expr = ..., **kwargs: Unpack[_Attributes]) -> Self: ... - -class Lambda(expr): - if sys.version_info >= (3, 10): - __match_args__ = ("args", "body") - args: arguments - body: expr - def __init__(self, args: arguments, body: expr, **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, args: arguments = ..., body: expr = ..., **kwargs: Unpack[_Attributes]) -> Self: ... - -class IfExp(expr): - if sys.version_info >= (3, 10): - __match_args__ = ("test", "body", "orelse") - test: expr - body: expr - orelse: expr - def __init__(self, test: expr, body: expr, orelse: expr, **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, *, test: expr = ..., body: expr = ..., orelse: expr = ..., **kwargs: Unpack[_Attributes] - ) -> Self: ... - -class Dict(expr): - if sys.version_info >= (3, 10): - __match_args__ = ("keys", "values") - keys: list[expr | None] - values: list[expr] - if sys.version_info >= (3, 13): - def __init__(self, keys: list[expr | None] = ..., values: list[expr] = ..., **kwargs: Unpack[_Attributes]) -> None: ... - else: - def __init__(self, keys: list[expr | None], values: list[expr], **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, *, keys: list[expr | None] = ..., values: list[expr] = ..., **kwargs: Unpack[_Attributes] - ) -> Self: ... - -class Set(expr): - if sys.version_info >= (3, 10): - __match_args__ = ("elts",) - elts: list[expr] - if sys.version_info >= (3, 13): - def __init__(self, elts: list[expr] = ..., **kwargs: Unpack[_Attributes]) -> None: ... - else: - def __init__(self, elts: list[expr], **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, elts: list[expr] = ..., **kwargs: Unpack[_Attributes]) -> Self: ... - -class ListComp(expr): - if sys.version_info >= (3, 10): - __match_args__ = ("elt", "generators") - elt: expr - generators: list[comprehension] - if sys.version_info >= (3, 13): - def __init__(self, elt: expr, generators: list[comprehension] = ..., **kwargs: Unpack[_Attributes]) -> None: ... - else: - def __init__(self, elt: expr, generators: list[comprehension], **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, *, elt: expr = ..., generators: list[comprehension] = ..., **kwargs: Unpack[_Attributes] - ) -> Self: ... - -class SetComp(expr): - if sys.version_info >= (3, 10): - __match_args__ = ("elt", "generators") - elt: expr - generators: list[comprehension] - if sys.version_info >= (3, 13): - def __init__(self, elt: expr, generators: list[comprehension] = ..., **kwargs: Unpack[_Attributes]) -> None: ... - else: - def __init__(self, elt: expr, generators: list[comprehension], **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, *, elt: expr = ..., generators: list[comprehension] = ..., **kwargs: Unpack[_Attributes] - ) -> Self: ... - -class DictComp(expr): - if sys.version_info >= (3, 10): - __match_args__ = ("key", "value", "generators") - key: expr - value: expr - generators: list[comprehension] - if sys.version_info >= (3, 13): - def __init__( - self, key: expr, value: expr, generators: list[comprehension] = ..., **kwargs: Unpack[_Attributes] - ) -> None: ... - else: - def __init__(self, key: expr, value: expr, generators: list[comprehension], **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, *, key: expr = ..., value: expr = ..., generators: list[comprehension] = ..., **kwargs: Unpack[_Attributes] - ) -> Self: ... - -class GeneratorExp(expr): - if sys.version_info >= (3, 10): - __match_args__ = ("elt", "generators") - elt: expr - generators: list[comprehension] - if sys.version_info >= (3, 13): - def __init__(self, elt: expr, generators: list[comprehension] = ..., **kwargs: Unpack[_Attributes]) -> None: ... - else: - def __init__(self, elt: expr, generators: list[comprehension], **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, *, elt: expr = ..., generators: list[comprehension] = ..., **kwargs: Unpack[_Attributes] - ) -> Self: ... - -class Await(expr): - if sys.version_info >= (3, 10): - __match_args__ = ("value",) - value: expr - def __init__(self, value: expr, **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, value: expr = ..., **kwargs: Unpack[_Attributes]) -> Self: ... - -class Yield(expr): - if sys.version_info >= (3, 10): - __match_args__ = ("value",) - value: expr | None - def __init__(self, value: expr | None = None, **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, value: expr | None = ..., **kwargs: Unpack[_Attributes]) -> Self: ... - -class YieldFrom(expr): - if sys.version_info >= (3, 10): - __match_args__ = ("value",) - value: expr - def __init__(self, value: expr, **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, value: expr = ..., **kwargs: Unpack[_Attributes]) -> Self: ... - -class Compare(expr): - if sys.version_info >= (3, 10): - __match_args__ = ("left", "ops", "comparators") - left: expr - ops: list[cmpop] - comparators: list[expr] - if sys.version_info >= (3, 13): - def __init__( - self, left: expr, ops: list[cmpop] = ..., comparators: list[expr] = ..., **kwargs: Unpack[_Attributes] - ) -> None: ... - else: - def __init__(self, left: expr, ops: list[cmpop], comparators: list[expr], **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, *, left: expr = ..., ops: list[cmpop] = ..., comparators: list[expr] = ..., **kwargs: Unpack[_Attributes] - ) -> Self: ... - -class Call(expr): - if sys.version_info >= (3, 10): - __match_args__ = ("func", "args", "keywords") - func: expr - args: list[expr] - keywords: list[keyword] - if sys.version_info >= (3, 13): - def __init__( - self, func: expr, args: list[expr] = ..., keywords: list[keyword] = ..., **kwargs: Unpack[_Attributes] - ) -> None: ... - else: - def __init__(self, func: expr, args: list[expr], keywords: list[keyword], **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, *, func: expr = ..., args: list[expr] = ..., keywords: list[keyword] = ..., **kwargs: Unpack[_Attributes] - ) -> Self: ... - -class FormattedValue(expr): - if sys.version_info >= (3, 10): - __match_args__ = ("value", "conversion", "format_spec") - value: expr - conversion: int - format_spec: expr | None - def __init__(self, value: expr, conversion: int, format_spec: expr | None = None, **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, *, value: expr = ..., conversion: int = ..., format_spec: expr | None = ..., **kwargs: Unpack[_Attributes] - ) -> Self: ... - -class JoinedStr(expr): - if sys.version_info >= (3, 10): - __match_args__ = ("values",) - values: list[expr] - if sys.version_info >= (3, 13): - def __init__(self, values: list[expr] = ..., **kwargs: Unpack[_Attributes]) -> None: ... - else: - def __init__(self, values: list[expr], **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, values: list[expr] = ..., **kwargs: Unpack[_Attributes]) -> Self: ... - -class Constant(expr): - if sys.version_info >= (3, 10): - __match_args__ = ("value", "kind") - value: Any # None, str, bytes, bool, int, float, complex, Ellipsis - kind: str | None - if sys.version_info < (3, 14): - # Aliases for value, for backwards compatibility - s: Any - n: int | float | complex - - def __init__(self, value: Any, kind: str | None = None, **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, value: Any = ..., kind: str | None = ..., **kwargs: Unpack[_Attributes]) -> Self: ... - -class NamedExpr(expr): - if sys.version_info >= (3, 10): - __match_args__ = ("target", "value") - target: Name - value: expr - def __init__(self, target: Name, value: expr, **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, target: Name = ..., value: expr = ..., **kwargs: Unpack[_Attributes]) -> Self: ... - -class Attribute(expr): - if sys.version_info >= (3, 10): - __match_args__ = ("value", "attr", "ctx") - value: expr - attr: _Identifier - ctx: expr_context # Not present in Python < 3.13 if not passed to `__init__` - def __init__(self, value: expr, attr: _Identifier, ctx: expr_context = ..., **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, *, value: expr = ..., attr: _Identifier = ..., ctx: expr_context = ..., **kwargs: Unpack[_Attributes] - ) -> Self: ... - -if sys.version_info >= (3, 9): - _Slice: typing_extensions.TypeAlias = expr - _SliceAttributes: typing_extensions.TypeAlias = _Attributes -else: - class slice(AST): ... - _Slice: typing_extensions.TypeAlias = slice - - class _SliceAttributes(TypedDict): ... - -class Slice(_Slice): - if sys.version_info >= (3, 10): - __match_args__ = ("lower", "upper", "step") - lower: expr | None - upper: expr | None - step: expr | None - def __init__( - self, lower: expr | None = None, upper: expr | None = None, step: expr | None = None, **kwargs: Unpack[_SliceAttributes] - ) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, - *, - lower: expr | None = ..., - upper: expr | None = ..., - step: expr | None = ..., - **kwargs: Unpack[_SliceAttributes], - ) -> Self: ... - -if sys.version_info < (3, 9): - class ExtSlice(slice): - dims: list[slice] - def __init__(self, dims: list[slice], **kwargs: Unpack[_SliceAttributes]) -> None: ... - - class Index(slice): - value: expr - def __init__(self, value: expr, **kwargs: Unpack[_SliceAttributes]) -> None: ... - -class Subscript(expr): - if sys.version_info >= (3, 10): - __match_args__ = ("value", "slice", "ctx") - value: expr - slice: _Slice - ctx: expr_context # Not present in Python < 3.13 if not passed to `__init__` - def __init__(self, value: expr, slice: _Slice, ctx: expr_context = ..., **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, *, value: expr = ..., slice: _Slice = ..., ctx: expr_context = ..., **kwargs: Unpack[_Attributes] - ) -> Self: ... - -class Starred(expr): - if sys.version_info >= (3, 10): - __match_args__ = ("value", "ctx") - value: expr - ctx: expr_context # Not present in Python < 3.13 if not passed to `__init__` - def __init__(self, value: expr, ctx: expr_context = ..., **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, value: expr = ..., ctx: expr_context = ..., **kwargs: Unpack[_Attributes]) -> Self: ... - -class Name(expr): - if sys.version_info >= (3, 10): - __match_args__ = ("id", "ctx") - id: _Identifier - ctx: expr_context # Not present in Python < 3.13 if not passed to `__init__` - def __init__(self, id: _Identifier, ctx: expr_context = ..., **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, id: _Identifier = ..., ctx: expr_context = ..., **kwargs: Unpack[_Attributes]) -> Self: ... - -class List(expr): - if sys.version_info >= (3, 10): - __match_args__ = ("elts", "ctx") - elts: list[expr] - ctx: expr_context # Not present in Python < 3.13 if not passed to `__init__` - if sys.version_info >= (3, 13): - def __init__(self, elts: list[expr] = ..., ctx: expr_context = ..., **kwargs: Unpack[_Attributes]) -> None: ... - else: - def __init__(self, elts: list[expr], ctx: expr_context = ..., **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, elts: list[expr] = ..., ctx: expr_context = ..., **kwargs: Unpack[_Attributes]) -> Self: ... - -class Tuple(expr): - if sys.version_info >= (3, 10): - __match_args__ = ("elts", "ctx") - elts: list[expr] - ctx: expr_context # Not present in Python < 3.13 if not passed to `__init__` - if sys.version_info >= (3, 9): - dims: list[expr] - if sys.version_info >= (3, 13): - def __init__(self, elts: list[expr] = ..., ctx: expr_context = ..., **kwargs: Unpack[_Attributes]) -> None: ... - else: - def __init__(self, elts: list[expr], ctx: expr_context = ..., **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, elts: list[expr] = ..., ctx: expr_context = ..., **kwargs: Unpack[_Attributes]) -> Self: ... - -class expr_context(AST): ... - -if sys.version_info < (3, 9): - class AugLoad(expr_context): ... - class AugStore(expr_context): ... - class Param(expr_context): ... - - class Suite(mod): - body: list[stmt] - def __init__(self, body: list[stmt]) -> None: ... - -class Del(expr_context): ... -class Load(expr_context): ... -class Store(expr_context): ... -class boolop(AST): ... -class And(boolop): ... -class Or(boolop): ... -class operator(AST): ... -class Add(operator): ... -class BitAnd(operator): ... -class BitOr(operator): ... -class BitXor(operator): ... -class Div(operator): ... -class FloorDiv(operator): ... -class LShift(operator): ... -class Mod(operator): ... -class Mult(operator): ... -class MatMult(operator): ... -class Pow(operator): ... -class RShift(operator): ... -class Sub(operator): ... -class unaryop(AST): ... -class Invert(unaryop): ... -class Not(unaryop): ... -class UAdd(unaryop): ... -class USub(unaryop): ... -class cmpop(AST): ... -class Eq(cmpop): ... -class Gt(cmpop): ... -class GtE(cmpop): ... -class In(cmpop): ... -class Is(cmpop): ... -class IsNot(cmpop): ... -class Lt(cmpop): ... -class LtE(cmpop): ... -class NotEq(cmpop): ... -class NotIn(cmpop): ... - -class comprehension(AST): - if sys.version_info >= (3, 10): - __match_args__ = ("target", "iter", "ifs", "is_async") - target: expr - iter: expr - ifs: list[expr] - is_async: int - if sys.version_info >= (3, 13): - @overload - def __init__(self, target: expr, iter: expr, ifs: list[expr], is_async: int) -> None: ... - @overload - def __init__(self, target: expr, iter: expr, ifs: list[expr] = ..., *, is_async: int) -> None: ... - else: - def __init__(self, target: expr, iter: expr, ifs: list[expr], is_async: int) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, target: expr = ..., iter: expr = ..., ifs: list[expr] = ..., is_async: int = ...) -> Self: ... - -class excepthandler(AST): - lineno: int - col_offset: int - end_lineno: int | None - end_col_offset: int | None - def __init__(self, **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, *, lineno: int = ..., col_offset: int = ..., end_lineno: int | None = ..., end_col_offset: int | None = ... - ) -> Self: ... - -class ExceptHandler(excepthandler): - if sys.version_info >= (3, 10): - __match_args__ = ("type", "name", "body") - type: expr | None - name: _Identifier | None - body: list[stmt] - if sys.version_info >= (3, 13): - def __init__( - self, type: expr | None = None, name: _Identifier | None = None, body: list[stmt] = ..., **kwargs: Unpack[_Attributes] - ) -> None: ... - else: - @overload - def __init__( - self, type: expr | None, name: _Identifier | None, body: list[stmt], **kwargs: Unpack[_Attributes] - ) -> None: ... - @overload - def __init__( - self, type: expr | None = None, name: _Identifier | None = None, *, body: list[stmt], **kwargs: Unpack[_Attributes] - ) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, - *, - type: expr | None = ..., - name: _Identifier | None = ..., - body: list[stmt] = ..., - **kwargs: Unpack[_Attributes], - ) -> Self: ... - -class arguments(AST): - if sys.version_info >= (3, 10): - __match_args__ = ("posonlyargs", "args", "vararg", "kwonlyargs", "kw_defaults", "kwarg", "defaults") - posonlyargs: list[arg] - args: list[arg] - vararg: arg | None - kwonlyargs: list[arg] - kw_defaults: list[expr | None] - kwarg: arg | None - defaults: list[expr] - if sys.version_info >= (3, 13): - def __init__( - self, - posonlyargs: list[arg] = ..., - args: list[arg] = ..., - vararg: arg | None = None, - kwonlyargs: list[arg] = ..., - kw_defaults: list[expr | None] = ..., - kwarg: arg | None = None, - defaults: list[expr] = ..., - ) -> None: ... - else: - @overload - def __init__( - self, - posonlyargs: list[arg], - args: list[arg], - vararg: arg | None, - kwonlyargs: list[arg], - kw_defaults: list[expr | None], - kwarg: arg | None, - defaults: list[expr], - ) -> None: ... - @overload - def __init__( - self, - posonlyargs: list[arg], - args: list[arg], - vararg: arg | None, - kwonlyargs: list[arg], - kw_defaults: list[expr | None], - kwarg: arg | None = None, - *, - defaults: list[expr], - ) -> None: ... - @overload - def __init__( - self, - posonlyargs: list[arg], - args: list[arg], - vararg: arg | None = None, - *, - kwonlyargs: list[arg], - kw_defaults: list[expr | None], - kwarg: arg | None = None, - defaults: list[expr], - ) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, - *, - posonlyargs: list[arg] = ..., - args: list[arg] = ..., - vararg: arg | None = ..., - kwonlyargs: list[arg] = ..., - kw_defaults: list[expr | None] = ..., - kwarg: arg | None = ..., - defaults: list[expr] = ..., - ) -> Self: ... - -class arg(AST): - lineno: int - col_offset: int - end_lineno: int | None - end_col_offset: int | None - if sys.version_info >= (3, 10): - __match_args__ = ("arg", "annotation", "type_comment") - arg: _Identifier - annotation: expr | None - type_comment: str | None - def __init__( - self, arg: _Identifier, annotation: expr | None = None, type_comment: str | None = None, **kwargs: Unpack[_Attributes] - ) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, - *, - arg: _Identifier = ..., - annotation: expr | None = ..., - type_comment: str | None = ..., - **kwargs: Unpack[_Attributes], - ) -> Self: ... - -class keyword(AST): - lineno: int - col_offset: int - end_lineno: int | None - end_col_offset: int | None - if sys.version_info >= (3, 10): - __match_args__ = ("arg", "value") - arg: _Identifier | None - value: expr - @overload - def __init__(self, arg: _Identifier | None, value: expr, **kwargs: Unpack[_Attributes]) -> None: ... - @overload - def __init__(self, arg: _Identifier | None = None, *, value: expr, **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, arg: _Identifier | None = ..., value: expr = ..., **kwargs: Unpack[_Attributes]) -> Self: ... - -class alias(AST): - lineno: int - col_offset: int - end_lineno: int | None - end_col_offset: int | None - if sys.version_info >= (3, 10): - __match_args__ = ("name", "asname") - name: str - asname: _Identifier | None - def __init__(self, name: str, asname: _Identifier | None = None, **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, name: str = ..., asname: _Identifier | None = ..., **kwargs: Unpack[_Attributes]) -> Self: ... - -class withitem(AST): - if sys.version_info >= (3, 10): - __match_args__ = ("context_expr", "optional_vars") - context_expr: expr - optional_vars: expr | None - def __init__(self, context_expr: expr, optional_vars: expr | None = None) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, context_expr: expr = ..., optional_vars: expr | None = ...) -> Self: ... + from ast import TryStar as TryStar if sys.version_info >= (3, 10): - class Match(stmt): - __match_args__ = ("subject", "cases") - subject: expr - cases: list[match_case] - if sys.version_info >= (3, 13): - def __init__(self, subject: expr, cases: list[match_case] = ..., **kwargs: Unpack[_Attributes]) -> None: ... - else: - def __init__(self, subject: expr, cases: list[match_case], **kwargs: Unpack[_Attributes]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, *, subject: expr = ..., cases: list[match_case] = ..., **kwargs: Unpack[_Attributes] - ) -> Self: ... - - class pattern(AST): - lineno: int - col_offset: int - end_lineno: int - end_col_offset: int - def __init__(self, **kwargs: Unpack[_Attributes[int]]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, *, lineno: int = ..., col_offset: int = ..., end_lineno: int = ..., end_col_offset: int = ... - ) -> Self: ... - - # Without the alias, Pyright complains variables named pattern are recursively defined - _Pattern: typing_extensions.TypeAlias = pattern - - class match_case(AST): - __match_args__ = ("pattern", "guard", "body") - pattern: _Pattern - guard: expr | None - body: list[stmt] - if sys.version_info >= (3, 13): - def __init__(self, pattern: _Pattern, guard: expr | None = None, body: list[stmt] = ...) -> None: ... - else: - @overload - def __init__(self, pattern: _Pattern, guard: expr | None, body: list[stmt]) -> None: ... - @overload - def __init__(self, pattern: _Pattern, guard: expr | None = None, *, body: list[stmt]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, pattern: _Pattern = ..., guard: expr | None = ..., body: list[stmt] = ...) -> Self: ... - - class MatchValue(pattern): - __match_args__ = ("value",) - value: expr - def __init__(self, value: expr, **kwargs: Unpack[_Attributes[int]]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, value: expr = ..., **kwargs: Unpack[_Attributes[int]]) -> Self: ... - - class MatchSingleton(pattern): - __match_args__ = ("value",) - value: Literal[True, False] | None - def __init__(self, value: Literal[True, False] | None, **kwargs: Unpack[_Attributes[int]]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, value: Literal[True, False] | None = ..., **kwargs: Unpack[_Attributes[int]]) -> Self: ... - - class MatchSequence(pattern): - __match_args__ = ("patterns",) - patterns: list[pattern] - if sys.version_info >= (3, 13): - def __init__(self, patterns: list[pattern] = ..., **kwargs: Unpack[_Attributes[int]]) -> None: ... - else: - def __init__(self, patterns: list[pattern], **kwargs: Unpack[_Attributes[int]]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, patterns: list[pattern] = ..., **kwargs: Unpack[_Attributes[int]]) -> Self: ... - - class MatchStar(pattern): - __match_args__ = ("name",) - name: _Identifier | None - def __init__(self, name: _Identifier | None, **kwargs: Unpack[_Attributes[int]]) -> None: ... + from ast import ( + MatchAs as MatchAs, + MatchClass as MatchClass, + MatchMapping as MatchMapping, + MatchOr as MatchOr, + MatchSequence as MatchSequence, + MatchSingleton as MatchSingleton, + MatchStar as MatchStar, + MatchValue as MatchValue, + match_case as match_case, + pattern as pattern, + ) - if sys.version_info >= (3, 14): - def __replace__(self, *, name: _Identifier | None = ..., **kwargs: Unpack[_Attributes[int]]) -> Self: ... - - class MatchMapping(pattern): - __match_args__ = ("keys", "patterns", "rest") - keys: list[expr] - patterns: list[pattern] - rest: _Identifier | None - if sys.version_info >= (3, 13): - def __init__( - self, - keys: list[expr] = ..., - patterns: list[pattern] = ..., - rest: _Identifier | None = None, - **kwargs: Unpack[_Attributes[int]], - ) -> None: ... - else: - def __init__( - self, - keys: list[expr], - patterns: list[pattern], - rest: _Identifier | None = None, - **kwargs: Unpack[_Attributes[int]], - ) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, - *, - keys: list[expr] = ..., - patterns: list[pattern] = ..., - rest: _Identifier | None = ..., - **kwargs: Unpack[_Attributes[int]], - ) -> Self: ... - - class MatchClass(pattern): - __match_args__ = ("cls", "patterns", "kwd_attrs", "kwd_patterns") - cls: expr - patterns: list[pattern] - kwd_attrs: list[_Identifier] - kwd_patterns: list[pattern] - if sys.version_info >= (3, 13): - def __init__( - self, - cls: expr, - patterns: list[pattern] = ..., - kwd_attrs: list[_Identifier] = ..., - kwd_patterns: list[pattern] = ..., - **kwargs: Unpack[_Attributes[int]], - ) -> None: ... - else: - def __init__( - self, - cls: expr, - patterns: list[pattern], - kwd_attrs: list[_Identifier], - kwd_patterns: list[pattern], - **kwargs: Unpack[_Attributes[int]], - ) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, - *, - cls: expr = ..., - patterns: list[pattern] = ..., - kwd_attrs: list[_Identifier] = ..., - kwd_patterns: list[pattern] = ..., - **kwargs: Unpack[_Attributes[int]], - ) -> Self: ... - - class MatchAs(pattern): - __match_args__ = ("pattern", "name") - pattern: _Pattern | None - name: _Identifier | None - def __init__( - self, pattern: _Pattern | None = None, name: _Identifier | None = None, **kwargs: Unpack[_Attributes[int]] - ) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, *, pattern: _Pattern | None = ..., name: _Identifier | None = ..., **kwargs: Unpack[_Attributes[int]] - ) -> Self: ... - - class MatchOr(pattern): - __match_args__ = ("patterns",) - patterns: list[pattern] - if sys.version_info >= (3, 13): - def __init__(self, patterns: list[pattern] = ..., **kwargs: Unpack[_Attributes[int]]) -> None: ... - else: - def __init__(self, patterns: list[pattern], **kwargs: Unpack[_Attributes[int]]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, *, patterns: list[pattern] = ..., **kwargs: Unpack[_Attributes[int]]) -> Self: ... - -if sys.version_info >= (3, 12): - class type_param(AST): - lineno: int - col_offset: int - end_lineno: int - end_col_offset: int - def __init__(self, **kwargs: Unpack[_Attributes[int]]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__(self, **kwargs: Unpack[_Attributes[int]]) -> Self: ... - - class TypeVar(type_param): - if sys.version_info >= (3, 13): - __match_args__ = ("name", "bound", "default_value") - else: - __match_args__ = ("name", "bound") - name: _Identifier - bound: expr | None - if sys.version_info >= (3, 13): - default_value: expr | None - def __init__( - self, - name: _Identifier, - bound: expr | None = None, - default_value: expr | None = None, - **kwargs: Unpack[_Attributes[int]], - ) -> None: ... - else: - def __init__(self, name: _Identifier, bound: expr | None = None, **kwargs: Unpack[_Attributes[int]]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, - *, - name: _Identifier = ..., - bound: expr | None = ..., - default_value: expr | None = ..., - **kwargs: Unpack[_Attributes[int]], - ) -> Self: ... - - class ParamSpec(type_param): - if sys.version_info >= (3, 13): - __match_args__ = ("name", "default_value") - else: - __match_args__ = ("name",) - name: _Identifier - if sys.version_info >= (3, 13): - default_value: expr | None - def __init__( - self, name: _Identifier, default_value: expr | None = None, **kwargs: Unpack[_Attributes[int]] - ) -> None: ... - else: - def __init__(self, name: _Identifier, **kwargs: Unpack[_Attributes[int]]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, *, name: _Identifier = ..., default_value: expr | None = ..., **kwargs: Unpack[_Attributes[int]] - ) -> Self: ... - - class TypeVarTuple(type_param): - if sys.version_info >= (3, 13): - __match_args__ = ("name", "default_value") - else: - __match_args__ = ("name",) - name: _Identifier - if sys.version_info >= (3, 13): - default_value: expr | None - def __init__( - self, name: _Identifier, default_value: expr | None = None, **kwargs: Unpack[_Attributes[int]] - ) -> None: ... - else: - def __init__(self, name: _Identifier, **kwargs: Unpack[_Attributes[int]]) -> None: ... - - if sys.version_info >= (3, 14): - def __replace__( - self, *, name: _Identifier = ..., default_value: expr | None = ..., **kwargs: Unpack[_Attributes[int]] - ) -> Self: ... +if sys.version_info < (3, 9): + from ast import ( + AugLoad as AugLoad, + AugStore as AugStore, + ExtSlice as ExtSlice, + Index as Index, + Param as Param, + Suite as Suite, + slice as slice, + ) - class TypeAlias(stmt): - __match_args__ = ("name", "type_params", "value") - name: Name - type_params: list[type_param] - value: expr - if sys.version_info >= (3, 13): - @overload - def __init__( - self, name: Name, type_params: list[type_param], value: expr, **kwargs: Unpack[_Attributes[int]] - ) -> None: ... - @overload - def __init__( - self, name: Name, type_params: list[type_param] = ..., *, value: expr, **kwargs: Unpack[_Attributes[int]] - ) -> None: ... - else: - def __init__( - self, name: Name, type_params: list[type_param], value: expr, **kwargs: Unpack[_Attributes[int]] - ) -> None: ... +PyCF_ALLOW_TOP_LEVEL_AWAIT: Literal[8192] +PyCF_ONLY_AST: Literal[1024] +PyCF_TYPE_COMMENTS: Literal[4096] - if sys.version_info >= (3, 14): - def __replace__( - self, - *, - name: Name = ..., - type_params: list[type_param] = ..., - value: expr = ..., - **kwargs: Unpack[_Attributes[int]], - ) -> Self: ... +if sys.version_info >= (3, 13): + PyCF_OPTIMIZED_AST: Literal[33792] diff --git a/mypy/typeshed/stdlib/_asyncio.pyi b/mypy/typeshed/stdlib/_asyncio.pyi new file mode 100644 index 000000000000..a259026615aa --- /dev/null +++ b/mypy/typeshed/stdlib/_asyncio.pyi @@ -0,0 +1,120 @@ +import sys +from asyncio.events import AbstractEventLoop +from collections.abc import Awaitable, Callable, Coroutine, Generator +from contextvars import Context +from types import FrameType +from typing import Any, Literal, TextIO, TypeVar +from typing_extensions import Self, TypeAlias + +if sys.version_info >= (3, 9): + from types import GenericAlias + +_T = TypeVar("_T") +_T_co = TypeVar("_T_co", covariant=True) +_TaskYieldType: TypeAlias = Future[object] | None + +class Future(Awaitable[_T]): + _state: str + @property + def _exception(self) -> BaseException | None: ... + _blocking: bool + @property + def _log_traceback(self) -> bool: ... + @_log_traceback.setter + def _log_traceback(self, val: Literal[False]) -> None: ... + _asyncio_future_blocking: bool # is a part of duck-typing contract for `Future` + def __init__(self, *, loop: AbstractEventLoop | None = ...) -> None: ... + def __del__(self) -> None: ... + def get_loop(self) -> AbstractEventLoop: ... + @property + def _callbacks(self) -> list[tuple[Callable[[Self], Any], Context]]: ... + def add_done_callback(self, fn: Callable[[Self], object], /, *, context: Context | None = None) -> None: ... + if sys.version_info >= (3, 9): + def cancel(self, msg: Any | None = None) -> bool: ... + else: + def cancel(self) -> bool: ... + + def cancelled(self) -> bool: ... + def done(self) -> bool: ... + def result(self) -> _T: ... + def exception(self) -> BaseException | None: ... + def remove_done_callback(self, fn: Callable[[Self], object], /) -> int: ... + def set_result(self, result: _T, /) -> None: ... + def set_exception(self, exception: type | BaseException, /) -> None: ... + def __iter__(self) -> Generator[Any, None, _T]: ... + def __await__(self) -> Generator[Any, None, _T]: ... + @property + def _loop(self) -> AbstractEventLoop: ... + if sys.version_info >= (3, 9): + def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... + +if sys.version_info >= (3, 12): + _TaskCompatibleCoro: TypeAlias = Coroutine[Any, Any, _T_co] +elif sys.version_info >= (3, 9): + _TaskCompatibleCoro: TypeAlias = Generator[_TaskYieldType, None, _T_co] | Coroutine[Any, Any, _T_co] +else: + _TaskCompatibleCoro: TypeAlias = Generator[_TaskYieldType, None, _T_co] | Awaitable[_T_co] + +# mypy and pyright complain that a subclass of an invariant class shouldn't be covariant. +# While this is true in general, here it's sort-of okay to have a covariant subclass, +# since the only reason why `asyncio.Future` is invariant is the `set_result()` method, +# and `asyncio.Task.set_result()` always raises. +class Task(Future[_T_co]): # type: ignore[type-var] # pyright: ignore[reportInvalidTypeArguments] + if sys.version_info >= (3, 12): + def __init__( + self, + coro: _TaskCompatibleCoro[_T_co], + *, + loop: AbstractEventLoop = ..., + name: str | None = ..., + context: Context | None = None, + eager_start: bool = False, + ) -> None: ... + elif sys.version_info >= (3, 11): + def __init__( + self, + coro: _TaskCompatibleCoro[_T_co], + *, + loop: AbstractEventLoop = ..., + name: str | None = ..., + context: Context | None = None, + ) -> None: ... + else: + def __init__( + self, coro: _TaskCompatibleCoro[_T_co], *, loop: AbstractEventLoop = ..., name: str | None = ... + ) -> None: ... + + if sys.version_info >= (3, 12): + def get_coro(self) -> _TaskCompatibleCoro[_T_co] | None: ... + else: + def get_coro(self) -> _TaskCompatibleCoro[_T_co]: ... + + def get_name(self) -> str: ... + def set_name(self, value: object, /) -> None: ... + if sys.version_info >= (3, 12): + def get_context(self) -> Context: ... + + def get_stack(self, *, limit: int | None = None) -> list[FrameType]: ... + def print_stack(self, *, limit: int | None = None, file: TextIO | None = None) -> None: ... + if sys.version_info >= (3, 11): + def cancelling(self) -> int: ... + def uncancel(self) -> int: ... + if sys.version_info < (3, 9): + @classmethod + def current_task(cls, loop: AbstractEventLoop | None = None) -> Task[Any] | None: ... + @classmethod + def all_tasks(cls, loop: AbstractEventLoop | None = None) -> set[Task[Any]]: ... + if sys.version_info >= (3, 9): + def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... + +def get_event_loop() -> AbstractEventLoop: ... +def get_running_loop() -> AbstractEventLoop: ... +def _set_running_loop(loop: AbstractEventLoop | None, /) -> None: ... +def _get_running_loop() -> AbstractEventLoop: ... +def _register_task(task: Task[Any]) -> None: ... +def _unregister_task(task: Task[Any]) -> None: ... +def _enter_task(loop: AbstractEventLoop, task: Task[Any]) -> None: ... +def _leave_task(loop: AbstractEventLoop, task: Task[Any]) -> None: ... + +if sys.version_info >= (3, 12): + def current_task(loop: AbstractEventLoop | None = None) -> Task[Any] | None: ... diff --git a/mypy/typeshed/stdlib/_blake2.pyi b/mypy/typeshed/stdlib/_blake2.pyi new file mode 100644 index 000000000000..10d7019a222f --- /dev/null +++ b/mypy/typeshed/stdlib/_blake2.pyi @@ -0,0 +1,117 @@ +import sys +from _typeshed import ReadableBuffer +from typing import ClassVar, final +from typing_extensions import Self + +BLAKE2B_MAX_DIGEST_SIZE: int = 64 +BLAKE2B_MAX_KEY_SIZE: int = 64 +BLAKE2B_PERSON_SIZE: int = 16 +BLAKE2B_SALT_SIZE: int = 16 +BLAKE2S_MAX_DIGEST_SIZE: int = 32 +BLAKE2S_MAX_KEY_SIZE: int = 32 +BLAKE2S_PERSON_SIZE: int = 8 +BLAKE2S_SALT_SIZE: int = 8 + +@final +class blake2b: + MAX_DIGEST_SIZE: ClassVar[int] = 64 + MAX_KEY_SIZE: ClassVar[int] = 64 + PERSON_SIZE: ClassVar[int] = 16 + SALT_SIZE: ClassVar[int] = 16 + block_size: int + digest_size: int + name: str + if sys.version_info >= (3, 9): + def __init__( + self, + data: ReadableBuffer = b"", + /, + *, + digest_size: int = 64, + key: ReadableBuffer = b"", + salt: ReadableBuffer = b"", + person: ReadableBuffer = b"", + fanout: int = 1, + depth: int = 1, + leaf_size: int = 0, + node_offset: int = 0, + node_depth: int = 0, + inner_size: int = 0, + last_node: bool = False, + usedforsecurity: bool = True, + ) -> None: ... + else: + def __init__( + self, + data: ReadableBuffer = b"", + /, + *, + digest_size: int = 64, + key: ReadableBuffer = b"", + salt: ReadableBuffer = b"", + person: ReadableBuffer = b"", + fanout: int = 1, + depth: int = 1, + leaf_size: int = 0, + node_offset: int = 0, + node_depth: int = 0, + inner_size: int = 0, + last_node: bool = False, + ) -> None: ... + + def copy(self) -> Self: ... + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def update(self, data: ReadableBuffer, /) -> None: ... + +@final +class blake2s: + MAX_DIGEST_SIZE: ClassVar[int] = 32 + MAX_KEY_SIZE: ClassVar[int] = 32 + PERSON_SIZE: ClassVar[int] = 8 + SALT_SIZE: ClassVar[int] = 8 + block_size: int + digest_size: int + name: str + if sys.version_info >= (3, 9): + def __init__( + self, + data: ReadableBuffer = b"", + /, + *, + digest_size: int = 32, + key: ReadableBuffer = b"", + salt: ReadableBuffer = b"", + person: ReadableBuffer = b"", + fanout: int = 1, + depth: int = 1, + leaf_size: int = 0, + node_offset: int = 0, + node_depth: int = 0, + inner_size: int = 0, + last_node: bool = False, + usedforsecurity: bool = True, + ) -> None: ... + else: + def __init__( + self, + data: ReadableBuffer = b"", + /, + *, + digest_size: int = 32, + key: ReadableBuffer = b"", + salt: ReadableBuffer = b"", + person: ReadableBuffer = b"", + fanout: int = 1, + depth: int = 1, + leaf_size: int = 0, + node_offset: int = 0, + node_depth: int = 0, + inner_size: int = 0, + last_node: bool = False, + ) -> None: ... + + def copy(self) -> Self: ... + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def update(self, data: ReadableBuffer, /) -> None: ... diff --git a/mypy/typeshed/stdlib/_bz2.pyi b/mypy/typeshed/stdlib/_bz2.pyi new file mode 100644 index 000000000000..4ba26fe96be0 --- /dev/null +++ b/mypy/typeshed/stdlib/_bz2.pyi @@ -0,0 +1,18 @@ +from _typeshed import ReadableBuffer +from typing import final + +@final +class BZ2Compressor: + def __init__(self, compresslevel: int = 9) -> None: ... + def compress(self, data: ReadableBuffer, /) -> bytes: ... + def flush(self) -> bytes: ... + +@final +class BZ2Decompressor: + def decompress(self, data: ReadableBuffer, max_length: int = -1) -> bytes: ... + @property + def eof(self) -> bool: ... + @property + def needs_input(self) -> bool: ... + @property + def unused_data(self) -> bytes: ... diff --git a/mypy/typeshed/stdlib/_codecs.pyi b/mypy/typeshed/stdlib/_codecs.pyi index ecf874d33ddd..11c5d58a855b 100644 --- a/mypy/typeshed/stdlib/_codecs.pyi +++ b/mypy/typeshed/stdlib/_codecs.pyi @@ -2,10 +2,13 @@ import codecs import sys from _typeshed import ReadableBuffer from collections.abc import Callable -from typing import Literal, overload +from typing import Literal, final, overload, type_check_only from typing_extensions import TypeAlias # This type is not exposed; it is defined in unicodeobject.c +# At runtime it calls itself builtins.EncodingMap +@final +@type_check_only class _EncodingMap: def size(self) -> int: ... diff --git a/mypy/typeshed/stdlib/_collections_abc.pyi b/mypy/typeshed/stdlib/_collections_abc.pyi index 8b1ac9c7eb8b..bf7f2991f9a4 100644 --- a/mypy/typeshed/stdlib/_collections_abc.pyi +++ b/mypy/typeshed/stdlib/_collections_abc.pyi @@ -73,6 +73,7 @@ _VT_co = TypeVar("_VT_co", covariant=True) # Value type covariant containers. @final class dict_keys(KeysView[_KT_co], Generic[_KT_co, _VT_co]): # undocumented def __eq__(self, value: object, /) -> bool: ... + def __reversed__(self) -> Iterator[_KT_co]: ... if sys.version_info >= (3, 13): def isdisjoint(self, other: Iterable[_KT_co], /) -> bool: ... if sys.version_info >= (3, 10): @@ -81,6 +82,7 @@ class dict_keys(KeysView[_KT_co], Generic[_KT_co, _VT_co]): # undocumented @final class dict_values(ValuesView[_VT_co], Generic[_KT_co, _VT_co]): # undocumented + def __reversed__(self) -> Iterator[_VT_co]: ... if sys.version_info >= (3, 10): @property def mapping(self) -> MappingProxyType[_KT_co, _VT_co]: ... @@ -88,6 +90,7 @@ class dict_values(ValuesView[_VT_co], Generic[_KT_co, _VT_co]): # undocumented @final class dict_items(ItemsView[_KT_co, _VT_co]): # undocumented def __eq__(self, value: object, /) -> bool: ... + def __reversed__(self) -> Iterator[tuple[_KT_co, _VT_co]]: ... if sys.version_info >= (3, 13): def isdisjoint(self, other: Iterable[tuple[_KT_co, _VT_co]], /) -> bool: ... if sys.version_info >= (3, 10): diff --git a/mypy/typeshed/stdlib/_contextvars.pyi b/mypy/typeshed/stdlib/_contextvars.pyi new file mode 100644 index 000000000000..2e21a8c5d017 --- /dev/null +++ b/mypy/typeshed/stdlib/_contextvars.pyi @@ -0,0 +1,61 @@ +import sys +from collections.abc import Callable, Iterator, Mapping +from typing import Any, ClassVar, Generic, TypeVar, final, overload +from typing_extensions import ParamSpec + +if sys.version_info >= (3, 9): + from types import GenericAlias + +_T = TypeVar("_T") +_D = TypeVar("_D") +_P = ParamSpec("_P") + +@final +class ContextVar(Generic[_T]): + @overload + def __init__(self, name: str) -> None: ... + @overload + def __init__(self, name: str, *, default: _T) -> None: ... + def __hash__(self) -> int: ... + @property + def name(self) -> str: ... + @overload + def get(self) -> _T: ... + @overload + def get(self, default: _T, /) -> _T: ... + @overload + def get(self, default: _D, /) -> _D | _T: ... + def set(self, value: _T, /) -> Token[_T]: ... + def reset(self, token: Token[_T], /) -> None: ... + if sys.version_info >= (3, 9): + def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... + +@final +class Token(Generic[_T]): + @property + def var(self) -> ContextVar[_T]: ... + @property + def old_value(self) -> Any: ... # returns either _T or MISSING, but that's hard to express + MISSING: ClassVar[object] + if sys.version_info >= (3, 9): + def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... + +def copy_context() -> Context: ... + +# It doesn't make sense to make this generic, because for most Contexts each ContextVar will have +# a different value. +@final +class Context(Mapping[ContextVar[Any], Any]): + def __init__(self) -> None: ... + @overload + def get(self, key: ContextVar[_T], default: None = None, /) -> _T | None: ... + @overload + def get(self, key: ContextVar[_T], default: _T, /) -> _T: ... + @overload + def get(self, key: ContextVar[_T], default: _D, /) -> _T | _D: ... + def run(self, callable: Callable[_P, _T], *args: _P.args, **kwargs: _P.kwargs) -> _T: ... + def copy(self) -> Context: ... + def __getitem__(self, key: ContextVar[_T], /) -> _T: ... + def __iter__(self) -> Iterator[ContextVar[Any]]: ... + def __len__(self) -> int: ... + def __eq__(self, value: object, /) -> bool: ... diff --git a/mypy/typeshed/stdlib/_csv.pyi b/mypy/typeshed/stdlib/_csv.pyi index 9bb5d27f6e35..afa2870be158 100644 --- a/mypy/typeshed/stdlib/_csv.pyi +++ b/mypy/typeshed/stdlib/_csv.pyi @@ -1,8 +1,9 @@ +import csv import sys from _typeshed import SupportsWrite -from collections.abc import Iterable, Iterator -from typing import Any, Final -from typing_extensions import TypeAlias +from collections.abc import Iterable +from typing import Any, Final, type_check_only +from typing_extensions import Self, TypeAlias __version__: Final[str] @@ -20,6 +21,8 @@ _QuotingType: TypeAlias = int class Error(Exception): ... +_DialectLike: TypeAlias = str | Dialect | csv.Dialect | type[Dialect | csv.Dialect] + class Dialect: delimiter: str quotechar: str | None @@ -29,21 +32,60 @@ class Dialect: lineterminator: str quoting: _QuotingType strict: bool - def __init__(self) -> None: ... + def __init__( + self, + dialect: _DialectLike | None = ..., + delimiter: str = ",", + doublequote: bool = True, + escapechar: str | None = None, + lineterminator: str = "\r\n", + quotechar: str | None = '"', + quoting: _QuotingType = 0, + skipinitialspace: bool = False, + strict: bool = False, + ) -> None: ... + +if sys.version_info >= (3, 10): + # This class calls itself _csv.reader. + class Reader: + @property + def dialect(self) -> Dialect: ... + line_num: int + def __iter__(self) -> Self: ... + def __next__(self) -> list[str]: ... -_DialectLike: TypeAlias = str | Dialect | type[Dialect] + # This class calls itself _csv.writer. + class Writer: + @property + def dialect(self) -> Dialect: ... + if sys.version_info >= (3, 13): + def writerow(self, row: Iterable[Any], /) -> Any: ... + def writerows(self, rows: Iterable[Iterable[Any]], /) -> None: ... + else: + def writerow(self, row: Iterable[Any]) -> Any: ... + def writerows(self, rows: Iterable[Iterable[Any]]) -> None: ... -class _reader(Iterator[list[str]]): - @property - def dialect(self) -> Dialect: ... - line_num: int - def __next__(self) -> list[str]: ... + # For the return types below. + # These aliases can be removed when typeshed drops support for 3.9. + _reader = Reader + _writer = Writer +else: + # This class is not exposed. It calls itself _csv.reader. + @type_check_only + class _reader: + @property + def dialect(self) -> Dialect: ... + line_num: int + def __iter__(self) -> Self: ... + def __next__(self) -> list[str]: ... -class _writer: - @property - def dialect(self) -> Dialect: ... - def writerow(self, row: Iterable[Any]) -> Any: ... - def writerows(self, rows: Iterable[Iterable[Any]]) -> None: ... + # This class is not exposed. It calls itself _csv.writer. + @type_check_only + class _writer: + @property + def dialect(self) -> Dialect: ... + def writerow(self, row: Iterable[Any]) -> Any: ... + def writerows(self, rows: Iterable[Iterable[Any]]) -> None: ... def writer( csvfile: SupportsWrite[str], diff --git a/mypy/typeshed/stdlib/_ctypes.pyi b/mypy/typeshed/stdlib/_ctypes.pyi index 0fe7521d7749..ecb07a29bb75 100644 --- a/mypy/typeshed/stdlib/_ctypes.pyi +++ b/mypy/typeshed/stdlib/_ctypes.pyi @@ -1,9 +1,10 @@ +import _typeshed import sys -from _typeshed import ReadableBuffer, WriteableBuffer +from _typeshed import ReadableBuffer, StrOrBytesPath, WriteableBuffer from abc import abstractmethod from collections.abc import Callable, Iterable, Iterator, Mapping, Sequence -from ctypes import CDLL, ArgumentError as ArgumentError -from typing import Any, ClassVar, Generic, TypeVar, overload +from ctypes import CDLL, ArgumentError as ArgumentError, c_void_p +from typing import Any, ClassVar, Generic, TypeVar, final, overload, type_check_only from typing_extensions import Self, TypeAlias if sys.version_info >= (3, 9): @@ -47,46 +48,79 @@ if sys.platform == "win32": def LoadLibrary(name: str, load_flags: int = 0, /) -> int: ... def FreeLibrary(handle: int, /) -> None: ... -class _CDataMeta(type): - # By default mypy complains about the following two methods, because strictly speaking cls - # might not be a Type[_CT]. However this can never actually happen, because the only class that - # uses _CDataMeta as its metaclass is _CData. So it's safe to ignore the errors here. - def __mul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] - def __rmul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] +else: + def dlclose(handle: int, /) -> None: ... + # The default for flag is RTLD_GLOBAL|RTLD_LOCAL, which is platform dependent. + def dlopen(name: StrOrBytesPath, flag: int = ..., /) -> int: ... + def dlsym(handle: int, name: str, /) -> int: ... -class _CData(metaclass=_CDataMeta): +if sys.version_info >= (3, 13): + # This class is not exposed. It calls itself _ctypes.CType_Type. + @type_check_only + class _CType_Type(type): + # By default mypy complains about the following two methods, because strictly speaking cls + # might not be a Type[_CT]. However this doesn't happen because this is only a + # metaclass for subclasses of _CData. + def __mul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] + def __rmul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] + + _CTypeBaseType = _CType_Type + +else: + _CTypeBaseType = type + +# This class is not exposed. +@type_check_only +class _CData: _b_base_: int _b_needsfree_: bool _objects: Mapping[Any, int] | None - # At runtime the following classmethods are available only on classes, not - # on instances. This can't be reflected properly in the type system: - # - # Structure.from_buffer(...) # valid at runtime - # Structure(...).from_buffer(...) # invalid at runtime - # - @classmethod - def from_buffer(cls, source: WriteableBuffer, offset: int = ...) -> Self: ... - @classmethod - def from_buffer_copy(cls, source: ReadableBuffer, offset: int = ...) -> Self: ... - @classmethod - def from_address(cls, address: int) -> Self: ... - @classmethod - def from_param(cls, value: Any, /) -> Self | _CArgObject: ... - @classmethod - def in_dll(cls, library: CDLL, name: str) -> Self: ... def __buffer__(self, flags: int, /) -> memoryview: ... - def __release_buffer__(self, buffer: memoryview, /) -> None: ... + def __ctypes_from_outparam__(self, /) -> Self: ... -class _SimpleCData(_CData, Generic[_T]): +# this is a union of all the subclasses of _CData, which is useful because of +# the methods that are present on each of those subclasses which are not present +# on _CData itself. +_CDataType: TypeAlias = _SimpleCData[Any] | _Pointer[Any] | CFuncPtr | Union | Structure | Array[Any] + +# This class is not exposed. It calls itself _ctypes.PyCSimpleType. +@type_check_only +class _PyCSimpleType(_CTypeBaseType): + def from_address(self: type[_typeshed.Self], value: int, /) -> _typeshed.Self: ... + def from_buffer(self: type[_typeshed.Self], obj: WriteableBuffer, offset: int = 0, /) -> _typeshed.Self: ... + def from_buffer_copy(self: type[_typeshed.Self], buffer: ReadableBuffer, offset: int = 0, /) -> _typeshed.Self: ... + def from_param(self: type[_typeshed.Self], value: Any, /) -> _typeshed.Self | _CArgObject: ... + def in_dll(self: type[_typeshed.Self], dll: CDLL, name: str, /) -> _typeshed.Self: ... + if sys.version_info < (3, 13): + # Inherited from CType_Type starting on 3.13 + def __mul__(self: type[_CT], value: int, /) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] + def __rmul__(self: type[_CT], value: int, /) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] + +class _SimpleCData(_CData, Generic[_T], metaclass=_PyCSimpleType): value: _T # The TypeVar can be unsolved here, # but we can't use overloads without creating many, many mypy false-positive errors def __init__(self, value: _T = ...) -> None: ... # pyright: ignore[reportInvalidTypeVarUse] + def __ctypes_from_outparam__(self, /) -> _T: ... # type: ignore[override] class _CanCastTo(_CData): ... class _PointerLike(_CanCastTo): ... -class _Pointer(_PointerLike, _CData, Generic[_CT]): +# This type is not exposed. It calls itself _ctypes.PyCPointerType. +@type_check_only +class _PyCPointerType(_CTypeBaseType): + def from_address(self: type[_typeshed.Self], value: int, /) -> _typeshed.Self: ... + def from_buffer(self: type[_typeshed.Self], obj: WriteableBuffer, offset: int = 0, /) -> _typeshed.Self: ... + def from_buffer_copy(self: type[_typeshed.Self], buffer: ReadableBuffer, offset: int = 0, /) -> _typeshed.Self: ... + def from_param(self: type[_typeshed.Self], value: Any, /) -> _typeshed.Self | _CArgObject: ... + def in_dll(self: type[_typeshed.Self], dll: CDLL, name: str, /) -> _typeshed.Self: ... + def set_type(self, type: Any, /) -> None: ... + if sys.version_info < (3, 13): + # Inherited from CType_Type starting on 3.13 + def __mul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] + def __rmul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] + +class _Pointer(_PointerLike, _CData, Generic[_CT], metaclass=_PyCPointerType): _type_: type[_CT] contents: _CT @overload @@ -99,19 +133,38 @@ class _Pointer(_PointerLike, _CData, Generic[_CT]): def __getitem__(self, key: slice, /) -> list[Any]: ... def __setitem__(self, key: int, value: Any, /) -> None: ... +@overload +def POINTER(type: None, /) -> type[c_void_p]: ... +@overload def POINTER(type: type[_CT], /) -> type[_Pointer[_CT]]: ... def pointer(obj: _CT, /) -> _Pointer[_CT]: ... +# This class is not exposed. It calls itself _ctypes.CArgObject. +@final +@type_check_only class _CArgObject: ... -def byref(obj: _CData, offset: int = ...) -> _CArgObject: ... +def byref(obj: _CData | _CDataType, offset: int = ...) -> _CArgObject: ... -_ECT: TypeAlias = Callable[[_CData | None, CFuncPtr, tuple[_CData, ...]], _CData] +_ECT: TypeAlias = Callable[[_CData | _CDataType | None, CFuncPtr, tuple[_CData | _CDataType, ...]], _CDataType] _PF: TypeAlias = tuple[int] | tuple[int, str | None] | tuple[int, str | None, Any] -class CFuncPtr(_PointerLike, _CData): - restype: type[_CData] | Callable[[int], Any] | None - argtypes: Sequence[type[_CData]] +# This class is not exposed. It calls itself _ctypes.PyCFuncPtrType. +@type_check_only +class _PyCFuncPtrType(_CTypeBaseType): + def from_address(self: type[_typeshed.Self], value: int, /) -> _typeshed.Self: ... + def from_buffer(self: type[_typeshed.Self], obj: WriteableBuffer, offset: int = 0, /) -> _typeshed.Self: ... + def from_buffer_copy(self: type[_typeshed.Self], buffer: ReadableBuffer, offset: int = 0, /) -> _typeshed.Self: ... + def from_param(self: type[_typeshed.Self], value: Any, /) -> _typeshed.Self | _CArgObject: ... + def in_dll(self: type[_typeshed.Self], dll: CDLL, name: str, /) -> _typeshed.Self: ... + if sys.version_info < (3, 13): + # Inherited from CType_Type starting on 3.13 + def __mul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] + def __rmul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] + +class CFuncPtr(_PointerLike, _CData, metaclass=_PyCFuncPtrType): + restype: type[_CDataType] | Callable[[int], Any] | None + argtypes: Sequence[type[_CDataType]] errcheck: _ECT # Abstract attribute that must be defined on subclasses _flags_: ClassVar[int] @@ -126,7 +179,7 @@ class CFuncPtr(_PointerLike, _CData): if sys.platform == "win32": @overload def __init__( - self, vtbl_index: int, name: str, paramflags: tuple[_PF, ...] | None = ..., iid: _CData | None = ..., / + self, vtbl_index: int, name: str, paramflags: tuple[_PF, ...] | None = ..., iid: _CData | _CDataType | None = ..., / ) -> None: ... def __call__(self, *args: Any, **kwargs: Any) -> Any: ... @@ -134,30 +187,95 @@ class CFuncPtr(_PointerLike, _CData): _GetT = TypeVar("_GetT") _SetT = TypeVar("_SetT") +# This class is not exposed. It calls itself _ctypes.CField. +@final +@type_check_only class _CField(Generic[_CT, _GetT, _SetT]): offset: int size: int - @overload - def __get__(self, instance: None, owner: type[Any] | None, /) -> Self: ... - @overload - def __get__(self, instance: Any, owner: type[Any] | None, /) -> _GetT: ... + if sys.version_info >= (3, 10): + @overload + def __get__(self, instance: None, owner: type[Any] | None = None, /) -> Self: ... + @overload + def __get__(self, instance: Any, owner: type[Any] | None = None, /) -> _GetT: ... + else: + @overload + def __get__(self, instance: None, owner: type[Any] | None, /) -> Self: ... + @overload + def __get__(self, instance: Any, owner: type[Any] | None, /) -> _GetT: ... + def __set__(self, instance: Any, value: _SetT, /) -> None: ... -class _StructUnionMeta(_CDataMeta): - _fields_: Sequence[tuple[str, type[_CData]] | tuple[str, type[_CData], int]] - _pack_: int - _anonymous_: Sequence[str] +# This class is not exposed. It calls itself _ctypes.UnionType. +@type_check_only +class _UnionType(_CTypeBaseType): + def from_address(self: type[_typeshed.Self], value: int, /) -> _typeshed.Self: ... + def from_buffer(self: type[_typeshed.Self], obj: WriteableBuffer, offset: int = 0, /) -> _typeshed.Self: ... + def from_buffer_copy(self: type[_typeshed.Self], buffer: ReadableBuffer, offset: int = 0, /) -> _typeshed.Self: ... + def from_param(self: type[_typeshed.Self], value: Any, /) -> _typeshed.Self | _CArgObject: ... + def in_dll(self: type[_typeshed.Self], dll: CDLL, name: str, /) -> _typeshed.Self: ... + # At runtime, various attributes are created on a Union subclass based + # on its _fields_. This method doesn't exist, but represents those + # dynamically created attributes. def __getattr__(self, name: str) -> _CField[Any, Any, Any]: ... + if sys.version_info < (3, 13): + # Inherited from CType_Type starting on 3.13 + def __mul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] + def __rmul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] + +class Union(_CData, metaclass=_UnionType): + _fields_: ClassVar[Sequence[tuple[str, type[_CDataType]] | tuple[str, type[_CDataType], int]]] + _pack_: ClassVar[int] + _anonymous_: ClassVar[Sequence[str]] + if sys.version_info >= (3, 13): + _align_: ClassVar[int] + + def __init__(self, *args: Any, **kw: Any) -> None: ... + def __getattr__(self, name: str) -> Any: ... + def __setattr__(self, name: str, value: Any) -> None: ... + +# This class is not exposed. It calls itself _ctypes.PyCStructType. +@type_check_only +class _PyCStructType(_CTypeBaseType): + def from_address(self: type[_typeshed.Self], value: int, /) -> _typeshed.Self: ... + def from_buffer(self: type[_typeshed.Self], obj: WriteableBuffer, offset: int = 0, /) -> _typeshed.Self: ... + def from_buffer_copy(self: type[_typeshed.Self], buffer: ReadableBuffer, offset: int = 0, /) -> _typeshed.Self: ... + def from_param(self: type[_typeshed.Self], value: Any, /) -> _typeshed.Self | _CArgObject: ... + def in_dll(self: type[_typeshed.Self], dll: CDLL, name: str, /) -> _typeshed.Self: ... + # At runtime, various attributes are created on a Structure subclass based + # on its _fields_. This method doesn't exist, but represents those + # dynamically created attributes. + def __getattr__(self, name: str) -> _CField[Any, Any, Any]: ... + if sys.version_info < (3, 13): + # Inherited from CType_Type starting on 3.13 + def __mul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] + def __rmul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] + +class Structure(_CData, metaclass=_PyCStructType): + _fields_: ClassVar[Sequence[tuple[str, type[_CDataType]] | tuple[str, type[_CDataType], int]]] + _pack_: ClassVar[int] + _anonymous_: ClassVar[Sequence[str]] + if sys.version_info >= (3, 13): + _align_: ClassVar[int] -class _StructUnionBase(_CData, metaclass=_StructUnionMeta): def __init__(self, *args: Any, **kw: Any) -> None: ... def __getattr__(self, name: str) -> Any: ... def __setattr__(self, name: str, value: Any) -> None: ... -class Union(_StructUnionBase): ... -class Structure(_StructUnionBase): ... +# This class is not exposed. It calls itself _ctypes.PyCArrayType. +@type_check_only +class _PyCArrayType(_CTypeBaseType): + def from_address(self: type[_typeshed.Self], value: int, /) -> _typeshed.Self: ... + def from_buffer(self: type[_typeshed.Self], obj: WriteableBuffer, offset: int = 0, /) -> _typeshed.Self: ... + def from_buffer_copy(self: type[_typeshed.Self], buffer: ReadableBuffer, offset: int = 0, /) -> _typeshed.Self: ... + def from_param(self: type[_typeshed.Self], value: Any, /) -> _typeshed.Self | _CArgObject: ... + def in_dll(self: type[_typeshed.Self], dll: CDLL, name: str, /) -> _typeshed.Self: ... + if sys.version_info < (3, 13): + # Inherited from CType_Type starting on 3.13 + def __mul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] + def __rmul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ... # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] -class Array(_CData, Generic[_CT]): +class Array(_CData, Generic[_CT], metaclass=_PyCArrayType): @property @abstractmethod def _length_(self) -> int: ... @@ -198,9 +316,15 @@ class Array(_CData, Generic[_CT]): if sys.version_info >= (3, 9): def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... -def addressof(obj: _CData, /) -> int: ... -def alignment(obj_or_type: _CData | type[_CData], /) -> int: ... +def addressof(obj: _CData | _CDataType, /) -> int: ... +def alignment(obj_or_type: _CData | _CDataType | type[_CData | _CDataType], /) -> int: ... def get_errno() -> int: ... -def resize(obj: _CData, size: int, /) -> None: ... +def resize(obj: _CData | _CDataType, size: int, /) -> None: ... def set_errno(value: int, /) -> int: ... -def sizeof(obj_or_type: _CData | type[_CData], /) -> int: ... +def sizeof(obj_or_type: _CData | _CDataType | type[_CData | _CDataType], /) -> int: ... +def PyObj_FromPtr(address: int, /) -> Any: ... +def Py_DECREF(o: _T, /) -> _T: ... +def Py_INCREF(o: _T, /) -> _T: ... +def buffer_info(o: _CData | _CDataType | type[_CData | _CDataType], /) -> tuple[str, int, tuple[int, ...]]: ... +def call_cdeclfunction(address: int, arguments: tuple[Any, ...], /) -> Any: ... +def call_function(address: int, arguments: tuple[Any, ...], /) -> Any: ... diff --git a/mypy/typeshed/stdlib/_curses.pyi b/mypy/typeshed/stdlib/_curses.pyi index b68c8925a041..9e06a1414da5 100644 --- a/mypy/typeshed/stdlib/_curses.pyi +++ b/mypy/typeshed/stdlib/_curses.pyi @@ -1,6 +1,7 @@ import sys from _typeshed import ReadOnlyBuffer, SupportsRead -from typing import IO, Any, NamedTuple, final, overload +from curses import _ncurses_version +from typing import IO, Any, final, overload from typing_extensions import TypeAlias # NOTE: This module is ordinarily only available on Unix, but the windows-curses @@ -298,7 +299,7 @@ if sys.version_info >= (3, 9): def getmouse() -> tuple[int, int, int, int, int]: ... def getsyx() -> tuple[int, int]: ... -def getwin(file: SupportsRead[bytes], /) -> _CursesWindow: ... +def getwin(file: SupportsRead[bytes], /) -> window: ... def halfdelay(tenths: int, /) -> None: ... def has_colors() -> bool: ... @@ -310,7 +311,7 @@ def has_il() -> bool: ... def has_key(key: int, /) -> bool: ... def init_color(color_number: int, r: int, g: int, b: int, /) -> None: ... def init_pair(pair_number: int, fg: int, bg: int, /) -> None: ... -def initscr() -> _CursesWindow: ... +def initscr() -> window: ... def intrflush(flag: bool, /) -> None: ... def is_term_resized(nlines: int, ncols: int, /) -> bool: ... def isendwin() -> bool: ... @@ -321,8 +322,8 @@ def meta(yes: bool, /) -> None: ... def mouseinterval(interval: int, /) -> None: ... def mousemask(newmask: int, /) -> tuple[int, int]: ... def napms(ms: int, /) -> int: ... -def newpad(nlines: int, ncols: int, /) -> _CursesWindow: ... -def newwin(nlines: int, ncols: int, begin_y: int = ..., begin_x: int = ..., /) -> _CursesWindow: ... +def newpad(nlines: int, ncols: int, /) -> window: ... +def newwin(nlines: int, ncols: int, begin_y: int = ..., begin_x: int = ..., /) -> window: ... def nl(flag: bool = True, /) -> None: ... def nocbreak() -> None: ... def noecho() -> None: ... @@ -378,7 +379,7 @@ def use_env(flag: bool, /) -> None: ... class error(Exception): ... @final -class _CursesWindow: +class window: # undocumented encoding: str @overload def addch(self, ch: _ChType, attr: int = ...) -> None: ... @@ -431,9 +432,9 @@ class _CursesWindow: def delch(self, y: int, x: int) -> None: ... def deleteln(self) -> None: ... @overload - def derwin(self, begin_y: int, begin_x: int) -> _CursesWindow: ... + def derwin(self, begin_y: int, begin_x: int) -> window: ... @overload - def derwin(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> _CursesWindow: ... + def derwin(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> window: ... def echochar(self, ch: _ChType, attr: int = ..., /) -> None: ... def enclose(self, y: int, x: int, /) -> bool: ... def erase(self) -> None: ... @@ -505,16 +506,16 @@ class _CursesWindow: @overload def noutrefresh(self, pminrow: int, pmincol: int, sminrow: int, smincol: int, smaxrow: int, smaxcol: int) -> None: ... @overload - def overlay(self, destwin: _CursesWindow) -> None: ... + def overlay(self, destwin: window) -> None: ... @overload def overlay( - self, destwin: _CursesWindow, sminrow: int, smincol: int, dminrow: int, dmincol: int, dmaxrow: int, dmaxcol: int + self, destwin: window, sminrow: int, smincol: int, dminrow: int, dmincol: int, dmaxrow: int, dmaxcol: int ) -> None: ... @overload - def overwrite(self, destwin: _CursesWindow) -> None: ... + def overwrite(self, destwin: window) -> None: ... @overload def overwrite( - self, destwin: _CursesWindow, sminrow: int, smincol: int, dminrow: int, dmincol: int, dmaxrow: int, dmaxcol: int + self, destwin: window, sminrow: int, smincol: int, dminrow: int, dmincol: int, dmaxrow: int, dmaxcol: int ) -> None: ... def putwin(self, file: IO[Any], /) -> None: ... def redrawln(self, beg: int, num: int, /) -> None: ... @@ -530,13 +531,13 @@ class _CursesWindow: def standend(self) -> None: ... def standout(self) -> None: ... @overload - def subpad(self, begin_y: int, begin_x: int) -> _CursesWindow: ... + def subpad(self, begin_y: int, begin_x: int) -> window: ... @overload - def subpad(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> _CursesWindow: ... + def subpad(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> window: ... @overload - def subwin(self, begin_y: int, begin_x: int) -> _CursesWindow: ... + def subwin(self, begin_y: int, begin_x: int) -> window: ... @overload - def subwin(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> _CursesWindow: ... + def subwin(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> window: ... def syncdown(self) -> None: ... def syncok(self, flag: bool) -> None: ... def syncup(self) -> None: ... @@ -549,10 +550,4 @@ class _CursesWindow: @overload def vline(self, y: int, x: int, ch: _ChType, n: int) -> None: ... -class _ncurses_version(NamedTuple): - major: int - minor: int - patch: int - ncurses_version: _ncurses_version -window = _CursesWindow # undocumented diff --git a/mypy/typeshed/stdlib/_curses_panel.pyi b/mypy/typeshed/stdlib/_curses_panel.pyi new file mode 100644 index 000000000000..ddec22236b96 --- /dev/null +++ b/mypy/typeshed/stdlib/_curses_panel.pyi @@ -0,0 +1,27 @@ +from _curses import window +from typing import final + +__version__: str +version: str + +class error(Exception): ... + +@final +class panel: + def above(self) -> panel: ... + def below(self) -> panel: ... + def bottom(self) -> None: ... + def hidden(self) -> bool: ... + def hide(self) -> None: ... + def move(self, y: int, x: int, /) -> None: ... + def replace(self, win: window, /) -> None: ... + def set_userptr(self, obj: object, /) -> None: ... + def show(self) -> None: ... + def top(self) -> None: ... + def userptr(self) -> object: ... + def window(self) -> window: ... + +def bottom_panel() -> panel: ... +def new_panel(win: window, /) -> panel: ... +def top_panel() -> panel: ... +def update_panels() -> panel: ... diff --git a/mypy/typeshed/stdlib/_dbm.pyi b/mypy/typeshed/stdlib/_dbm.pyi new file mode 100644 index 000000000000..7e53cca3c704 --- /dev/null +++ b/mypy/typeshed/stdlib/_dbm.pyi @@ -0,0 +1,44 @@ +import sys +from _typeshed import ReadOnlyBuffer, StrOrBytesPath +from types import TracebackType +from typing import TypeVar, final, overload, type_check_only +from typing_extensions import Self, TypeAlias + +if sys.platform != "win32": + _T = TypeVar("_T") + _KeyType: TypeAlias = str | ReadOnlyBuffer + _ValueType: TypeAlias = str | ReadOnlyBuffer + + class error(OSError): ... + library: str + + # Actual typename dbm, not exposed by the implementation + @final + @type_check_only + class _dbm: + def close(self) -> None: ... + if sys.version_info >= (3, 13): + def clear(self) -> None: ... + + def __getitem__(self, item: _KeyType) -> bytes: ... + def __setitem__(self, key: _KeyType, value: _ValueType) -> None: ... + def __delitem__(self, key: _KeyType) -> None: ... + def __len__(self) -> int: ... + def __enter__(self) -> Self: ... + def __exit__( + self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None + ) -> None: ... + @overload + def get(self, k: _KeyType, /) -> bytes | None: ... + @overload + def get(self, k: _KeyType, default: _T, /) -> bytes | _T: ... + def keys(self) -> list[bytes]: ... + def setdefault(self, k: _KeyType, default: _ValueType = ..., /) -> bytes: ... + # This isn't true, but the class can't be instantiated. See #13024 + __new__: None # type: ignore[assignment] + __init__: None # type: ignore[assignment] + + if sys.version_info >= (3, 11): + def open(filename: StrOrBytesPath, flags: str = "r", mode: int = 0o666, /) -> _dbm: ... + else: + def open(filename: str, flags: str = "r", mode: int = 0o666, /) -> _dbm: ... diff --git a/mypy/typeshed/stdlib/_decimal.pyi b/mypy/typeshed/stdlib/_decimal.pyi index 937a04ac3799..cdd0268a1bdf 100644 --- a/mypy/typeshed/stdlib/_decimal.pyi +++ b/mypy/typeshed/stdlib/_decimal.pyi @@ -1,22 +1,32 @@ -import numbers import sys -from collections.abc import Container, Sequence -from types import TracebackType -from typing import Any, ClassVar, Final, Literal, NamedTuple, overload -from typing_extensions import Self, TypeAlias +from decimal import ( + Clamped as Clamped, + Context as Context, + ConversionSyntax as ConversionSyntax, + Decimal as Decimal, + DecimalException as DecimalException, + DecimalTuple as DecimalTuple, + DivisionByZero as DivisionByZero, + DivisionImpossible as DivisionImpossible, + DivisionUndefined as DivisionUndefined, + FloatOperation as FloatOperation, + Inexact as Inexact, + InvalidContext as InvalidContext, + InvalidOperation as InvalidOperation, + Overflow as Overflow, + Rounded as Rounded, + Subnormal as Subnormal, + Underflow as Underflow, + _ContextManager, +) +from typing import Final +from typing_extensions import TypeAlias -_Decimal: TypeAlias = Decimal | int -_DecimalNew: TypeAlias = Decimal | float | str | tuple[int, Sequence[int], int] -_ComparableNum: TypeAlias = Decimal | float | numbers.Rational +_TrapType: TypeAlias = type[DecimalException] __version__: Final[str] __libmpdec_version__: Final[str] -class DecimalTuple(NamedTuple): - sign: int - digits: tuple[int, ...] - exponent: int | Literal["n", "N", "F"] - ROUND_DOWN: Final[str] ROUND_HALF_UP: Final[str] ROUND_HALF_EVEN: Final[str] @@ -32,21 +42,6 @@ MAX_PREC: Final[int] MIN_EMIN: Final[int] MIN_ETINY: Final[int] -class DecimalException(ArithmeticError): ... -class Clamped(DecimalException): ... -class InvalidOperation(DecimalException): ... -class ConversionSyntax(InvalidOperation): ... -class DivisionByZero(DecimalException, ZeroDivisionError): ... -class DivisionImpossible(InvalidOperation): ... -class DivisionUndefined(InvalidOperation, ZeroDivisionError): ... -class Inexact(DecimalException): ... -class InvalidContext(InvalidOperation): ... -class Rounded(DecimalException): ... -class Subnormal(DecimalException): ... -class Overflow(Inexact, Rounded): ... -class Underflow(Inexact, Rounded, Subnormal): ... -class FloatOperation(DecimalException, TypeError): ... - def setcontext(context: Context, /) -> None: ... def getcontext() -> Context: ... @@ -67,215 +62,6 @@ if sys.version_info >= (3, 11): else: def localcontext(ctx: Context | None = None) -> _ContextManager: ... -class Decimal: - def __new__(cls, value: _DecimalNew = ..., context: Context | None = ...) -> Self: ... - @classmethod - def from_float(cls, f: float, /) -> Self: ... - def __bool__(self) -> bool: ... - def compare(self, other: _Decimal, context: Context | None = None) -> Decimal: ... - def __hash__(self) -> int: ... - def as_tuple(self) -> DecimalTuple: ... - def as_integer_ratio(self) -> tuple[int, int]: ... - def to_eng_string(self, context: Context | None = None) -> str: ... - def __abs__(self) -> Decimal: ... - def __add__(self, value: _Decimal, /) -> Decimal: ... - def __divmod__(self, value: _Decimal, /) -> tuple[Decimal, Decimal]: ... - def __eq__(self, value: object, /) -> bool: ... - def __floordiv__(self, value: _Decimal, /) -> Decimal: ... - def __ge__(self, value: _ComparableNum, /) -> bool: ... - def __gt__(self, value: _ComparableNum, /) -> bool: ... - def __le__(self, value: _ComparableNum, /) -> bool: ... - def __lt__(self, value: _ComparableNum, /) -> bool: ... - def __mod__(self, value: _Decimal, /) -> Decimal: ... - def __mul__(self, value: _Decimal, /) -> Decimal: ... - def __neg__(self) -> Decimal: ... - def __pos__(self) -> Decimal: ... - def __pow__(self, value: _Decimal, mod: _Decimal | None = None, /) -> Decimal: ... - def __radd__(self, value: _Decimal, /) -> Decimal: ... - def __rdivmod__(self, value: _Decimal, /) -> tuple[Decimal, Decimal]: ... - def __rfloordiv__(self, value: _Decimal, /) -> Decimal: ... - def __rmod__(self, value: _Decimal, /) -> Decimal: ... - def __rmul__(self, value: _Decimal, /) -> Decimal: ... - def __rsub__(self, value: _Decimal, /) -> Decimal: ... - def __rtruediv__(self, value: _Decimal, /) -> Decimal: ... - def __sub__(self, value: _Decimal, /) -> Decimal: ... - def __truediv__(self, value: _Decimal, /) -> Decimal: ... - def remainder_near(self, other: _Decimal, context: Context | None = None) -> Decimal: ... - def __float__(self) -> float: ... - def __int__(self) -> int: ... - def __trunc__(self) -> int: ... - @property - def real(self) -> Decimal: ... - @property - def imag(self) -> Decimal: ... - def conjugate(self) -> Decimal: ... - def __complex__(self) -> complex: ... - @overload - def __round__(self) -> int: ... - @overload - def __round__(self, ndigits: int, /) -> Decimal: ... - def __floor__(self) -> int: ... - def __ceil__(self) -> int: ... - def fma(self, other: _Decimal, third: _Decimal, context: Context | None = None) -> Decimal: ... - def __rpow__(self, value: _Decimal, mod: Context | None = None, /) -> Decimal: ... - def normalize(self, context: Context | None = None) -> Decimal: ... - def quantize(self, exp: _Decimal, rounding: str | None = None, context: Context | None = None) -> Decimal: ... - def same_quantum(self, other: _Decimal, context: Context | None = None) -> bool: ... - def to_integral_exact(self, rounding: str | None = None, context: Context | None = None) -> Decimal: ... - def to_integral_value(self, rounding: str | None = None, context: Context | None = None) -> Decimal: ... - def to_integral(self, rounding: str | None = None, context: Context | None = None) -> Decimal: ... - def sqrt(self, context: Context | None = None) -> Decimal: ... - def max(self, other: _Decimal, context: Context | None = None) -> Decimal: ... - def min(self, other: _Decimal, context: Context | None = None) -> Decimal: ... - def adjusted(self) -> int: ... - def canonical(self) -> Decimal: ... - def compare_signal(self, other: _Decimal, context: Context | None = None) -> Decimal: ... - def compare_total(self, other: _Decimal, context: Context | None = None) -> Decimal: ... - def compare_total_mag(self, other: _Decimal, context: Context | None = None) -> Decimal: ... - def copy_abs(self) -> Decimal: ... - def copy_negate(self) -> Decimal: ... - def copy_sign(self, other: _Decimal, context: Context | None = None) -> Decimal: ... - def exp(self, context: Context | None = None) -> Decimal: ... - def is_canonical(self) -> bool: ... - def is_finite(self) -> bool: ... - def is_infinite(self) -> bool: ... - def is_nan(self) -> bool: ... - def is_normal(self, context: Context | None = None) -> bool: ... - def is_qnan(self) -> bool: ... - def is_signed(self) -> bool: ... - def is_snan(self) -> bool: ... - def is_subnormal(self, context: Context | None = None) -> bool: ... - def is_zero(self) -> bool: ... - def ln(self, context: Context | None = None) -> Decimal: ... - def log10(self, context: Context | None = None) -> Decimal: ... - def logb(self, context: Context | None = None) -> Decimal: ... - def logical_and(self, other: _Decimal, context: Context | None = None) -> Decimal: ... - def logical_invert(self, context: Context | None = None) -> Decimal: ... - def logical_or(self, other: _Decimal, context: Context | None = None) -> Decimal: ... - def logical_xor(self, other: _Decimal, context: Context | None = None) -> Decimal: ... - def max_mag(self, other: _Decimal, context: Context | None = None) -> Decimal: ... - def min_mag(self, other: _Decimal, context: Context | None = None) -> Decimal: ... - def next_minus(self, context: Context | None = None) -> Decimal: ... - def next_plus(self, context: Context | None = None) -> Decimal: ... - def next_toward(self, other: _Decimal, context: Context | None = None) -> Decimal: ... - def number_class(self, context: Context | None = None) -> str: ... - def radix(self) -> Decimal: ... - def rotate(self, other: _Decimal, context: Context | None = None) -> Decimal: ... - def scaleb(self, other: _Decimal, context: Context | None = None) -> Decimal: ... - def shift(self, other: _Decimal, context: Context | None = None) -> Decimal: ... - def __reduce__(self) -> tuple[type[Self], tuple[str]]: ... - def __copy__(self) -> Self: ... - def __deepcopy__(self, memo: Any, /) -> Self: ... - def __format__(self, specifier: str, context: Context | None = ..., /) -> str: ... - -class _ContextManager: - new_context: Context - saved_context: Context - def __init__(self, new_context: Context) -> None: ... - def __enter__(self) -> Context: ... - def __exit__(self, t: type[BaseException] | None, v: BaseException | None, tb: TracebackType | None) -> None: ... - -_TrapType: TypeAlias = type[DecimalException] - -class Context: - # TODO: Context doesn't allow you to delete *any* attributes from instances of the class at runtime, - # even settable attributes like `prec` and `rounding`, - # but that's inexpressable in the stub. - # Type checkers either ignore it or misinterpret it - # if you add a `def __delattr__(self, name: str, /) -> NoReturn` method to the stub - prec: int - rounding: str - Emin: int - Emax: int - capitals: int - clamp: int - traps: dict[_TrapType, bool] - flags: dict[_TrapType, bool] - def __init__( - self, - prec: int | None = ..., - rounding: str | None = ..., - Emin: int | None = ..., - Emax: int | None = ..., - capitals: int | None = ..., - clamp: int | None = ..., - flags: None | dict[_TrapType, bool] | Container[_TrapType] = ..., - traps: None | dict[_TrapType, bool] | Container[_TrapType] = ..., - _ignored_flags: list[_TrapType] | None = ..., - ) -> None: ... - def __reduce__(self) -> tuple[type[Self], tuple[Any, ...]]: ... - def clear_flags(self) -> None: ... - def clear_traps(self) -> None: ... - def copy(self) -> Context: ... - def __copy__(self) -> Context: ... - # see https://github.com/python/cpython/issues/94107 - __hash__: ClassVar[None] # type: ignore[assignment] - def Etiny(self) -> int: ... - def Etop(self) -> int: ... - def create_decimal(self, num: _DecimalNew = "0", /) -> Decimal: ... - def create_decimal_from_float(self, f: float, /) -> Decimal: ... - def abs(self, x: _Decimal, /) -> Decimal: ... - def add(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... - def canonical(self, x: Decimal, /) -> Decimal: ... - def compare(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... - def compare_signal(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... - def compare_total(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... - def compare_total_mag(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... - def copy_abs(self, x: _Decimal, /) -> Decimal: ... - def copy_decimal(self, x: _Decimal, /) -> Decimal: ... - def copy_negate(self, x: _Decimal, /) -> Decimal: ... - def copy_sign(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... - def divide(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... - def divide_int(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... - def divmod(self, x: _Decimal, y: _Decimal, /) -> tuple[Decimal, Decimal]: ... - def exp(self, x: _Decimal, /) -> Decimal: ... - def fma(self, x: _Decimal, y: _Decimal, z: _Decimal, /) -> Decimal: ... - def is_canonical(self, x: _Decimal, /) -> bool: ... - def is_finite(self, x: _Decimal, /) -> bool: ... - def is_infinite(self, x: _Decimal, /) -> bool: ... - def is_nan(self, x: _Decimal, /) -> bool: ... - def is_normal(self, x: _Decimal, /) -> bool: ... - def is_qnan(self, x: _Decimal, /) -> bool: ... - def is_signed(self, x: _Decimal, /) -> bool: ... - def is_snan(self, x: _Decimal, /) -> bool: ... - def is_subnormal(self, x: _Decimal, /) -> bool: ... - def is_zero(self, x: _Decimal, /) -> bool: ... - def ln(self, x: _Decimal, /) -> Decimal: ... - def log10(self, x: _Decimal, /) -> Decimal: ... - def logb(self, x: _Decimal, /) -> Decimal: ... - def logical_and(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... - def logical_invert(self, x: _Decimal, /) -> Decimal: ... - def logical_or(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... - def logical_xor(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... - def max(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... - def max_mag(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... - def min(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... - def min_mag(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... - def minus(self, x: _Decimal, /) -> Decimal: ... - def multiply(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... - def next_minus(self, x: _Decimal, /) -> Decimal: ... - def next_plus(self, x: _Decimal, /) -> Decimal: ... - def next_toward(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... - def normalize(self, x: _Decimal, /) -> Decimal: ... - def number_class(self, x: _Decimal, /) -> str: ... - def plus(self, x: _Decimal, /) -> Decimal: ... - def power(self, a: _Decimal, b: _Decimal, modulo: _Decimal | None = None) -> Decimal: ... - def quantize(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... - def radix(self) -> Decimal: ... - def remainder(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... - def remainder_near(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... - def rotate(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... - def same_quantum(self, x: _Decimal, y: _Decimal, /) -> bool: ... - def scaleb(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... - def shift(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... - def sqrt(self, x: _Decimal, /) -> Decimal: ... - def subtract(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... - def to_eng_string(self, x: _Decimal, /) -> str: ... - def to_sci_string(self, x: _Decimal, /) -> str: ... - def to_integral_exact(self, x: _Decimal, /) -> Decimal: ... - def to_integral_value(self, x: _Decimal, /) -> Decimal: ... - def to_integral(self, x: _Decimal, /) -> Decimal: ... - DefaultContext: Context BasicContext: Context ExtendedContext: Context diff --git a/mypy/typeshed/stdlib/_frozen_importlib.pyi b/mypy/typeshed/stdlib/_frozen_importlib.pyi new file mode 100644 index 000000000000..b6d7a1842048 --- /dev/null +++ b/mypy/typeshed/stdlib/_frozen_importlib.pyi @@ -0,0 +1,112 @@ +import importlib.abc +import importlib.machinery +import sys +import types +from _typeshed.importlib import LoaderProtocol +from collections.abc import Mapping, Sequence +from types import ModuleType +from typing import Any + +# Signature of `builtins.__import__` should be kept identical to `importlib.__import__` +def __import__( + name: str, + globals: Mapping[str, object] | None = None, + locals: Mapping[str, object] | None = None, + fromlist: Sequence[str] = (), + level: int = 0, +) -> ModuleType: ... +def spec_from_loader( + name: str, loader: LoaderProtocol | None, *, origin: str | None = None, is_package: bool | None = None +) -> importlib.machinery.ModuleSpec | None: ... +def module_from_spec(spec: importlib.machinery.ModuleSpec) -> types.ModuleType: ... +def _init_module_attrs( + spec: importlib.machinery.ModuleSpec, module: types.ModuleType, *, override: bool = False +) -> types.ModuleType: ... + +class ModuleSpec: + def __init__( + self, + name: str, + loader: importlib.abc.Loader | None, + *, + origin: str | None = None, + loader_state: Any = None, + is_package: bool | None = None, + ) -> None: ... + name: str + loader: importlib.abc.Loader | None + origin: str | None + submodule_search_locations: list[str] | None + loader_state: Any + cached: str | None + @property + def parent(self) -> str | None: ... + has_location: bool + def __eq__(self, other: object) -> bool: ... + +class BuiltinImporter(importlib.abc.MetaPathFinder, importlib.abc.InspectLoader): + # MetaPathFinder + if sys.version_info < (3, 12): + @classmethod + def find_module(cls, fullname: str, path: Sequence[str] | None = None) -> importlib.abc.Loader | None: ... + + @classmethod + def find_spec( + cls, fullname: str, path: Sequence[str] | None = None, target: types.ModuleType | None = None + ) -> ModuleSpec | None: ... + # InspectLoader + @classmethod + def is_package(cls, fullname: str) -> bool: ... + @classmethod + def load_module(cls, fullname: str) -> types.ModuleType: ... + @classmethod + def get_code(cls, fullname: str) -> None: ... + @classmethod + def get_source(cls, fullname: str) -> None: ... + # Loader + if sys.version_info < (3, 12): + @staticmethod + def module_repr(module: types.ModuleType) -> str: ... + if sys.version_info >= (3, 10): + @staticmethod + def create_module(spec: ModuleSpec) -> types.ModuleType | None: ... + @staticmethod + def exec_module(module: types.ModuleType) -> None: ... + else: + @classmethod + def create_module(cls, spec: ModuleSpec) -> types.ModuleType | None: ... + @classmethod + def exec_module(cls, module: types.ModuleType) -> None: ... + +class FrozenImporter(importlib.abc.MetaPathFinder, importlib.abc.InspectLoader): + # MetaPathFinder + if sys.version_info < (3, 12): + @classmethod + def find_module(cls, fullname: str, path: Sequence[str] | None = None) -> importlib.abc.Loader | None: ... + + @classmethod + def find_spec( + cls, fullname: str, path: Sequence[str] | None = None, target: types.ModuleType | None = None + ) -> ModuleSpec | None: ... + # InspectLoader + @classmethod + def is_package(cls, fullname: str) -> bool: ... + @classmethod + def load_module(cls, fullname: str) -> types.ModuleType: ... + @classmethod + def get_code(cls, fullname: str) -> None: ... + @classmethod + def get_source(cls, fullname: str) -> None: ... + # Loader + if sys.version_info < (3, 12): + @staticmethod + def module_repr(m: types.ModuleType) -> str: ... + if sys.version_info >= (3, 10): + @staticmethod + def create_module(spec: ModuleSpec) -> types.ModuleType | None: ... + else: + @classmethod + def create_module(cls, spec: ModuleSpec) -> types.ModuleType | None: ... + + @staticmethod + def exec_module(module: types.ModuleType) -> None: ... diff --git a/mypy/typeshed/stdlib/_frozen_importlib_external.pyi b/mypy/typeshed/stdlib/_frozen_importlib_external.pyi new file mode 100644 index 000000000000..d3127666da30 --- /dev/null +++ b/mypy/typeshed/stdlib/_frozen_importlib_external.pyi @@ -0,0 +1,178 @@ +import _ast +import _io +import importlib.abc +import importlib.machinery +import sys +import types +from _typeshed import ReadableBuffer, StrOrBytesPath, StrPath +from _typeshed.importlib import LoaderProtocol +from collections.abc import Callable, Iterable, Iterator, Mapping, MutableSequence, Sequence +from importlib.machinery import ModuleSpec +from importlib.metadata import DistributionFinder, PathDistribution +from typing import Any, Literal +from typing_extensions import Self, deprecated + +if sys.version_info >= (3, 10): + import importlib.readers + +if sys.platform == "win32": + path_separators: Literal["\\/"] + path_sep: Literal["\\"] + path_sep_tuple: tuple[Literal["\\"], Literal["/"]] +else: + path_separators: Literal["/"] + path_sep: Literal["/"] + path_sep_tuple: tuple[Literal["/"]] + +MAGIC_NUMBER: bytes + +def cache_from_source(path: str, debug_override: bool | None = None, *, optimization: Any | None = None) -> str: ... +def source_from_cache(path: str) -> str: ... +def decode_source(source_bytes: ReadableBuffer) -> str: ... +def spec_from_file_location( + name: str, + location: StrOrBytesPath | None = None, + *, + loader: LoaderProtocol | None = None, + submodule_search_locations: list[str] | None = ..., +) -> importlib.machinery.ModuleSpec | None: ... + +class WindowsRegistryFinder(importlib.abc.MetaPathFinder): + if sys.version_info < (3, 12): + @classmethod + def find_module(cls, fullname: str, path: Sequence[str] | None = None) -> importlib.abc.Loader | None: ... + + @classmethod + def find_spec( + cls, fullname: str, path: Sequence[str] | None = None, target: types.ModuleType | None = None + ) -> ModuleSpec | None: ... + +class PathFinder(importlib.abc.MetaPathFinder): + if sys.version_info >= (3, 10): + @staticmethod + def invalidate_caches() -> None: ... + else: + @classmethod + def invalidate_caches(cls) -> None: ... + if sys.version_info >= (3, 10): + @staticmethod + def find_distributions(context: DistributionFinder.Context = ...) -> Iterable[PathDistribution]: ... + else: + @classmethod + def find_distributions(cls, context: DistributionFinder.Context = ...) -> Iterable[PathDistribution]: ... + + @classmethod + def find_spec( + cls, fullname: str, path: Sequence[str] | None = None, target: types.ModuleType | None = None + ) -> ModuleSpec | None: ... + if sys.version_info < (3, 12): + @classmethod + def find_module(cls, fullname: str, path: Sequence[str] | None = None) -> importlib.abc.Loader | None: ... + +SOURCE_SUFFIXES: list[str] +DEBUG_BYTECODE_SUFFIXES: list[str] +OPTIMIZED_BYTECODE_SUFFIXES: list[str] +BYTECODE_SUFFIXES: list[str] +EXTENSION_SUFFIXES: list[str] + +class FileFinder(importlib.abc.PathEntryFinder): + path: str + def __init__(self, path: str, *loader_details: tuple[type[importlib.abc.Loader], list[str]]) -> None: ... + @classmethod + def path_hook( + cls, *loader_details: tuple[type[importlib.abc.Loader], list[str]] + ) -> Callable[[str], importlib.abc.PathEntryFinder]: ... + +class _LoaderBasics: + def is_package(self, fullname: str) -> bool: ... + def create_module(self, spec: ModuleSpec) -> types.ModuleType | None: ... + def exec_module(self, module: types.ModuleType) -> None: ... + def load_module(self, fullname: str) -> types.ModuleType: ... + +class SourceLoader(_LoaderBasics): + def path_mtime(self, path: str) -> float: ... + def set_data(self, path: str, data: bytes) -> None: ... + def get_source(self, fullname: str) -> str | None: ... + def path_stats(self, path: str) -> Mapping[str, Any]: ... + def source_to_code( + self, data: ReadableBuffer | str | _ast.Module | _ast.Expression | _ast.Interactive, path: ReadableBuffer | StrPath + ) -> types.CodeType: ... + def get_code(self, fullname: str) -> types.CodeType | None: ... + +class FileLoader: + name: str + path: str + def __init__(self, fullname: str, path: str) -> None: ... + def get_data(self, path: str) -> bytes: ... + def get_filename(self, name: str | None = None) -> str: ... + def load_module(self, name: str | None = None) -> types.ModuleType: ... + if sys.version_info >= (3, 10): + def get_resource_reader(self, name: str | None = None) -> importlib.readers.FileReader: ... + else: + def get_resource_reader(self, name: str | None = None) -> Self | None: ... + def open_resource(self, resource: str) -> _io.FileIO: ... + def resource_path(self, resource: str) -> str: ... + def is_resource(self, name: str) -> bool: ... + def contents(self) -> Iterator[str]: ... + +class SourceFileLoader(importlib.abc.FileLoader, FileLoader, importlib.abc.SourceLoader, SourceLoader): # type: ignore[misc] # incompatible method arguments in base classes + def set_data(self, path: str, data: ReadableBuffer, *, _mode: int = 0o666) -> None: ... + def path_stats(self, path: str) -> Mapping[str, Any]: ... + +class SourcelessFileLoader(importlib.abc.FileLoader, FileLoader, _LoaderBasics): + def get_code(self, fullname: str) -> types.CodeType | None: ... + def get_source(self, fullname: str) -> None: ... + +class ExtensionFileLoader(FileLoader, _LoaderBasics, importlib.abc.ExecutionLoader): + def __init__(self, name: str, path: str) -> None: ... + def get_filename(self, name: str | None = None) -> str: ... + def get_source(self, fullname: str) -> None: ... + def create_module(self, spec: ModuleSpec) -> types.ModuleType: ... + def exec_module(self, module: types.ModuleType) -> None: ... + def get_code(self, fullname: str) -> None: ... + def __eq__(self, other: object) -> bool: ... + def __hash__(self) -> int: ... + +if sys.version_info >= (3, 11): + class NamespaceLoader(importlib.abc.InspectLoader): + def __init__( + self, name: str, path: MutableSequence[str], path_finder: Callable[[str, tuple[str, ...]], ModuleSpec] + ) -> None: ... + def is_package(self, fullname: str) -> Literal[True]: ... + def get_source(self, fullname: str) -> Literal[""]: ... + def get_code(self, fullname: str) -> types.CodeType: ... + def create_module(self, spec: ModuleSpec) -> None: ... + def exec_module(self, module: types.ModuleType) -> None: ... + @deprecated("load_module() is deprecated; use exec_module() instead") + def load_module(self, fullname: str) -> types.ModuleType: ... + def get_resource_reader(self, module: types.ModuleType) -> importlib.readers.NamespaceReader: ... + if sys.version_info < (3, 12): + @staticmethod + @deprecated("module_repr() is deprecated, and has been removed in Python 3.12") + def module_repr(module: types.ModuleType) -> str: ... + + _NamespaceLoader = NamespaceLoader +else: + class _NamespaceLoader: + def __init__( + self, name: str, path: MutableSequence[str], path_finder: Callable[[str, tuple[str, ...]], ModuleSpec] + ) -> None: ... + def is_package(self, fullname: str) -> Literal[True]: ... + def get_source(self, fullname: str) -> Literal[""]: ... + def get_code(self, fullname: str) -> types.CodeType: ... + def create_module(self, spec: ModuleSpec) -> None: ... + def exec_module(self, module: types.ModuleType) -> None: ... + @deprecated("load_module() is deprecated; use exec_module() instead") + def load_module(self, fullname: str) -> types.ModuleType: ... + if sys.version_info >= (3, 10): + @staticmethod + @deprecated("module_repr() is deprecated, and has been removed in Python 3.12") + def module_repr(module: types.ModuleType) -> str: ... + def get_resource_reader(self, module: types.ModuleType) -> importlib.readers.NamespaceReader: ... + else: + @classmethod + @deprecated("module_repr() is deprecated, and has been removed in Python 3.12") + def module_repr(cls, module: types.ModuleType) -> str: ... + +if sys.version_info >= (3, 13): + class AppleFrameworkLoader(ExtensionFileLoader, importlib.abc.ExecutionLoader): ... diff --git a/mypy/typeshed/stdlib/_gdbm.pyi b/mypy/typeshed/stdlib/_gdbm.pyi new file mode 100644 index 000000000000..1d1d541f5477 --- /dev/null +++ b/mypy/typeshed/stdlib/_gdbm.pyi @@ -0,0 +1,47 @@ +import sys +from _typeshed import ReadOnlyBuffer, StrOrBytesPath +from types import TracebackType +from typing import TypeVar, overload +from typing_extensions import Self, TypeAlias + +if sys.platform != "win32": + _T = TypeVar("_T") + _KeyType: TypeAlias = str | ReadOnlyBuffer + _ValueType: TypeAlias = str | ReadOnlyBuffer + + open_flags: str + + class error(OSError): ... + # Actual typename gdbm, not exposed by the implementation + class _gdbm: + def firstkey(self) -> bytes | None: ... + def nextkey(self, key: _KeyType) -> bytes | None: ... + def reorganize(self) -> None: ... + def sync(self) -> None: ... + def close(self) -> None: ... + if sys.version_info >= (3, 13): + def clear(self) -> None: ... + + def __getitem__(self, item: _KeyType) -> bytes: ... + def __setitem__(self, key: _KeyType, value: _ValueType) -> None: ... + def __delitem__(self, key: _KeyType) -> None: ... + def __contains__(self, key: _KeyType) -> bool: ... + def __len__(self) -> int: ... + def __enter__(self) -> Self: ... + def __exit__( + self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None + ) -> None: ... + @overload + def get(self, k: _KeyType) -> bytes | None: ... + @overload + def get(self, k: _KeyType, default: _T) -> bytes | _T: ... + def keys(self) -> list[bytes]: ... + def setdefault(self, k: _KeyType, default: _ValueType = ...) -> bytes: ... + # Don't exist at runtime + __new__: None # type: ignore[assignment] + __init__: None # type: ignore[assignment] + + if sys.version_info >= (3, 11): + def open(filename: StrOrBytesPath, flags: str = "r", mode: int = 0o666, /) -> _gdbm: ... + else: + def open(filename: str, flags: str = "r", mode: int = 0o666, /) -> _gdbm: ... diff --git a/mypy/typeshed/stdlib/_hashlib.pyi b/mypy/typeshed/stdlib/_hashlib.pyi new file mode 100644 index 000000000000..5cf85e4cacaa --- /dev/null +++ b/mypy/typeshed/stdlib/_hashlib.pyi @@ -0,0 +1,80 @@ +import sys +from _typeshed import ReadableBuffer +from collections.abc import Callable +from types import ModuleType +from typing import AnyStr, final, overload +from typing_extensions import Self, TypeAlias + +_DigestMod: TypeAlias = str | Callable[[], HASH] | ModuleType | None + +openssl_md_meth_names: frozenset[str] + +class HASH: + @property + def digest_size(self) -> int: ... + @property + def block_size(self) -> int: ... + @property + def name(self) -> str: ... + def copy(self) -> Self: ... + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def update(self, obj: ReadableBuffer, /) -> None: ... + +if sys.version_info >= (3, 10): + class UnsupportedDigestmodError(ValueError): ... + +if sys.version_info >= (3, 9): + class HASHXOF(HASH): + def digest(self, length: int) -> bytes: ... # type: ignore[override] + def hexdigest(self, length: int) -> str: ... # type: ignore[override] + + @final + class HMAC: + @property + def digest_size(self) -> int: ... + @property + def block_size(self) -> int: ... + @property + def name(self) -> str: ... + def copy(self) -> Self: ... + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def update(self, msg: ReadableBuffer) -> None: ... + + @overload + def compare_digest(a: ReadableBuffer, b: ReadableBuffer, /) -> bool: ... + @overload + def compare_digest(a: AnyStr, b: AnyStr, /) -> bool: ... + def get_fips_mode() -> int: ... + def hmac_new(key: bytes | bytearray, msg: ReadableBuffer = b"", digestmod: _DigestMod = None) -> HMAC: ... + def new(name: str, string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ... + def openssl_md5(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ... + def openssl_sha1(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ... + def openssl_sha224(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ... + def openssl_sha256(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ... + def openssl_sha384(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ... + def openssl_sha512(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ... + def openssl_sha3_224(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ... + def openssl_sha3_256(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ... + def openssl_sha3_384(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ... + def openssl_sha3_512(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASH: ... + def openssl_shake_128(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASHXOF: ... + def openssl_shake_256(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> HASHXOF: ... + +else: + def new(name: str, string: ReadableBuffer = b"") -> HASH: ... + def openssl_md5(string: ReadableBuffer = b"") -> HASH: ... + def openssl_sha1(string: ReadableBuffer = b"") -> HASH: ... + def openssl_sha224(string: ReadableBuffer = b"") -> HASH: ... + def openssl_sha256(string: ReadableBuffer = b"") -> HASH: ... + def openssl_sha384(string: ReadableBuffer = b"") -> HASH: ... + def openssl_sha512(string: ReadableBuffer = b"") -> HASH: ... + +def hmac_digest(key: bytes | bytearray, msg: ReadableBuffer, digest: str) -> bytes: ... +def pbkdf2_hmac( + hash_name: str, password: ReadableBuffer, salt: ReadableBuffer, iterations: int, dklen: int | None = None +) -> bytes: ... +def scrypt( + password: ReadableBuffer, *, salt: ReadableBuffer, n: int, r: int, p: int, maxmem: int = 0, dklen: int = 64 +) -> bytes: ... diff --git a/mypy/typeshed/stdlib/_interpreters.pyi b/mypy/typeshed/stdlib/_interpreters.pyi index 75f661a7e8e1..a57ef13c6d0f 100644 --- a/mypy/typeshed/stdlib/_interpreters.pyi +++ b/mypy/typeshed/stdlib/_interpreters.pyi @@ -7,7 +7,7 @@ _Configs: TypeAlias = Literal["default", "isolated", "legacy", "empty", ""] class InterpreterError(Exception): ... class InterpreterNotFoundError(InterpreterError): ... -class NotShareableError(Exception): ... +class NotShareableError(ValueError): ... class CrossInterpreterBufferView: def __buffer__(self, flags: int, /) -> memoryview: ... diff --git a/mypy/typeshed/stdlib/_io.pyi b/mypy/typeshed/stdlib/_io.pyi new file mode 100644 index 000000000000..284d99f92b60 --- /dev/null +++ b/mypy/typeshed/stdlib/_io.pyi @@ -0,0 +1,216 @@ +import builtins +import codecs +import sys +from _typeshed import FileDescriptorOrPath, MaybeNone, ReadableBuffer, WriteableBuffer +from collections.abc import Callable, Iterable, Iterator +from io import BufferedIOBase, RawIOBase, TextIOBase, UnsupportedOperation as UnsupportedOperation +from os import _Opener +from types import TracebackType +from typing import IO, Any, BinaryIO, Final, Generic, Literal, Protocol, TextIO, TypeVar, overload, type_check_only +from typing_extensions import Self + +_T = TypeVar("_T") + +DEFAULT_BUFFER_SIZE: Final = 8192 + +open = builtins.open + +def open_code(path: str) -> IO[bytes]: ... + +BlockingIOError = builtins.BlockingIOError + +class _IOBase: + def __iter__(self) -> Iterator[bytes]: ... + def __next__(self) -> bytes: ... + def __enter__(self) -> Self: ... + def __exit__( + self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None + ) -> None: ... + def close(self) -> None: ... + def fileno(self) -> int: ... + def flush(self) -> None: ... + def isatty(self) -> bool: ... + def readable(self) -> bool: ... + read: Callable[..., Any] + def readlines(self, hint: int = -1, /) -> list[bytes]: ... + def seek(self, offset: int, whence: int = 0, /) -> int: ... + def seekable(self) -> bool: ... + def tell(self) -> int: ... + def truncate(self, size: int | None = None, /) -> int: ... + def writable(self) -> bool: ... + write: Callable[..., Any] + def writelines(self, lines: Iterable[ReadableBuffer], /) -> None: ... + def readline(self, size: int | None = -1, /) -> bytes: ... + def __del__(self) -> None: ... + @property + def closed(self) -> bool: ... + def _checkClosed(self) -> None: ... # undocumented + +class _RawIOBase(_IOBase): + def readall(self) -> bytes: ... + # The following methods can return None if the file is in non-blocking mode + # and no data is available. + def readinto(self, buffer: WriteableBuffer, /) -> int | MaybeNone: ... + def write(self, b: ReadableBuffer, /) -> int | MaybeNone: ... + def read(self, size: int = -1, /) -> bytes | MaybeNone: ... + +class _BufferedIOBase(_IOBase): + def detach(self) -> RawIOBase: ... + def readinto(self, buffer: WriteableBuffer, /) -> int: ... + def write(self, buffer: ReadableBuffer, /) -> int: ... + def readinto1(self, buffer: WriteableBuffer, /) -> int: ... + def read(self, size: int | None = -1, /) -> bytes: ... + def read1(self, size: int = -1, /) -> bytes: ... + +class FileIO(RawIOBase, _RawIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of writelines in the base classes + mode: str + # The type of "name" equals the argument passed in to the constructor, + # but that can make FileIO incompatible with other I/O types that assume + # "name" is a str. In the future, making FileIO generic might help. + name: Any + def __init__( + self, file: FileDescriptorOrPath, mode: str = "r", closefd: bool = True, opener: _Opener | None = None + ) -> None: ... + @property + def closefd(self) -> bool: ... + def seek(self, pos: int, whence: int = 0, /) -> int: ... + def read(self, size: int | None = -1, /) -> bytes | MaybeNone: ... + +class BytesIO(BufferedIOBase, _BufferedIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of methods in the base classes + def __init__(self, initial_bytes: ReadableBuffer = b"") -> None: ... + # BytesIO does not contain a "name" field. This workaround is necessary + # to allow BytesIO sub-classes to add this field, as it is defined + # as a read-only property on IO[]. + name: Any + def getvalue(self) -> bytes: ... + def getbuffer(self) -> memoryview: ... + def read1(self, size: int | None = -1, /) -> bytes: ... + def readlines(self, size: int | None = None, /) -> list[bytes]: ... + def seek(self, pos: int, whence: int = 0, /) -> int: ... + +class BufferedReader(BufferedIOBase, _BufferedIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of methods in the base classes + raw: RawIOBase + def __init__(self, raw: RawIOBase, buffer_size: int = 8192) -> None: ... + def peek(self, size: int = 0, /) -> bytes: ... + def seek(self, target: int, whence: int = 0, /) -> int: ... + def truncate(self, pos: int | None = None, /) -> int: ... + +class BufferedWriter(BufferedIOBase, _BufferedIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of writelines in the base classes + raw: RawIOBase + def __init__(self, raw: RawIOBase, buffer_size: int = 8192) -> None: ... + def write(self, buffer: ReadableBuffer, /) -> int: ... + def seek(self, target: int, whence: int = 0, /) -> int: ... + def truncate(self, pos: int | None = None, /) -> int: ... + +class BufferedRandom(BufferedIOBase, _BufferedIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of methods in the base classes + mode: str + name: Any + raw: RawIOBase + def __init__(self, raw: RawIOBase, buffer_size: int = 8192) -> None: ... + def seek(self, target: int, whence: int = 0, /) -> int: ... # stubtest needs this + def peek(self, size: int = 0, /) -> bytes: ... + def truncate(self, pos: int | None = None, /) -> int: ... + +class BufferedRWPair(BufferedIOBase, _BufferedIOBase): + def __init__(self, reader: RawIOBase, writer: RawIOBase, buffer_size: int = 8192) -> None: ... + def peek(self, size: int = 0, /) -> bytes: ... + +class _TextIOBase(_IOBase): + encoding: str + errors: str | None + newlines: str | tuple[str, ...] | None + def __iter__(self) -> Iterator[str]: ... # type: ignore[override] + def __next__(self) -> str: ... # type: ignore[override] + def detach(self) -> BinaryIO: ... + def write(self, s: str, /) -> int: ... + def writelines(self, lines: Iterable[str], /) -> None: ... # type: ignore[override] + def readline(self, size: int = -1, /) -> str: ... # type: ignore[override] + def readlines(self, hint: int = -1, /) -> list[str]: ... # type: ignore[override] + def read(self, size: int | None = -1, /) -> str: ... + +@type_check_only +class _WrappedBuffer(Protocol): + # "name" is wrapped by TextIOWrapper. Its type is inconsistent between + # the various I/O types, see the comments on TextIOWrapper.name and + # TextIO.name. + @property + def name(self) -> Any: ... + @property + def closed(self) -> bool: ... + def read(self, size: int = ..., /) -> ReadableBuffer: ... + # Optional: def read1(self, size: int, /) -> ReadableBuffer: ... + def write(self, b: bytes, /) -> object: ... + def flush(self) -> object: ... + def close(self) -> object: ... + def seekable(self) -> bool: ... + def readable(self) -> bool: ... + def writable(self) -> bool: ... + def truncate(self, size: int, /) -> int: ... + def fileno(self) -> int: ... + def isatty(self) -> bool: ... + # Optional: Only needs to be present if seekable() returns True. + # def seek(self, offset: Literal[0], whence: Literal[2]) -> int: ... + # def tell(self) -> int: ... + +_BufferT_co = TypeVar("_BufferT_co", bound=_WrappedBuffer, default=_WrappedBuffer, covariant=True) + +class TextIOWrapper(TextIOBase, _TextIOBase, TextIO, Generic[_BufferT_co]): # type: ignore[misc] # incompatible definitions of write in the base classes + def __init__( + self, + buffer: _BufferT_co, + encoding: str | None = None, + errors: str | None = None, + newline: str | None = None, + line_buffering: bool = False, + write_through: bool = False, + ) -> None: ... + # Equals the "buffer" argument passed in to the constructor. + @property + def buffer(self) -> _BufferT_co: ... # type: ignore[override] + @property + def line_buffering(self) -> bool: ... + @property + def write_through(self) -> bool: ... + def reconfigure( + self, + *, + encoding: str | None = None, + errors: str | None = None, + newline: str | None = None, + line_buffering: bool | None = None, + write_through: bool | None = None, + ) -> None: ... + def readline(self, size: int = -1, /) -> str: ... # type: ignore[override] + # Equals the "buffer" argument passed in to the constructor. + def detach(self) -> _BufferT_co: ... # type: ignore[override] + # TextIOWrapper's version of seek only supports a limited subset of + # operations. + def seek(self, cookie: int, whence: int = 0, /) -> int: ... + def truncate(self, pos: int | None = None, /) -> int: ... + +class StringIO(TextIOBase, _TextIOBase, TextIO): # type: ignore[misc] # incompatible definitions of write in the base classes + def __init__(self, initial_value: str | None = "", newline: str | None = "\n") -> None: ... + # StringIO does not contain a "name" field. This workaround is necessary + # to allow StringIO sub-classes to add this field, as it is defined + # as a read-only property on IO[]. + name: Any + def getvalue(self) -> str: ... + @property + def line_buffering(self) -> bool: ... + def seek(self, pos: int, whence: int = 0, /) -> int: ... + def truncate(self, pos: int | None = None, /) -> int: ... + +class IncrementalNewlineDecoder: + def __init__(self, decoder: codecs.IncrementalDecoder | None, translate: bool, errors: str = "strict") -> None: ... + def decode(self, input: ReadableBuffer | str, final: bool = False) -> str: ... + @property + def newlines(self) -> str | tuple[str, ...] | None: ... + def getstate(self) -> tuple[bytes, int]: ... + def reset(self) -> None: ... + def setstate(self, state: tuple[bytes, int], /) -> None: ... + +if sys.version_info >= (3, 10): + @overload + def text_encoding(encoding: None, stacklevel: int = 2, /) -> Literal["locale", "utf-8"]: ... + @overload + def text_encoding(encoding: _T, stacklevel: int = 2, /) -> _T: ... diff --git a/mypy/typeshed/stdlib/_json.pyi b/mypy/typeshed/stdlib/_json.pyi index 069fb6eac4bf..e1c7c52ca3b1 100644 --- a/mypy/typeshed/stdlib/_json.pyi +++ b/mypy/typeshed/stdlib/_json.pyi @@ -45,5 +45,6 @@ class make_scanner: def __init__(self, context: make_scanner) -> None: ... def __call__(self, string: str, index: int) -> tuple[Any, int]: ... +def encode_basestring(s: str, /) -> str: ... def encode_basestring_ascii(s: str, /) -> str: ... def scanstring(string: str, end: int, strict: bool = ...) -> tuple[str, int]: ... diff --git a/mypy/typeshed/stdlib/_lzma.pyi b/mypy/typeshed/stdlib/_lzma.pyi new file mode 100644 index 000000000000..1f5be78876c6 --- /dev/null +++ b/mypy/typeshed/stdlib/_lzma.pyi @@ -0,0 +1,60 @@ +from _typeshed import ReadableBuffer +from collections.abc import Mapping, Sequence +from typing import Any, Final, final +from typing_extensions import TypeAlias + +_FilterChain: TypeAlias = Sequence[Mapping[str, Any]] + +FORMAT_AUTO: Final = 0 +FORMAT_XZ: Final = 1 +FORMAT_ALONE: Final = 2 +FORMAT_RAW: Final = 3 +CHECK_NONE: Final = 0 +CHECK_CRC32: Final = 1 +CHECK_CRC64: Final = 4 +CHECK_SHA256: Final = 10 +CHECK_ID_MAX: Final = 15 +CHECK_UNKNOWN: Final = 16 +FILTER_LZMA1: int # v big number +FILTER_LZMA2: Final = 33 +FILTER_DELTA: Final = 3 +FILTER_X86: Final = 4 +FILTER_IA64: Final = 6 +FILTER_ARM: Final = 7 +FILTER_ARMTHUMB: Final = 8 +FILTER_SPARC: Final = 9 +FILTER_POWERPC: Final = 5 +MF_HC3: Final = 3 +MF_HC4: Final = 4 +MF_BT2: Final = 18 +MF_BT3: Final = 19 +MF_BT4: Final = 20 +MODE_FAST: Final = 1 +MODE_NORMAL: Final = 2 +PRESET_DEFAULT: Final = 6 +PRESET_EXTREME: int # v big number + +@final +class LZMADecompressor: + def __init__(self, format: int | None = ..., memlimit: int | None = ..., filters: _FilterChain | None = ...) -> None: ... + def decompress(self, data: ReadableBuffer, max_length: int = -1) -> bytes: ... + @property + def check(self) -> int: ... + @property + def eof(self) -> bool: ... + @property + def unused_data(self) -> bytes: ... + @property + def needs_input(self) -> bool: ... + +@final +class LZMACompressor: + def __init__( + self, format: int | None = ..., check: int = ..., preset: int | None = ..., filters: _FilterChain | None = ... + ) -> None: ... + def compress(self, data: ReadableBuffer, /) -> bytes: ... + def flush(self) -> bytes: ... + +class LZMAError(Exception): ... + +def is_check_supported(check_id: int, /) -> bool: ... diff --git a/mypy/typeshed/stdlib/_multibytecodec.pyi b/mypy/typeshed/stdlib/_multibytecodec.pyi new file mode 100644 index 000000000000..7e408f2aa30e --- /dev/null +++ b/mypy/typeshed/stdlib/_multibytecodec.pyi @@ -0,0 +1,44 @@ +from _typeshed import ReadableBuffer +from codecs import _ReadableStream, _WritableStream +from collections.abc import Iterable +from typing import final, type_check_only + +# This class is not exposed. It calls itself _multibytecodec.MultibyteCodec. +@final +@type_check_only +class _MultibyteCodec: + def decode(self, input: ReadableBuffer, errors: str | None = None) -> str: ... + def encode(self, input: str, errors: str | None = None) -> bytes: ... + +class MultibyteIncrementalDecoder: + errors: str + def __init__(self, errors: str = "strict") -> None: ... + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + def getstate(self) -> tuple[bytes, int]: ... + def reset(self) -> None: ... + def setstate(self, state: tuple[bytes, int], /) -> None: ... + +class MultibyteIncrementalEncoder: + errors: str + def __init__(self, errors: str = "strict") -> None: ... + def encode(self, input: str, final: bool = False) -> bytes: ... + def getstate(self) -> int: ... + def reset(self) -> None: ... + def setstate(self, state: int, /) -> None: ... + +class MultibyteStreamReader: + errors: str + stream: _ReadableStream + def __init__(self, stream: _ReadableStream, errors: str = "strict") -> None: ... + def read(self, sizeobj: int | None = None, /) -> str: ... + def readline(self, sizeobj: int | None = None, /) -> str: ... + def readlines(self, sizehintobj: int | None = None, /) -> list[str]: ... + def reset(self) -> None: ... + +class MultibyteStreamWriter: + errors: str + stream: _WritableStream + def __init__(self, stream: _WritableStream, errors: str = "strict") -> None: ... + def reset(self) -> None: ... + def write(self, strobj: str, /) -> None: ... + def writelines(self, lines: Iterable[str], /) -> None: ... diff --git a/mypy/typeshed/stdlib/_operator.pyi b/mypy/typeshed/stdlib/_operator.pyi index 1b0083f4e274..967215d8fa21 100644 --- a/mypy/typeshed/stdlib/_operator.pyi +++ b/mypy/typeshed/stdlib/_operator.pyi @@ -1,18 +1,16 @@ import sys from _typeshed import SupportsGetItem from collections.abc import Callable, Container, Iterable, MutableMapping, MutableSequence, Sequence -from typing import Any, AnyStr, Generic, Protocol, SupportsAbs, SupportsIndex, TypeVar, final, overload -from typing_extensions import ParamSpec, TypeAlias, TypeIs, TypeVarTuple, Unpack +from operator import attrgetter as attrgetter, itemgetter as itemgetter, methodcaller as methodcaller +from typing import Any, AnyStr, Protocol, SupportsAbs, SupportsIndex, TypeVar, overload +from typing_extensions import ParamSpec, TypeAlias, TypeIs _R = TypeVar("_R") _T = TypeVar("_T") _T_co = TypeVar("_T_co", covariant=True) -_T1 = TypeVar("_T1") -_T2 = TypeVar("_T2") _K = TypeVar("_K") _V = TypeVar("_V") _P = ParamSpec("_P") -_Ts = TypeVarTuple("_Ts") # The following protocols return "Any" instead of bool, since the comparison # operators can be overloaded to return an arbitrary object. For example, @@ -92,40 +90,6 @@ def setitem(a: MutableSequence[_T], b: slice, c: Sequence[_T], /) -> None: ... @overload def setitem(a: MutableMapping[_K, _V], b: _K, c: _V, /) -> None: ... def length_hint(obj: object, default: int = 0, /) -> int: ... -@final -class attrgetter(Generic[_T_co]): - @overload - def __new__(cls, attr: str, /) -> attrgetter[Any]: ... - @overload - def __new__(cls, attr: str, attr2: str, /) -> attrgetter[tuple[Any, Any]]: ... - @overload - def __new__(cls, attr: str, attr2: str, attr3: str, /) -> attrgetter[tuple[Any, Any, Any]]: ... - @overload - def __new__(cls, attr: str, attr2: str, attr3: str, attr4: str, /) -> attrgetter[tuple[Any, Any, Any, Any]]: ... - @overload - def __new__(cls, attr: str, /, *attrs: str) -> attrgetter[tuple[Any, ...]]: ... - def __call__(self, obj: Any, /) -> _T_co: ... - -@final -class itemgetter(Generic[_T_co]): - @overload - def __new__(cls, item: _T, /) -> itemgetter[_T]: ... - @overload - def __new__(cls, item1: _T1, item2: _T2, /, *items: Unpack[_Ts]) -> itemgetter[tuple[_T1, _T2, Unpack[_Ts]]]: ... - # __key: _KT_contra in SupportsGetItem seems to be causing variance issues, ie: - # TypeVar "_KT_contra@SupportsGetItem" is contravariant - # "tuple[int, int]" is incompatible with protocol "SupportsIndex" - # preventing [_T_co, ...] instead of [Any, ...] - # - # A suspected mypy issue prevents using [..., _T] instead of [..., Any] here. - # https://github.com/python/mypy/issues/14032 - def __call__(self, obj: SupportsGetItem[Any, Any]) -> Any: ... - -@final -class methodcaller: - def __init__(self, name: str, /, *args: Any, **kwargs: Any) -> None: ... - def __call__(self, obj: Any) -> Any: ... - def iadd(a: Any, b: Any, /) -> Any: ... def iand(a: Any, b: Any, /) -> Any: ... def iconcat(a: Any, b: Any, /) -> Any: ... diff --git a/mypy/typeshed/stdlib/_posixsubprocess.pyi b/mypy/typeshed/stdlib/_posixsubprocess.pyi index 3df56d9a3d03..df05dcd80be8 100644 --- a/mypy/typeshed/stdlib/_posixsubprocess.pyi +++ b/mypy/typeshed/stdlib/_posixsubprocess.pyi @@ -4,7 +4,6 @@ from collections.abc import Callable, Sequence from typing import SupportsIndex if sys.platform != "win32": - def cloexec_pipe() -> tuple[int, int]: ... def fork_exec( args: Sequence[StrOrBytesPath] | None, executable_list: Sequence[bytes], diff --git a/mypy/typeshed/stdlib/_queue.pyi b/mypy/typeshed/stdlib/_queue.pyi new file mode 100644 index 000000000000..0d4caea7442e --- /dev/null +++ b/mypy/typeshed/stdlib/_queue.pyi @@ -0,0 +1,20 @@ +import sys +from typing import Any, Generic, TypeVar + +if sys.version_info >= (3, 9): + from types import GenericAlias + +_T = TypeVar("_T") + +class Empty(Exception): ... + +class SimpleQueue(Generic[_T]): + def __init__(self) -> None: ... + def empty(self) -> bool: ... + def get(self, block: bool = True, timeout: float | None = None) -> _T: ... + def get_nowait(self) -> _T: ... + def put(self, item: _T, block: bool = True, timeout: float | None = None) -> None: ... + def put_nowait(self, item: _T) -> None: ... + def qsize(self) -> int: ... + if sys.version_info >= (3, 9): + def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... diff --git a/mypy/typeshed/stdlib/_socket.pyi b/mypy/typeshed/stdlib/_socket.pyi index affa8d63ecfa..36bc5c31c646 100644 --- a/mypy/typeshed/stdlib/_socket.pyi +++ b/mypy/typeshed/stdlib/_socket.pyi @@ -1,8 +1,9 @@ import sys from _typeshed import ReadableBuffer, WriteableBuffer from collections.abc import Iterable +from socket import error as error, gaierror as gaierror, herror as herror, timeout as timeout from typing import Any, SupportsIndex, overload -from typing_extensions import TypeAlias +from typing_extensions import CapsuleType, TypeAlias _CMSG: TypeAlias = tuple[int, int, bytes] _CMSGArg: TypeAlias = tuple[int, int, ReadableBuffer] @@ -71,7 +72,8 @@ SO_SNDBUF: int SO_SNDLOWAT: int SO_SNDTIMEO: int SO_TYPE: int -SO_USELOOPBACK: int +if sys.platform != "linux": + SO_USELOOPBACK: int if sys.platform == "win32": SO_EXCLUSIVEADDRUSE: int if sys.platform != "win32": @@ -86,7 +88,10 @@ if sys.platform != "win32" and sys.platform != "darwin": SO_PEERSEC: int SO_PRIORITY: int SO_PROTOCOL: int +if sys.platform != "win32" and sys.platform != "darwin" and sys.platform != "linux": SO_SETFIB: int +if sys.platform == "linux" and sys.version_info >= (3, 13): + SO_BINDTOIFINDEX: int SOMAXCONN: int @@ -98,27 +103,32 @@ MSG_TRUNC: int MSG_WAITALL: int if sys.platform != "win32": MSG_DONTWAIT: int - MSG_EOF: int MSG_EOR: int MSG_NOSIGNAL: int # Sometimes this exists on darwin, sometimes not if sys.platform != "darwin": - MSG_BCAST: int MSG_ERRQUEUE: int +if sys.platform == "win32": + MSG_BCAST: int MSG_MCAST: int if sys.platform != "win32" and sys.platform != "darwin": - MSG_BTAG: int MSG_CMSG_CLOEXEC: int MSG_CONFIRM: int - MSG_ETAG: int MSG_FASTOPEN: int MSG_MORE: int +if sys.platform != "win32" and sys.platform != "linux": + MSG_EOF: int +if sys.platform != "win32" and sys.platform != "linux" and sys.platform != "darwin": MSG_NOTIFICATION: int + MSG_BTAG: int # Not FreeBSD either + MSG_ETAG: int # Not FreeBSD either SOL_IP: int SOL_SOCKET: int SOL_TCP: int SOL_UDP: int if sys.platform != "win32" and sys.platform != "darwin": + # Defined in socket.h for Linux, but these aren't always present for + # some reason. SOL_ATALK: int SOL_AX25: int SOL_HCI: int @@ -127,10 +137,11 @@ if sys.platform != "win32" and sys.platform != "darwin": SOL_ROSE: int if sys.platform != "win32": - SCM_CREDS: int SCM_RIGHTS: int if sys.platform != "win32" and sys.platform != "darwin": SCM_CREDENTIALS: int +if sys.platform != "win32" and sys.platform != "linux": + SCM_CREDS: int IPPROTO_ICMP: int IPPROTO_IP: int @@ -142,21 +153,22 @@ IPPROTO_DSTOPTS: int IPPROTO_EGP: int IPPROTO_ESP: int IPPROTO_FRAGMENT: int -IPPROTO_GGP: int IPPROTO_HOPOPTS: int IPPROTO_ICMPV6: int IPPROTO_IDP: int IPPROTO_IGMP: int -IPPROTO_IPV4: int IPPROTO_IPV6: int -IPPROTO_MAX: int -IPPROTO_ND: int IPPROTO_NONE: int IPPROTO_PIM: int IPPROTO_PUP: int IPPROTO_ROUTING: int IPPROTO_SCTP: int -if sys.platform != "darwin": +if sys.platform != "linux": + IPPROTO_GGP: int + IPPROTO_IPV4: int + IPPROTO_MAX: int + IPPROTO_ND: int +if sys.platform == "win32": IPPROTO_CBT: int IPPROTO_ICLFXBM: int IPPROTO_IGP: int @@ -165,18 +177,19 @@ if sys.platform != "darwin": IPPROTO_RDP: int IPPROTO_ST: int if sys.platform != "win32": - IPPROTO_EON: int IPPROTO_GRE: int - IPPROTO_HELLO: int - IPPROTO_IPCOMP: int IPPROTO_IPIP: int IPPROTO_RSVP: int IPPROTO_TP: int +if sys.platform != "win32" and sys.platform != "linux": + IPPROTO_EON: int + IPPROTO_HELLO: int + IPPROTO_IPCOMP: int IPPROTO_XTP: int -if sys.platform != "win32" and sys.platform != "darwin": - IPPROTO_BIP: int - IPPROTO_MOBILE: int - IPPROTO_VRRP: int +if sys.platform != "win32" and sys.platform != "darwin" and sys.platform != "linux": + IPPROTO_BIP: int # Not FreeBSD either + IPPROTO_MOBILE: int # Not FreeBSD either + IPPROTO_VRRP: int # Not FreeBSD either if sys.version_info >= (3, 9) and sys.platform == "linux": # Availability: Linux >= 2.6.20, FreeBSD >= 10.1 IPPROTO_UDPLITE: int @@ -201,11 +214,10 @@ IP_MULTICAST_IF: int IP_MULTICAST_LOOP: int IP_MULTICAST_TTL: int IP_OPTIONS: int -IP_RECVDSTADDR: int +if sys.platform != "linux": + IP_RECVDSTADDR: int if sys.version_info >= (3, 10): IP_RECVTOS: int -elif sys.platform != "win32" and sys.platform != "darwin": - IP_RECVTOS: int IP_TOS: int IP_TTL: int if sys.platform != "win32": @@ -217,6 +229,7 @@ if sys.platform != "win32": IP_RETOPTS: int if sys.platform != "win32" and sys.platform != "darwin": IP_TRANSPARENT: int +if sys.platform != "win32" and sys.platform != "darwin" and sys.version_info >= (3, 11): IP_BIND_ADDRESS_NO_PORT: int if sys.version_info >= (3, 12): IP_ADD_SOURCE_MEMBERSHIP: int @@ -254,6 +267,9 @@ if sys.platform != "win32": IPV6_RECVPATHMTU: int IPV6_RECVPKTINFO: int IPV6_RTHDRDSTOPTS: int + +if sys.platform != "win32" and sys.platform != "linux": + if sys.version_info >= (3, 9) or sys.platform != "darwin": IPV6_USE_MIN_MTU: int EAI_AGAIN: int @@ -267,11 +283,12 @@ EAI_SERVICE: int EAI_SOCKTYPE: int if sys.platform != "win32": EAI_ADDRFAMILY: int + EAI_OVERFLOW: int + EAI_SYSTEM: int +if sys.platform != "win32" and sys.platform != "linux": EAI_BADHINTS: int EAI_MAX: int - EAI_OVERFLOW: int EAI_PROTOCOL: int - EAI_SYSTEM: int AI_ADDRCONFIG: int AI_ALL: int @@ -280,7 +297,7 @@ AI_NUMERICHOST: int AI_NUMERICSERV: int AI_PASSIVE: int AI_V4MAPPED: int -if sys.platform != "win32": +if sys.platform != "win32" and sys.platform != "linux": AI_DEFAULT: int AI_MASK: int AI_V4MAPPED_CFG: int @@ -292,6 +309,8 @@ NI_NAMEREQD: int NI_NOFQDN: int NI_NUMERICHOST: int NI_NUMERICSERV: int +if sys.platform == "linux" and sys.version_info >= (3, 13): + NI_IDN: int TCP_FASTOPEN: int TCP_KEEPCNT: int @@ -317,6 +336,27 @@ if sys.platform != "win32" and sys.platform != "darwin": TCP_SYNCNT: int TCP_USER_TIMEOUT: int TCP_WINDOW_CLAMP: int +if sys.platform == "linux" and sys.version_info >= (3, 12): + TCP_CC_INFO: int + TCP_FASTOPEN_CONNECT: int + TCP_FASTOPEN_KEY: int + TCP_FASTOPEN_NO_COOKIE: int + TCP_INQ: int + TCP_MD5SIG: int + TCP_MD5SIG_EXT: int + TCP_QUEUE_SEQ: int + TCP_REPAIR: int + TCP_REPAIR_OPTIONS: int + TCP_REPAIR_QUEUE: int + TCP_REPAIR_WINDOW: int + TCP_SAVED_SYN: int + TCP_SAVE_SYN: int + TCP_THIN_DUPACK: int + TCP_THIN_LINEAR_TIMEOUTS: int + TCP_TIMESTAMP: int + TCP_TX_DELAY: int + TCP_ULP: int + TCP_ZEROCOPY_RECEIVE: int # -------------------- # Specifically documented constants @@ -333,12 +373,13 @@ if sys.platform == "linux": CAN_ERR_FLAG: int CAN_ERR_MASK: int CAN_RAW: int - CAN_RAW_ERR_FILTER: int CAN_RAW_FILTER: int CAN_RAW_LOOPBACK: int CAN_RAW_RECV_OWN_MSGS: int CAN_RTR_FLAG: int CAN_SFF_MASK: int + if sys.version_info < (3, 11): + CAN_RAW_ERR_FILTER: int if sys.platform == "linux": # Availability: Linux >= 2.6.25 @@ -436,12 +477,13 @@ if sys.platform == "linux": AF_RDS: int PF_RDS: int SOL_RDS: int + # These are present in include/linux/rds.h but don't always show up + # here. RDS_CANCEL_SENT_TO: int RDS_CMSG_RDMA_ARGS: int RDS_CMSG_RDMA_DEST: int RDS_CMSG_RDMA_MAP: int RDS_CMSG_RDMA_STATUS: int - RDS_CMSG_RDMA_UPDATE: int RDS_CONG_MONITOR: int RDS_FREE_MR: int RDS_GET_MR: int @@ -455,6 +497,10 @@ if sys.platform == "linux": RDS_RDMA_USE_ONCE: int RDS_RECVERR: int + # This is supported by CPython but doesn't seem to be a real thing. + # The closest existing constant in rds.h is RDS_CMSG_CONG_UPDATE + # RDS_CMSG_RDMA_UPDATE: int + if sys.platform == "win32": SIO_RCVALL: int SIO_KEEPALIVE_VALS: int @@ -521,16 +567,17 @@ if sys.platform == "linux": if sys.platform != "win32" or sys.version_info >= (3, 9): # Documented as only available on BSD, macOS, but empirically sometimes # available on Windows - AF_LINK: int + if sys.platform != "linux": + AF_LINK: int has_ipv6: bool -if sys.platform != "darwin": +if sys.platform != "darwin" and sys.platform != "linux": if sys.platform != "win32" or sys.version_info >= (3, 9): BDADDR_ANY: str BDADDR_LOCAL: str -if sys.platform != "win32" and sys.platform != "darwin": +if sys.platform != "win32" and sys.platform != "darwin" and sys.platform != "linux": HCI_FILTER: int # not in NetBSD or DragonFlyBSD HCI_TIME_STAMP: int # not in FreeBSD, NetBSD, or DragonFlyBSD HCI_DATA_DIR: int # not in FreeBSD, NetBSD, or DragonFlyBSD @@ -579,36 +626,37 @@ if sys.version_info >= (3, 12): if sys.platform == "linux": # Netlink is defined by Linux AF_NETLINK: int - NETLINK_ARPD: int NETLINK_CRYPTO: int NETLINK_DNRTMSG: int NETLINK_FIREWALL: int NETLINK_IP6_FW: int NETLINK_NFLOG: int - NETLINK_ROUTE6: int NETLINK_ROUTE: int - NETLINK_SKIP: int - NETLINK_TAPBASE: int - NETLINK_TCPDIAG: int NETLINK_USERSOCK: int - NETLINK_W1: int NETLINK_XFRM: int + # Technically still supported by CPython + # NETLINK_ARPD: int # linux 2.0 to 2.6.12 (EOL August 2005) + # NETLINK_ROUTE6: int # linux 2.2 to 2.6.12 (EOL August 2005) + # NETLINK_SKIP: int # linux 2.0 to 2.6.12 (EOL August 2005) + # NETLINK_TAPBASE: int # linux 2.2 to 2.6.12 (EOL August 2005) + # NETLINK_TCPDIAG: int # linux 2.6.0 to 2.6.13 (EOL December 2005) + # NETLINK_W1: int # linux 2.6.13 to 2.6.17 (EOL October 2006) if sys.platform == "darwin": PF_SYSTEM: int SYSPROTO_CONTROL: int -if sys.platform != "darwin": +if sys.platform != "darwin" and sys.platform != "linux": if sys.version_info >= (3, 9) or sys.platform != "win32": AF_BLUETOOTH: int -if sys.platform != "win32" and sys.platform != "darwin": +if sys.platform != "win32" and sys.platform != "darwin" and sys.platform != "linux": # Linux and some BSD support is explicit in the docs # Windows and macOS do not support in practice BTPROTO_HCI: int BTPROTO_L2CAP: int BTPROTO_SCO: int # not in FreeBSD -if sys.platform != "darwin": +if sys.platform != "darwin" and sys.platform != "linux": if sys.version_info >= (3, 9) or sys.platform != "win32": BTPROTO_RFCOMM: int @@ -635,13 +683,14 @@ AF_SNA: int if sys.platform != "win32": AF_ROUTE: int + +if sys.platform == "darwin": AF_SYSTEM: int if sys.platform != "darwin": AF_IRDA: int if sys.platform != "win32" and sys.platform != "darwin": - AF_AAL5: int AF_ASH: int AF_ATMPVC: int AF_ATMSVC: int @@ -660,24 +709,14 @@ if sys.platform != "win32" and sys.platform != "darwin": # Miscellaneous undocumented -if sys.platform != "win32": +if sys.platform != "win32" and sys.platform != "linux": LOCAL_PEERCRED: int if sys.platform != "win32" and sys.platform != "darwin": + # Defined in linux socket.h, but this isn't always present for + # some reason. IPX_TYPE: int -# ===== Exceptions ===== - -error = OSError - -class herror(error): ... -class gaierror(error): ... - -if sys.version_info >= (3, 10): - timeout = TimeoutError -else: - class timeout(error): ... - # ===== Classes ===== class socket: @@ -687,8 +726,9 @@ class socket: def type(self) -> int: ... @property def proto(self) -> int: ... + # F811: "Redefinition of unused `timeout`" @property - def timeout(self) -> float | None: ... + def timeout(self) -> float | None: ... # noqa: F811 if sys.platform == "win32": def __init__( self, family: int = ..., type: int = ..., proto: int = ..., fileno: SupportsIndex | bytes | None = ... @@ -788,7 +828,9 @@ def inet_ntoa(packed_ip: ReadableBuffer, /) -> str: ... def inet_pton(address_family: int, ip_string: str, /) -> bytes: ... def inet_ntop(address_family: int, packed_ip: ReadableBuffer, /) -> str: ... def getdefaulttimeout() -> float | None: ... -def setdefaulttimeout(timeout: float | None, /) -> None: ... + +# F811: "Redefinition of unused `timeout`" +def setdefaulttimeout(timeout: float | None, /) -> None: ... # noqa: F811 if sys.platform != "win32": def sethostname(name: str, /) -> None: ... @@ -800,4 +842,4 @@ def if_nameindex() -> list[tuple[int, str]]: ... def if_nametoindex(oname: str, /) -> int: ... def if_indextoname(index: int, /) -> str: ... -CAPI: object +CAPI: CapsuleType diff --git a/mypy/typeshed/stdlib/_sqlite3.pyi b/mypy/typeshed/stdlib/_sqlite3.pyi new file mode 100644 index 000000000000..6f06542c1ba7 --- /dev/null +++ b/mypy/typeshed/stdlib/_sqlite3.pyi @@ -0,0 +1,312 @@ +import sys +from _typeshed import ReadableBuffer, StrOrBytesPath +from collections.abc import Callable +from sqlite3 import ( + Connection as Connection, + Cursor as Cursor, + DatabaseError as DatabaseError, + DataError as DataError, + Error as Error, + IntegrityError as IntegrityError, + InterfaceError as InterfaceError, + InternalError as InternalError, + NotSupportedError as NotSupportedError, + OperationalError as OperationalError, + PrepareProtocol as PrepareProtocol, + ProgrammingError as ProgrammingError, + Row as Row, + Warning as Warning, +) +from typing import Any, Final, Literal, TypeVar, overload +from typing_extensions import TypeAlias + +if sys.version_info >= (3, 11): + from sqlite3 import Blob as Blob + +_T = TypeVar("_T") +_ConnectionT = TypeVar("_ConnectionT", bound=Connection) +_SqliteData: TypeAlias = str | ReadableBuffer | int | float | None +_Adapter: TypeAlias = Callable[[_T], _SqliteData] +_Converter: TypeAlias = Callable[[bytes], Any] + +PARSE_COLNAMES: Final[int] +PARSE_DECLTYPES: Final[int] +SQLITE_ALTER_TABLE: Final[int] +SQLITE_ANALYZE: Final[int] +SQLITE_ATTACH: Final[int] +SQLITE_CREATE_INDEX: Final[int] +SQLITE_CREATE_TABLE: Final[int] +SQLITE_CREATE_TEMP_INDEX: Final[int] +SQLITE_CREATE_TEMP_TABLE: Final[int] +SQLITE_CREATE_TEMP_TRIGGER: Final[int] +SQLITE_CREATE_TEMP_VIEW: Final[int] +SQLITE_CREATE_TRIGGER: Final[int] +SQLITE_CREATE_VIEW: Final[int] +SQLITE_CREATE_VTABLE: Final[int] +SQLITE_DELETE: Final[int] +SQLITE_DENY: Final[int] +SQLITE_DETACH: Final[int] +SQLITE_DONE: Final[int] +SQLITE_DROP_INDEX: Final[int] +SQLITE_DROP_TABLE: Final[int] +SQLITE_DROP_TEMP_INDEX: Final[int] +SQLITE_DROP_TEMP_TABLE: Final[int] +SQLITE_DROP_TEMP_TRIGGER: Final[int] +SQLITE_DROP_TEMP_VIEW: Final[int] +SQLITE_DROP_TRIGGER: Final[int] +SQLITE_DROP_VIEW: Final[int] +SQLITE_DROP_VTABLE: Final[int] +SQLITE_FUNCTION: Final[int] +SQLITE_IGNORE: Final[int] +SQLITE_INSERT: Final[int] +SQLITE_OK: Final[int] +SQLITE_PRAGMA: Final[int] +SQLITE_READ: Final[int] +SQLITE_RECURSIVE: Final[int] +SQLITE_REINDEX: Final[int] +SQLITE_SAVEPOINT: Final[int] +SQLITE_SELECT: Final[int] +SQLITE_TRANSACTION: Final[int] +SQLITE_UPDATE: Final[int] +adapters: dict[tuple[type[Any], type[Any]], _Adapter[Any]] +converters: dict[str, _Converter] +sqlite_version: str + +if sys.version_info < (3, 12): + version: str + +if sys.version_info >= (3, 12): + LEGACY_TRANSACTION_CONTROL: Final[int] + SQLITE_DBCONFIG_DEFENSIVE: Final[int] + SQLITE_DBCONFIG_DQS_DDL: Final[int] + SQLITE_DBCONFIG_DQS_DML: Final[int] + SQLITE_DBCONFIG_ENABLE_FKEY: Final[int] + SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER: Final[int] + SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION: Final[int] + SQLITE_DBCONFIG_ENABLE_QPSG: Final[int] + SQLITE_DBCONFIG_ENABLE_TRIGGER: Final[int] + SQLITE_DBCONFIG_ENABLE_VIEW: Final[int] + SQLITE_DBCONFIG_LEGACY_ALTER_TABLE: Final[int] + SQLITE_DBCONFIG_LEGACY_FILE_FORMAT: Final[int] + SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE: Final[int] + SQLITE_DBCONFIG_RESET_DATABASE: Final[int] + SQLITE_DBCONFIG_TRIGGER_EQP: Final[int] + SQLITE_DBCONFIG_TRUSTED_SCHEMA: Final[int] + SQLITE_DBCONFIG_WRITABLE_SCHEMA: Final[int] + +if sys.version_info >= (3, 11): + SQLITE_ABORT: Final[int] + SQLITE_ABORT_ROLLBACK: Final[int] + SQLITE_AUTH: Final[int] + SQLITE_AUTH_USER: Final[int] + SQLITE_BUSY: Final[int] + SQLITE_BUSY_RECOVERY: Final[int] + SQLITE_BUSY_SNAPSHOT: Final[int] + SQLITE_BUSY_TIMEOUT: Final[int] + SQLITE_CANTOPEN: Final[int] + SQLITE_CANTOPEN_CONVPATH: Final[int] + SQLITE_CANTOPEN_DIRTYWAL: Final[int] + SQLITE_CANTOPEN_FULLPATH: Final[int] + SQLITE_CANTOPEN_ISDIR: Final[int] + SQLITE_CANTOPEN_NOTEMPDIR: Final[int] + SQLITE_CANTOPEN_SYMLINK: Final[int] + SQLITE_CONSTRAINT: Final[int] + SQLITE_CONSTRAINT_CHECK: Final[int] + SQLITE_CONSTRAINT_COMMITHOOK: Final[int] + SQLITE_CONSTRAINT_FOREIGNKEY: Final[int] + SQLITE_CONSTRAINT_FUNCTION: Final[int] + SQLITE_CONSTRAINT_NOTNULL: Final[int] + SQLITE_CONSTRAINT_PINNED: Final[int] + SQLITE_CONSTRAINT_PRIMARYKEY: Final[int] + SQLITE_CONSTRAINT_ROWID: Final[int] + SQLITE_CONSTRAINT_TRIGGER: Final[int] + SQLITE_CONSTRAINT_UNIQUE: Final[int] + SQLITE_CONSTRAINT_VTAB: Final[int] + SQLITE_CORRUPT: Final[int] + SQLITE_CORRUPT_INDEX: Final[int] + SQLITE_CORRUPT_SEQUENCE: Final[int] + SQLITE_CORRUPT_VTAB: Final[int] + SQLITE_EMPTY: Final[int] + SQLITE_ERROR: Final[int] + SQLITE_ERROR_MISSING_COLLSEQ: Final[int] + SQLITE_ERROR_RETRY: Final[int] + SQLITE_ERROR_SNAPSHOT: Final[int] + SQLITE_FORMAT: Final[int] + SQLITE_FULL: Final[int] + SQLITE_INTERNAL: Final[int] + SQLITE_INTERRUPT: Final[int] + SQLITE_IOERR: Final[int] + SQLITE_IOERR_ACCESS: Final[int] + SQLITE_IOERR_AUTH: Final[int] + SQLITE_IOERR_BEGIN_ATOMIC: Final[int] + SQLITE_IOERR_BLOCKED: Final[int] + SQLITE_IOERR_CHECKRESERVEDLOCK: Final[int] + SQLITE_IOERR_CLOSE: Final[int] + SQLITE_IOERR_COMMIT_ATOMIC: Final[int] + SQLITE_IOERR_CONVPATH: Final[int] + SQLITE_IOERR_CORRUPTFS: Final[int] + SQLITE_IOERR_DATA: Final[int] + SQLITE_IOERR_DELETE: Final[int] + SQLITE_IOERR_DELETE_NOENT: Final[int] + SQLITE_IOERR_DIR_CLOSE: Final[int] + SQLITE_IOERR_DIR_FSYNC: Final[int] + SQLITE_IOERR_FSTAT: Final[int] + SQLITE_IOERR_FSYNC: Final[int] + SQLITE_IOERR_GETTEMPPATH: Final[int] + SQLITE_IOERR_LOCK: Final[int] + SQLITE_IOERR_MMAP: Final[int] + SQLITE_IOERR_NOMEM: Final[int] + SQLITE_IOERR_RDLOCK: Final[int] + SQLITE_IOERR_READ: Final[int] + SQLITE_IOERR_ROLLBACK_ATOMIC: Final[int] + SQLITE_IOERR_SEEK: Final[int] + SQLITE_IOERR_SHMLOCK: Final[int] + SQLITE_IOERR_SHMMAP: Final[int] + SQLITE_IOERR_SHMOPEN: Final[int] + SQLITE_IOERR_SHMSIZE: Final[int] + SQLITE_IOERR_SHORT_READ: Final[int] + SQLITE_IOERR_TRUNCATE: Final[int] + SQLITE_IOERR_UNLOCK: Final[int] + SQLITE_IOERR_VNODE: Final[int] + SQLITE_IOERR_WRITE: Final[int] + SQLITE_LIMIT_ATTACHED: Final[int] + SQLITE_LIMIT_COLUMN: Final[int] + SQLITE_LIMIT_COMPOUND_SELECT: Final[int] + SQLITE_LIMIT_EXPR_DEPTH: Final[int] + SQLITE_LIMIT_FUNCTION_ARG: Final[int] + SQLITE_LIMIT_LENGTH: Final[int] + SQLITE_LIMIT_LIKE_PATTERN_LENGTH: Final[int] + SQLITE_LIMIT_SQL_LENGTH: Final[int] + SQLITE_LIMIT_TRIGGER_DEPTH: Final[int] + SQLITE_LIMIT_VARIABLE_NUMBER: Final[int] + SQLITE_LIMIT_VDBE_OP: Final[int] + SQLITE_LIMIT_WORKER_THREADS: Final[int] + SQLITE_LOCKED: Final[int] + SQLITE_LOCKED_SHAREDCACHE: Final[int] + SQLITE_LOCKED_VTAB: Final[int] + SQLITE_MISMATCH: Final[int] + SQLITE_MISUSE: Final[int] + SQLITE_NOLFS: Final[int] + SQLITE_NOMEM: Final[int] + SQLITE_NOTADB: Final[int] + SQLITE_NOTFOUND: Final[int] + SQLITE_NOTICE: Final[int] + SQLITE_NOTICE_RECOVER_ROLLBACK: Final[int] + SQLITE_NOTICE_RECOVER_WAL: Final[int] + SQLITE_OK_LOAD_PERMANENTLY: Final[int] + SQLITE_OK_SYMLINK: Final[int] + SQLITE_PERM: Final[int] + SQLITE_PROTOCOL: Final[int] + SQLITE_RANGE: Final[int] + SQLITE_READONLY: Final[int] + SQLITE_READONLY_CANTINIT: Final[int] + SQLITE_READONLY_CANTLOCK: Final[int] + SQLITE_READONLY_DBMOVED: Final[int] + SQLITE_READONLY_DIRECTORY: Final[int] + SQLITE_READONLY_RECOVERY: Final[int] + SQLITE_READONLY_ROLLBACK: Final[int] + SQLITE_ROW: Final[int] + SQLITE_SCHEMA: Final[int] + SQLITE_TOOBIG: Final[int] + SQLITE_WARNING: Final[int] + SQLITE_WARNING_AUTOINDEX: Final[int] + threadsafety: Final[int] + +# Can take or return anything depending on what's in the registry. +@overload +def adapt(obj: Any, proto: Any, /) -> Any: ... +@overload +def adapt(obj: Any, proto: Any, alt: _T, /) -> Any | _T: ... +def complete_statement(statement: str) -> bool: ... + +if sys.version_info >= (3, 12): + @overload + def connect( + database: StrOrBytesPath, + timeout: float = 5.0, + detect_types: int = 0, + isolation_level: Literal["DEFERRED", "EXCLUSIVE", "IMMEDIATE"] | None = "DEFERRED", + check_same_thread: bool = True, + cached_statements: int = 128, + uri: bool = False, + *, + autocommit: bool = ..., + ) -> Connection: ... + @overload + def connect( + database: StrOrBytesPath, + timeout: float, + detect_types: int, + isolation_level: Literal["DEFERRED", "EXCLUSIVE", "IMMEDIATE"] | None, + check_same_thread: bool, + factory: type[_ConnectionT], + cached_statements: int = 128, + uri: bool = False, + *, + autocommit: bool = ..., + ) -> _ConnectionT: ... + @overload + def connect( + database: StrOrBytesPath, + timeout: float = 5.0, + detect_types: int = 0, + isolation_level: Literal["DEFERRED", "EXCLUSIVE", "IMMEDIATE"] | None = "DEFERRED", + check_same_thread: bool = True, + *, + factory: type[_ConnectionT], + cached_statements: int = 128, + uri: bool = False, + autocommit: bool = ..., + ) -> _ConnectionT: ... + +else: + @overload + def connect( + database: StrOrBytesPath, + timeout: float = 5.0, + detect_types: int = 0, + isolation_level: Literal["DEFERRED", "EXCLUSIVE", "IMMEDIATE"] | None = "DEFERRED", + check_same_thread: bool = True, + cached_statements: int = 128, + uri: bool = False, + ) -> Connection: ... + @overload + def connect( + database: StrOrBytesPath, + timeout: float, + detect_types: int, + isolation_level: Literal["DEFERRED", "EXCLUSIVE", "IMMEDIATE"] | None, + check_same_thread: bool, + factory: type[_ConnectionT], + cached_statements: int = 128, + uri: bool = False, + ) -> _ConnectionT: ... + @overload + def connect( + database: StrOrBytesPath, + timeout: float = 5.0, + detect_types: int = 0, + isolation_level: Literal["DEFERRED", "EXCLUSIVE", "IMMEDIATE"] | None = "DEFERRED", + check_same_thread: bool = True, + *, + factory: type[_ConnectionT], + cached_statements: int = 128, + uri: bool = False, + ) -> _ConnectionT: ... + +def enable_callback_tracebacks(enable: bool, /) -> None: ... + +if sys.version_info < (3, 12): + # takes a pos-or-keyword argument because there is a C wrapper + def enable_shared_cache(do_enable: int) -> None: ... + +if sys.version_info >= (3, 10): + def register_adapter(type: type[_T], adapter: _Adapter[_T], /) -> None: ... + def register_converter(typename: str, converter: _Converter, /) -> None: ... + +else: + def register_adapter(type: type[_T], caster: _Adapter[_T], /) -> None: ... + def register_converter(name: str, converter: _Converter, /) -> None: ... + +if sys.version_info < (3, 10): + OptimizedUnicode = str diff --git a/mypy/typeshed/stdlib/_ssl.pyi b/mypy/typeshed/stdlib/_ssl.pyi new file mode 100644 index 000000000000..938135eb1192 --- /dev/null +++ b/mypy/typeshed/stdlib/_ssl.pyi @@ -0,0 +1,292 @@ +import sys +from _typeshed import ReadableBuffer, StrOrBytesPath +from collections.abc import Callable +from ssl import ( + SSLCertVerificationError as SSLCertVerificationError, + SSLContext, + SSLEOFError as SSLEOFError, + SSLError as SSLError, + SSLObject, + SSLSyscallError as SSLSyscallError, + SSLWantReadError as SSLWantReadError, + SSLWantWriteError as SSLWantWriteError, + SSLZeroReturnError as SSLZeroReturnError, +) +from typing import Any, Literal, TypedDict, final, overload +from typing_extensions import NotRequired, Self, TypeAlias + +_PasswordType: TypeAlias = Callable[[], str | bytes | bytearray] | str | bytes | bytearray +_PCTRTT: TypeAlias = tuple[tuple[str, str], ...] +_PCTRTTT: TypeAlias = tuple[_PCTRTT, ...] +_PeerCertRetDictType: TypeAlias = dict[str, str | _PCTRTTT | _PCTRTT] + +class _Cipher(TypedDict): + aead: bool + alg_bits: int + auth: str + description: str + digest: str | None + id: int + kea: str + name: str + protocol: str + strength_bits: int + symmetric: str + +class _CertInfo(TypedDict): + subject: tuple[tuple[tuple[str, str], ...], ...] + issuer: tuple[tuple[tuple[str, str], ...], ...] + version: int + serialNumber: str + notBefore: str + notAfter: str + subjectAltName: NotRequired[tuple[tuple[str, str], ...] | None] + OCSP: NotRequired[tuple[str, ...] | None] + caIssuers: NotRequired[tuple[str, ...] | None] + crlDistributionPoints: NotRequired[tuple[str, ...] | None] + +def RAND_add(string: str | ReadableBuffer, entropy: float, /) -> None: ... +def RAND_bytes(n: int, /) -> bytes: ... + +if sys.version_info < (3, 12): + def RAND_pseudo_bytes(n: int, /) -> tuple[bytes, bool]: ... + +if sys.version_info < (3, 10): + def RAND_egd(path: str) -> None: ... + +def RAND_status() -> bool: ... +def get_default_verify_paths() -> tuple[str, str, str, str]: ... + +if sys.platform == "win32": + _EnumRetType: TypeAlias = list[tuple[bytes, str, set[str] | bool]] + def enum_certificates(store_name: str) -> _EnumRetType: ... + def enum_crls(store_name: str) -> _EnumRetType: ... + +def txt2obj(txt: str, name: bool = False) -> tuple[int, str, str, str]: ... +def nid2obj(nid: int, /) -> tuple[int, str, str, str]: ... + +class _SSLContext: + check_hostname: bool + keylog_filename: str | None + maximum_version: int + minimum_version: int + num_tickets: int + options: int + post_handshake_auth: bool + protocol: int + if sys.version_info >= (3, 10): + security_level: int + sni_callback: Callable[[SSLObject, str, SSLContext], None | int] | None + verify_flags: int + verify_mode: int + def __new__(cls, protocol: int, /) -> Self: ... + def cert_store_stats(self) -> dict[str, int]: ... + @overload + def get_ca_certs(self, binary_form: Literal[False] = False) -> list[_PeerCertRetDictType]: ... + @overload + def get_ca_certs(self, binary_form: Literal[True]) -> list[bytes]: ... + @overload + def get_ca_certs(self, binary_form: bool = False) -> Any: ... + def get_ciphers(self) -> list[_Cipher]: ... + def load_cert_chain( + self, certfile: StrOrBytesPath, keyfile: StrOrBytesPath | None = None, password: _PasswordType | None = None + ) -> None: ... + def load_dh_params(self, path: str, /) -> None: ... + def load_verify_locations( + self, + cafile: StrOrBytesPath | None = None, + capath: StrOrBytesPath | None = None, + cadata: str | ReadableBuffer | None = None, + ) -> None: ... + def session_stats(self) -> dict[str, int]: ... + def set_ciphers(self, cipherlist: str, /) -> None: ... + def set_default_verify_paths(self) -> None: ... + def set_ecdh_curve(self, name: str, /) -> None: ... + if sys.version_info >= (3, 13): + def set_psk_client_callback(self, callback: Callable[[str | None], tuple[str | None, bytes]] | None) -> None: ... + def set_psk_server_callback( + self, callback: Callable[[str | None], bytes] | None, identity_hint: str | None = None + ) -> None: ... + +@final +class MemoryBIO: + eof: bool + pending: int + def __new__(self) -> Self: ... + def read(self, size: int = -1, /) -> bytes: ... + def write(self, b: ReadableBuffer, /) -> int: ... + def write_eof(self) -> None: ... + +@final +class SSLSession: + @property + def has_ticket(self) -> bool: ... + @property + def id(self) -> bytes: ... + @property + def ticket_lifetime_hint(self) -> int: ... + @property + def time(self) -> int: ... + @property + def timeout(self) -> int: ... + +# _ssl.Certificate is weird: it can't be instantiated or subclassed. +# Instances can only be created via methods of the private _ssl._SSLSocket class, +# for which the relevant method signatures are: +# +# class _SSLSocket: +# def get_unverified_chain(self) -> list[Certificate] | None: ... +# def get_verified_chain(self) -> list[Certificate] | None: ... +# +# You can find a _ssl._SSLSocket object as the _sslobj attribute of a ssl.SSLSocket object + +if sys.version_info >= (3, 10): + @final + class Certificate: + def get_info(self) -> _CertInfo: ... + @overload + def public_bytes(self) -> str: ... + @overload + def public_bytes(self, format: Literal[1] = 1, /) -> str: ... # ENCODING_PEM + @overload + def public_bytes(self, format: Literal[2], /) -> bytes: ... # ENCODING_DER + @overload + def public_bytes(self, format: int, /) -> str | bytes: ... + +if sys.version_info < (3, 12): + err_codes_to_names: dict[tuple[int, int], str] + err_names_to_codes: dict[str, tuple[int, int]] + lib_codes_to_names: dict[int, str] + +_DEFAULT_CIPHERS: str + +# SSL error numbers +SSL_ERROR_ZERO_RETURN: int +SSL_ERROR_WANT_READ: int +SSL_ERROR_WANT_WRITE: int +SSL_ERROR_WANT_X509_LOOKUP: int +SSL_ERROR_SYSCALL: int +SSL_ERROR_SSL: int +SSL_ERROR_WANT_CONNECT: int +SSL_ERROR_EOF: int +SSL_ERROR_INVALID_ERROR_CODE: int + +# verify modes +CERT_NONE: int +CERT_OPTIONAL: int +CERT_REQUIRED: int + +# verify flags +VERIFY_DEFAULT: int +VERIFY_CRL_CHECK_LEAF: int +VERIFY_CRL_CHECK_CHAIN: int +VERIFY_X509_STRICT: int +VERIFY_X509_TRUSTED_FIRST: int +if sys.version_info >= (3, 10): + VERIFY_ALLOW_PROXY_CERTS: int + VERIFY_X509_PARTIAL_CHAIN: int + +# alert descriptions +ALERT_DESCRIPTION_CLOSE_NOTIFY: int +ALERT_DESCRIPTION_UNEXPECTED_MESSAGE: int +ALERT_DESCRIPTION_BAD_RECORD_MAC: int +ALERT_DESCRIPTION_RECORD_OVERFLOW: int +ALERT_DESCRIPTION_DECOMPRESSION_FAILURE: int +ALERT_DESCRIPTION_HANDSHAKE_FAILURE: int +ALERT_DESCRIPTION_BAD_CERTIFICATE: int +ALERT_DESCRIPTION_UNSUPPORTED_CERTIFICATE: int +ALERT_DESCRIPTION_CERTIFICATE_REVOKED: int +ALERT_DESCRIPTION_CERTIFICATE_EXPIRED: int +ALERT_DESCRIPTION_CERTIFICATE_UNKNOWN: int +ALERT_DESCRIPTION_ILLEGAL_PARAMETER: int +ALERT_DESCRIPTION_UNKNOWN_CA: int +ALERT_DESCRIPTION_ACCESS_DENIED: int +ALERT_DESCRIPTION_DECODE_ERROR: int +ALERT_DESCRIPTION_DECRYPT_ERROR: int +ALERT_DESCRIPTION_PROTOCOL_VERSION: int +ALERT_DESCRIPTION_INSUFFICIENT_SECURITY: int +ALERT_DESCRIPTION_INTERNAL_ERROR: int +ALERT_DESCRIPTION_USER_CANCELLED: int +ALERT_DESCRIPTION_NO_RENEGOTIATION: int +ALERT_DESCRIPTION_UNSUPPORTED_EXTENSION: int +ALERT_DESCRIPTION_CERTIFICATE_UNOBTAINABLE: int +ALERT_DESCRIPTION_UNRECOGNIZED_NAME: int +ALERT_DESCRIPTION_BAD_CERTIFICATE_STATUS_RESPONSE: int +ALERT_DESCRIPTION_BAD_CERTIFICATE_HASH_VALUE: int +ALERT_DESCRIPTION_UNKNOWN_PSK_IDENTITY: int + +# protocol versions +PROTOCOL_SSLv23: int +PROTOCOL_TLS: int +PROTOCOL_TLS_CLIENT: int +PROTOCOL_TLS_SERVER: int +PROTOCOL_TLSv1: int +PROTOCOL_TLSv1_1: int +PROTOCOL_TLSv1_2: int + +# protocol options +OP_ALL: int +OP_NO_SSLv2: int +OP_NO_SSLv3: int +OP_NO_TLSv1: int +OP_NO_TLSv1_1: int +OP_NO_TLSv1_2: int +OP_NO_TLSv1_3: int +OP_CIPHER_SERVER_PREFERENCE: int +OP_SINGLE_DH_USE: int +OP_NO_TICKET: int +OP_SINGLE_ECDH_USE: int +OP_NO_COMPRESSION: int +OP_ENABLE_MIDDLEBOX_COMPAT: int +OP_NO_RENEGOTIATION: int +if sys.version_info >= (3, 11): + OP_IGNORE_UNEXPECTED_EOF: int +elif sys.version_info >= (3, 8) and sys.platform == "linux": + OP_IGNORE_UNEXPECTED_EOF: int +if sys.version_info >= (3, 12): + OP_LEGACY_SERVER_CONNECT: int + OP_ENABLE_KTLS: int + +# host flags +HOSTFLAG_ALWAYS_CHECK_SUBJECT: int +HOSTFLAG_NEVER_CHECK_SUBJECT: int +HOSTFLAG_NO_WILDCARDS: int +HOSTFLAG_NO_PARTIAL_WILDCARDS: int +HOSTFLAG_MULTI_LABEL_WILDCARDS: int +HOSTFLAG_SINGLE_LABEL_SUBDOMAINS: int + +if sys.version_info >= (3, 10): + # certificate file types + # Typed as Literal so the overload on Certificate.public_bytes can work properly. + ENCODING_PEM: Literal[1] + ENCODING_DER: Literal[2] + +# protocol versions +PROTO_MINIMUM_SUPPORTED: int +PROTO_MAXIMUM_SUPPORTED: int +PROTO_SSLv3: int +PROTO_TLSv1: int +PROTO_TLSv1_1: int +PROTO_TLSv1_2: int +PROTO_TLSv1_3: int + +# feature support +HAS_SNI: bool +HAS_TLS_UNIQUE: bool +HAS_ECDH: bool +HAS_NPN: bool +if sys.version_info >= (3, 13): + HAS_PSK: bool +HAS_ALPN: bool +HAS_SSLv2: bool +HAS_SSLv3: bool +HAS_TLSv1: bool +HAS_TLSv1_1: bool +HAS_TLSv1_2: bool +HAS_TLSv1_3: bool + +# version info +OPENSSL_VERSION_NUMBER: int +OPENSSL_VERSION_INFO: tuple[int, int, int, int, int] +OPENSSL_VERSION: str +_OPENSSL_API_VERSION: tuple[int, int, int, int, int] diff --git a/mypy/typeshed/stdlib/_struct.pyi b/mypy/typeshed/stdlib/_struct.pyi new file mode 100644 index 000000000000..662170e869f3 --- /dev/null +++ b/mypy/typeshed/stdlib/_struct.pyi @@ -0,0 +1,22 @@ +from _typeshed import ReadableBuffer, WriteableBuffer +from collections.abc import Iterator +from typing import Any + +def pack(fmt: str | bytes, /, *v: Any) -> bytes: ... +def pack_into(fmt: str | bytes, buffer: WriteableBuffer, offset: int, /, *v: Any) -> None: ... +def unpack(format: str | bytes, buffer: ReadableBuffer, /) -> tuple[Any, ...]: ... +def unpack_from(format: str | bytes, /, buffer: ReadableBuffer, offset: int = 0) -> tuple[Any, ...]: ... +def iter_unpack(format: str | bytes, buffer: ReadableBuffer, /) -> Iterator[tuple[Any, ...]]: ... +def calcsize(format: str | bytes, /) -> int: ... + +class Struct: + @property + def format(self) -> str: ... + @property + def size(self) -> int: ... + def __init__(self, format: str | bytes) -> None: ... + def pack(self, *v: Any) -> bytes: ... + def pack_into(self, buffer: WriteableBuffer, offset: int, *v: Any) -> None: ... + def unpack(self, buffer: ReadableBuffer, /) -> tuple[Any, ...]: ... + def unpack_from(self, buffer: ReadableBuffer, offset: int = 0) -> tuple[Any, ...]: ... + def iter_unpack(self, buffer: ReadableBuffer, /) -> Iterator[tuple[Any, ...]]: ... diff --git a/mypy/typeshed/stdlib/_thread.pyi b/mypy/typeshed/stdlib/_thread.pyi index b75e7608fa77..f0b70ed2a0b0 100644 --- a/mypy/typeshed/stdlib/_thread.pyi +++ b/mypy/typeshed/stdlib/_thread.pyi @@ -44,6 +44,12 @@ def start_new_thread(function: Callable[[Unpack[_Ts]], object], args: tuple[Unpa @overload def start_new_thread(function: Callable[..., object], args: tuple[Any, ...], kwargs: dict[str, Any], /) -> int: ... +# Obsolete synonym for start_new_thread() +@overload +def start_new(function: Callable[[Unpack[_Ts]], object], args: tuple[Unpack[_Ts]], /) -> int: ... +@overload +def start_new(function: Callable[..., object], args: tuple[Any, ...], kwargs: dict[str, Any], /) -> int: ... + if sys.version_info >= (3, 10): def interrupt_main(signum: signal.Signals = ..., /) -> None: ... @@ -51,7 +57,9 @@ else: def interrupt_main() -> None: ... def exit() -> NoReturn: ... +def exit_thread() -> NoReturn: ... # Obsolete synonym for exit() def allocate_lock() -> LockType: ... +def allocate() -> LockType: ... # Obsolete synonym for allocate_lock() def get_ident() -> int: ... def stack_size(size: int = 0, /) -> int: ... diff --git a/mypy/typeshed/stdlib/_threading_local.pyi b/mypy/typeshed/stdlib/_threading_local.pyi index 98683dabcef8..07a825f0d816 100644 --- a/mypy/typeshed/stdlib/_threading_local.pyi +++ b/mypy/typeshed/stdlib/_threading_local.pyi @@ -1,5 +1,6 @@ +from threading import RLock from typing import Any -from typing_extensions import TypeAlias +from typing_extensions import Self, TypeAlias from weakref import ReferenceType __all__ = ["local"] @@ -8,10 +9,14 @@ _LocalDict: TypeAlias = dict[Any, Any] class _localimpl: key: str dicts: dict[int, tuple[ReferenceType[Any], _LocalDict]] + # Keep localargs in sync with the *args, **kwargs annotation on local.__new__ + localargs: tuple[list[Any], dict[str, Any]] + locallock: RLock def get_dict(self) -> _LocalDict: ... def create_dict(self) -> _LocalDict: ... class local: + def __new__(cls, /, *args: Any, **kw: Any) -> Self: ... def __getattribute__(self, name: str) -> Any: ... def __setattr__(self, name: str, value: Any) -> None: ... def __delattr__(self, name: str) -> None: ... diff --git a/mypy/typeshed/stdlib/_weakref.pyi b/mypy/typeshed/stdlib/_weakref.pyi index f142820c56c7..a744340afaab 100644 --- a/mypy/typeshed/stdlib/_weakref.pyi +++ b/mypy/typeshed/stdlib/_weakref.pyi @@ -1,37 +1,10 @@ -import sys from collections.abc import Callable -from typing import Any, Generic, TypeVar, final, overload -from typing_extensions import Self - -if sys.version_info >= (3, 9): - from types import GenericAlias +from typing import Any, TypeVar, overload +from weakref import CallableProxyType as CallableProxyType, ProxyType as ProxyType, ReferenceType as ReferenceType, ref as ref _C = TypeVar("_C", bound=Callable[..., Any]) _T = TypeVar("_T") -@final -class CallableProxyType(Generic[_C]): # "weakcallableproxy" - def __eq__(self, value: object, /) -> bool: ... - def __getattr__(self, attr: str) -> Any: ... - __call__: _C - -@final -class ProxyType(Generic[_T]): # "weakproxy" - def __eq__(self, value: object, /) -> bool: ... - def __getattr__(self, attr: str) -> Any: ... - -class ReferenceType(Generic[_T]): - __callback__: Callable[[Self], Any] - def __new__(cls, o: _T, callback: Callable[[Self], Any] | None = ..., /) -> Self: ... - def __init__(self, o: _T, callback: Callable[[Self], Any] | None = ..., /) -> None: ... - def __call__(self) -> _T | None: ... - def __eq__(self, value: object, /) -> bool: ... - def __hash__(self) -> int: ... - if sys.version_info >= (3, 9): - def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... - -ref = ReferenceType - def getweakrefcount(object: Any, /) -> int: ... def getweakrefs(object: Any, /) -> list[Any]: ... diff --git a/mypy/typeshed/stdlib/ast.pyi b/mypy/typeshed/stdlib/ast.pyi index 80049cff4ce0..351a4af2fb75 100644 --- a/mypy/typeshed/stdlib/ast.pyi +++ b/mypy/typeshed/stdlib/ast.pyi @@ -1,184 +1,1717 @@ import os import sys -from _ast import * +import typing_extensions +from _ast import ( + PyCF_ALLOW_TOP_LEVEL_AWAIT as PyCF_ALLOW_TOP_LEVEL_AWAIT, + PyCF_ONLY_AST as PyCF_ONLY_AST, + PyCF_TYPE_COMMENTS as PyCF_TYPE_COMMENTS, +) from _typeshed import ReadableBuffer, Unused from collections.abc import Iterator -from typing import Any, Literal, TypeVar as _TypeVar, overload -from typing_extensions import deprecated +from typing import Any, ClassVar, Generic, Literal, TypedDict, TypeVar as _TypeVar, overload +from typing_extensions import Self, Unpack, deprecated -class _ABC(type): - if sys.version_info >= (3, 9): - def __init__(cls, *args: Unused) -> None: ... +if sys.version_info >= (3, 13): + from _ast import PyCF_OPTIMIZED_AST as PyCF_OPTIMIZED_AST -if sys.version_info < (3, 14): - @deprecated("Replaced by ast.Constant; removed in Python 3.14") - class Num(Constant, metaclass=_ABC): - value: int | float | complex +# Alias used for fields that must always be valid identifiers +# A string `x` counts as a valid identifier if both the following are True +# (1) `x.isidentifier()` evaluates to `True` +# (2) `keyword.iskeyword(x)` evaluates to `False` +_Identifier: typing_extensions.TypeAlias = str - @deprecated("Replaced by ast.Constant; removed in Python 3.14") - class Str(Constant, metaclass=_ABC): - value: str - # Aliases for value, for backwards compatibility - s: str +# Used for node end positions in constructor keyword arguments +_EndPositionT = typing_extensions.TypeVar("_EndPositionT", int, int | None, default=int | None) - @deprecated("Replaced by ast.Constant; removed in Python 3.14") - class Bytes(Constant, metaclass=_ABC): - value: bytes +# Corresponds to the names in the `_attributes` class variable which is non-empty in certain AST nodes +class _Attributes(TypedDict, Generic[_EndPositionT], total=False): + lineno: int + col_offset: int + end_lineno: _EndPositionT + end_col_offset: _EndPositionT + +# The various AST classes are implemented in C, and imported from _ast at runtime, +# but they consider themselves to live in the ast module, +# so we'll define the stubs in this file. +class AST: + if sys.version_info >= (3, 10): + __match_args__ = () + _attributes: ClassVar[tuple[str, ...]] + _fields: ClassVar[tuple[str, ...]] + if sys.version_info >= (3, 13): + _field_types: ClassVar[dict[str, Any]] + + if sys.version_info >= (3, 14): + def __replace__(self) -> Self: ... + +class mod(AST): ... + +class Module(mod): + if sys.version_info >= (3, 10): + __match_args__ = ("body", "type_ignores") + body: list[stmt] + type_ignores: list[TypeIgnore] + if sys.version_info >= (3, 13): + def __init__(self, body: list[stmt] = ..., type_ignores: list[TypeIgnore] = ...) -> None: ... + else: + def __init__(self, body: list[stmt], type_ignores: list[TypeIgnore]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, body: list[stmt] = ..., type_ignores: list[TypeIgnore] = ...) -> Self: ... + +class Interactive(mod): + if sys.version_info >= (3, 10): + __match_args__ = ("body",) + body: list[stmt] + if sys.version_info >= (3, 13): + def __init__(self, body: list[stmt] = ...) -> None: ... + else: + def __init__(self, body: list[stmt]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, body: list[stmt] = ...) -> Self: ... + +class Expression(mod): + if sys.version_info >= (3, 10): + __match_args__ = ("body",) + body: expr + def __init__(self, body: expr) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, body: expr = ...) -> Self: ... + +class FunctionType(mod): + if sys.version_info >= (3, 10): + __match_args__ = ("argtypes", "returns") + argtypes: list[expr] + returns: expr + if sys.version_info >= (3, 13): + @overload + def __init__(self, argtypes: list[expr], returns: expr) -> None: ... + @overload + def __init__(self, argtypes: list[expr] = ..., *, returns: expr) -> None: ... + else: + def __init__(self, argtypes: list[expr], returns: expr) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, argtypes: list[expr] = ..., returns: expr = ...) -> Self: ... + +class stmt(AST): + lineno: int + col_offset: int + end_lineno: int | None + end_col_offset: int | None + def __init__(self, **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, **kwargs: Unpack[_Attributes]) -> Self: ... + +class FunctionDef(stmt): + if sys.version_info >= (3, 12): + __match_args__ = ("name", "args", "body", "decorator_list", "returns", "type_comment", "type_params") + elif sys.version_info >= (3, 10): + __match_args__ = ("name", "args", "body", "decorator_list", "returns", "type_comment") + name: _Identifier + args: arguments + body: list[stmt] + decorator_list: list[expr] + returns: expr | None + type_comment: str | None + if sys.version_info >= (3, 12): + type_params: list[type_param] + if sys.version_info >= (3, 13): + def __init__( + self, + name: _Identifier, + args: arguments, + body: list[stmt] = ..., + decorator_list: list[expr] = ..., + returns: expr | None = None, + type_comment: str | None = None, + type_params: list[type_param] = ..., + **kwargs: Unpack[_Attributes], + ) -> None: ... + elif sys.version_info >= (3, 12): + @overload + def __init__( + self, + name: _Identifier, + args: arguments, + body: list[stmt], + decorator_list: list[expr], + returns: expr | None, + type_comment: str | None, + type_params: list[type_param], + **kwargs: Unpack[_Attributes], + ) -> None: ... + @overload + def __init__( + self, + name: _Identifier, + args: arguments, + body: list[stmt], + decorator_list: list[expr], + returns: expr | None = None, + type_comment: str | None = None, + *, + type_params: list[type_param], + **kwargs: Unpack[_Attributes], + ) -> None: ... + else: + def __init__( + self, + name: _Identifier, + args: arguments, + body: list[stmt], + decorator_list: list[expr], + returns: expr | None = None, + type_comment: str | None = None, + **kwargs: Unpack[_Attributes], + ) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, + *, + name: _Identifier = ..., + args: arguments = ..., + body: list[stmt] = ..., + decorator_list: list[expr] = ..., + returns: expr | None = ..., + type_comment: str | None = ..., + type_params: list[type_param] = ..., + ) -> Self: ... + +class AsyncFunctionDef(stmt): + if sys.version_info >= (3, 12): + __match_args__ = ("name", "args", "body", "decorator_list", "returns", "type_comment", "type_params") + elif sys.version_info >= (3, 10): + __match_args__ = ("name", "args", "body", "decorator_list", "returns", "type_comment") + name: _Identifier + args: arguments + body: list[stmt] + decorator_list: list[expr] + returns: expr | None + type_comment: str | None + if sys.version_info >= (3, 12): + type_params: list[type_param] + if sys.version_info >= (3, 13): + def __init__( + self, + name: _Identifier, + args: arguments, + body: list[stmt] = ..., + decorator_list: list[expr] = ..., + returns: expr | None = None, + type_comment: str | None = None, + type_params: list[type_param] = ..., + **kwargs: Unpack[_Attributes], + ) -> None: ... + elif sys.version_info >= (3, 12): + @overload + def __init__( + self, + name: _Identifier, + args: arguments, + body: list[stmt], + decorator_list: list[expr], + returns: expr | None, + type_comment: str | None, + type_params: list[type_param], + **kwargs: Unpack[_Attributes], + ) -> None: ... + @overload + def __init__( + self, + name: _Identifier, + args: arguments, + body: list[stmt], + decorator_list: list[expr], + returns: expr | None = None, + type_comment: str | None = None, + *, + type_params: list[type_param], + **kwargs: Unpack[_Attributes], + ) -> None: ... + else: + def __init__( + self, + name: _Identifier, + args: arguments, + body: list[stmt], + decorator_list: list[expr], + returns: expr | None = None, + type_comment: str | None = None, + **kwargs: Unpack[_Attributes], + ) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, + *, + name: _Identifier = ..., + args: arguments = ..., + body: list[stmt], + decorator_list: list[expr], + returns: expr | None, + type_comment: str | None, + type_params: list[type_param], + ) -> Self: ... + +class ClassDef(stmt): + if sys.version_info >= (3, 12): + __match_args__ = ("name", "bases", "keywords", "body", "decorator_list", "type_params") + elif sys.version_info >= (3, 10): + __match_args__ = ("name", "bases", "keywords", "body", "decorator_list") + name: _Identifier + bases: list[expr] + keywords: list[keyword] + body: list[stmt] + decorator_list: list[expr] + if sys.version_info >= (3, 12): + type_params: list[type_param] + if sys.version_info >= (3, 13): + def __init__( + self, + name: _Identifier, + bases: list[expr] = ..., + keywords: list[keyword] = ..., + body: list[stmt] = ..., + decorator_list: list[expr] = ..., + type_params: list[type_param] = ..., + **kwargs: Unpack[_Attributes], + ) -> None: ... + elif sys.version_info >= (3, 12): + def __init__( + self, + name: _Identifier, + bases: list[expr], + keywords: list[keyword], + body: list[stmt], + decorator_list: list[expr], + type_params: list[type_param], + **kwargs: Unpack[_Attributes], + ) -> None: ... + else: + def __init__( + self, + name: _Identifier, + bases: list[expr], + keywords: list[keyword], + body: list[stmt], + decorator_list: list[expr], + **kwargs: Unpack[_Attributes], + ) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, + *, + name: _Identifier, + bases: list[expr], + keywords: list[keyword], + body: list[stmt], + decorator_list: list[expr], + type_params: list[type_param], + **kwargs: Unpack[_Attributes], + ) -> Self: ... + +class Return(stmt): + if sys.version_info >= (3, 10): + __match_args__ = ("value",) + value: expr | None + def __init__(self, value: expr | None = None, **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, value: expr | None = ..., **kwargs: Unpack[_Attributes]) -> Self: ... + +class Delete(stmt): + if sys.version_info >= (3, 10): + __match_args__ = ("targets",) + targets: list[expr] + if sys.version_info >= (3, 13): + def __init__(self, targets: list[expr] = ..., **kwargs: Unpack[_Attributes]) -> None: ... + else: + def __init__(self, targets: list[expr], **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, targets: list[expr] = ..., **kwargs: Unpack[_Attributes]) -> Self: ... + +class Assign(stmt): + if sys.version_info >= (3, 10): + __match_args__ = ("targets", "value", "type_comment") + targets: list[expr] + value: expr + type_comment: str | None + if sys.version_info >= (3, 13): + @overload + def __init__( + self, targets: list[expr], value: expr, type_comment: str | None = None, **kwargs: Unpack[_Attributes] + ) -> None: ... + @overload + def __init__( + self, targets: list[expr] = ..., *, value: expr, type_comment: str | None = None, **kwargs: Unpack[_Attributes] + ) -> None: ... + else: + def __init__( + self, targets: list[expr], value: expr, type_comment: str | None = None, **kwargs: Unpack[_Attributes] + ) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, *, targets: list[expr] = ..., value: expr = ..., type_comment: str | None = ..., **kwargs: Unpack[_Attributes] + ) -> Self: ... + +if sys.version_info >= (3, 12): + class TypeAlias(stmt): + __match_args__ = ("name", "type_params", "value") + name: Name + type_params: list[type_param] + value: expr + if sys.version_info >= (3, 13): + @overload + def __init__( + self, name: Name, type_params: list[type_param], value: expr, **kwargs: Unpack[_Attributes[int]] + ) -> None: ... + @overload + def __init__( + self, name: Name, type_params: list[type_param] = ..., *, value: expr, **kwargs: Unpack[_Attributes[int]] + ) -> None: ... + else: + def __init__( + self, name: Name, type_params: list[type_param], value: expr, **kwargs: Unpack[_Attributes[int]] + ) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, + *, + name: Name = ..., + type_params: list[type_param] = ..., + value: expr = ..., + **kwargs: Unpack[_Attributes[int]], + ) -> Self: ... + +class AugAssign(stmt): + if sys.version_info >= (3, 10): + __match_args__ = ("target", "op", "value") + target: Name | Attribute | Subscript + op: operator + value: expr + def __init__( + self, target: Name | Attribute | Subscript, op: operator, value: expr, **kwargs: Unpack[_Attributes] + ) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, + *, + target: Name | Attribute | Subscript = ..., + op: operator = ..., + value: expr = ..., + **kwargs: Unpack[_Attributes], + ) -> Self: ... + +class AnnAssign(stmt): + if sys.version_info >= (3, 10): + __match_args__ = ("target", "annotation", "value", "simple") + target: Name | Attribute | Subscript + annotation: expr + value: expr | None + simple: int + @overload + def __init__( + self, + target: Name | Attribute | Subscript, + annotation: expr, + value: expr | None, + simple: int, + **kwargs: Unpack[_Attributes], + ) -> None: ... + @overload + def __init__( + self, + target: Name | Attribute | Subscript, + annotation: expr, + value: expr | None = None, + *, + simple: int, + **kwargs: Unpack[_Attributes], + ) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, + *, + target: Name | Attribute | Subscript = ..., + annotation: expr = ..., + value: expr | None = ..., + simple: int = ..., + **kwargs: Unpack[_Attributes], + ) -> Self: ... + +class For(stmt): + if sys.version_info >= (3, 10): + __match_args__ = ("target", "iter", "body", "orelse", "type_comment") + target: expr + iter: expr + body: list[stmt] + orelse: list[stmt] + type_comment: str | None + if sys.version_info >= (3, 13): + def __init__( + self, + target: expr, + iter: expr, + body: list[stmt] = ..., + orelse: list[stmt] = ..., + type_comment: str | None = None, + **kwargs: Unpack[_Attributes], + ) -> None: ... + else: + def __init__( + self, + target: expr, + iter: expr, + body: list[stmt], + orelse: list[stmt], + type_comment: str | None = None, + **kwargs: Unpack[_Attributes], + ) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, + *, + target: expr = ..., + iter: expr = ..., + body: list[stmt] = ..., + orelse: list[stmt] = ..., + type_comment: str | None = ..., + **kwargs: Unpack[_Attributes], + ) -> Self: ... + +class AsyncFor(stmt): + if sys.version_info >= (3, 10): + __match_args__ = ("target", "iter", "body", "orelse", "type_comment") + target: expr + iter: expr + body: list[stmt] + orelse: list[stmt] + type_comment: str | None + if sys.version_info >= (3, 13): + def __init__( + self, + target: expr, + iter: expr, + body: list[stmt] = ..., + orelse: list[stmt] = ..., + type_comment: str | None = None, + **kwargs: Unpack[_Attributes], + ) -> None: ... + else: + def __init__( + self, + target: expr, + iter: expr, + body: list[stmt], + orelse: list[stmt], + type_comment: str | None = None, + **kwargs: Unpack[_Attributes], + ) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, + *, + target: expr = ..., + iter: expr = ..., + body: list[stmt] = ..., + orelse: list[stmt] = ..., + type_comment: str | None = ..., + **kwargs: Unpack[_Attributes], + ) -> Self: ... + +class While(stmt): + if sys.version_info >= (3, 10): + __match_args__ = ("test", "body", "orelse") + test: expr + body: list[stmt] + orelse: list[stmt] + if sys.version_info >= (3, 13): + def __init__( + self, test: expr, body: list[stmt] = ..., orelse: list[stmt] = ..., **kwargs: Unpack[_Attributes] + ) -> None: ... + else: + def __init__(self, test: expr, body: list[stmt], orelse: list[stmt], **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, test: expr, body: list[stmt], orelse: list[stmt], **kwargs: Unpack[_Attributes]) -> Self: ... + +class If(stmt): + if sys.version_info >= (3, 10): + __match_args__ = ("test", "body", "orelse") + test: expr + body: list[stmt] + orelse: list[stmt] + if sys.version_info >= (3, 13): + def __init__( + self, test: expr, body: list[stmt] = ..., orelse: list[stmt] = ..., **kwargs: Unpack[_Attributes] + ) -> None: ... + else: + def __init__(self, test: expr, body: list[stmt], orelse: list[stmt], **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, *, test: expr = ..., body: list[stmt] = ..., orelse: list[stmt] = ..., **kwargs: Unpack[_Attributes] + ) -> Self: ... + +class With(stmt): + if sys.version_info >= (3, 10): + __match_args__ = ("items", "body", "type_comment") + items: list[withitem] + body: list[stmt] + type_comment: str | None + if sys.version_info >= (3, 13): + def __init__( + self, + items: list[withitem] = ..., + body: list[stmt] = ..., + type_comment: str | None = None, + **kwargs: Unpack[_Attributes], + ) -> None: ... + else: + def __init__( + self, items: list[withitem], body: list[stmt], type_comment: str | None = None, **kwargs: Unpack[_Attributes] + ) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, + *, + items: list[withitem] = ..., + body: list[stmt] = ..., + type_comment: str | None = ..., + **kwargs: Unpack[_Attributes], + ) -> Self: ... + +class AsyncWith(stmt): + if sys.version_info >= (3, 10): + __match_args__ = ("items", "body", "type_comment") + items: list[withitem] + body: list[stmt] + type_comment: str | None + if sys.version_info >= (3, 13): + def __init__( + self, + items: list[withitem] = ..., + body: list[stmt] = ..., + type_comment: str | None = None, + **kwargs: Unpack[_Attributes], + ) -> None: ... + else: + def __init__( + self, items: list[withitem], body: list[stmt], type_comment: str | None = None, **kwargs: Unpack[_Attributes] + ) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, + *, + items: list[withitem] = ..., + body: list[stmt] = ..., + type_comment: str | None = ..., + **kwargs: Unpack[_Attributes], + ) -> Self: ... + +if sys.version_info >= (3, 10): + class Match(stmt): + __match_args__ = ("subject", "cases") + subject: expr + cases: list[match_case] + if sys.version_info >= (3, 13): + def __init__(self, subject: expr, cases: list[match_case] = ..., **kwargs: Unpack[_Attributes]) -> None: ... + else: + def __init__(self, subject: expr, cases: list[match_case], **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, *, subject: expr = ..., cases: list[match_case] = ..., **kwargs: Unpack[_Attributes] + ) -> Self: ... + +class Raise(stmt): + if sys.version_info >= (3, 10): + __match_args__ = ("exc", "cause") + exc: expr | None + cause: expr | None + def __init__(self, exc: expr | None = None, cause: expr | None = None, **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, exc: expr | None = ..., cause: expr | None = ..., **kwargs: Unpack[_Attributes]) -> Self: ... + +class Try(stmt): + if sys.version_info >= (3, 10): + __match_args__ = ("body", "handlers", "orelse", "finalbody") + body: list[stmt] + handlers: list[ExceptHandler] + orelse: list[stmt] + finalbody: list[stmt] + if sys.version_info >= (3, 13): + def __init__( + self, + body: list[stmt] = ..., + handlers: list[ExceptHandler] = ..., + orelse: list[stmt] = ..., + finalbody: list[stmt] = ..., + **kwargs: Unpack[_Attributes], + ) -> None: ... + else: + def __init__( + self, + body: list[stmt], + handlers: list[ExceptHandler], + orelse: list[stmt], + finalbody: list[stmt], + **kwargs: Unpack[_Attributes], + ) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, + *, + body: list[stmt] = ..., + handlers: list[ExceptHandler] = ..., + orelse: list[stmt] = ..., + finalbody: list[stmt] = ..., + **kwargs: Unpack[_Attributes], + ) -> Self: ... + +if sys.version_info >= (3, 11): + class TryStar(stmt): + __match_args__ = ("body", "handlers", "orelse", "finalbody") + body: list[stmt] + handlers: list[ExceptHandler] + orelse: list[stmt] + finalbody: list[stmt] + if sys.version_info >= (3, 13): + def __init__( + self, + body: list[stmt] = ..., + handlers: list[ExceptHandler] = ..., + orelse: list[stmt] = ..., + finalbody: list[stmt] = ..., + **kwargs: Unpack[_Attributes], + ) -> None: ... + else: + def __init__( + self, + body: list[stmt], + handlers: list[ExceptHandler], + orelse: list[stmt], + finalbody: list[stmt], + **kwargs: Unpack[_Attributes], + ) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, + *, + body: list[stmt] = ..., + handlers: list[ExceptHandler] = ..., + orelse: list[stmt] = ..., + finalbody: list[stmt] = ..., + **kwargs: Unpack[_Attributes], + ) -> Self: ... + +class Assert(stmt): + if sys.version_info >= (3, 10): + __match_args__ = ("test", "msg") + test: expr + msg: expr | None + def __init__(self, test: expr, msg: expr | None = None, **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, test: expr, msg: expr | None, **kwargs: Unpack[_Attributes]) -> Self: ... + +class Import(stmt): + if sys.version_info >= (3, 10): + __match_args__ = ("names",) + names: list[alias] + if sys.version_info >= (3, 13): + def __init__(self, names: list[alias] = ..., **kwargs: Unpack[_Attributes]) -> None: ... + else: + def __init__(self, names: list[alias], **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, names: list[alias] = ..., **kwargs: Unpack[_Attributes]) -> Self: ... + +class ImportFrom(stmt): + if sys.version_info >= (3, 10): + __match_args__ = ("module", "names", "level") + module: str | None + names: list[alias] + level: int + if sys.version_info >= (3, 13): + @overload + def __init__(self, module: str | None, names: list[alias], level: int, **kwargs: Unpack[_Attributes]) -> None: ... + @overload + def __init__( + self, module: str | None = None, names: list[alias] = ..., *, level: int, **kwargs: Unpack[_Attributes] + ) -> None: ... + else: + @overload + def __init__(self, module: str | None, names: list[alias], level: int, **kwargs: Unpack[_Attributes]) -> None: ... + @overload + def __init__( + self, module: str | None = None, *, names: list[alias], level: int, **kwargs: Unpack[_Attributes] + ) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, *, module: str | None = ..., names: list[alias] = ..., level: int = ..., **kwargs: Unpack[_Attributes] + ) -> Self: ... + +class Global(stmt): + if sys.version_info >= (3, 10): + __match_args__ = ("names",) + names: list[_Identifier] + if sys.version_info >= (3, 13): + def __init__(self, names: list[_Identifier] = ..., **kwargs: Unpack[_Attributes]) -> None: ... + else: + def __init__(self, names: list[_Identifier], **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, names: list[_Identifier], **kwargs: Unpack[_Attributes]) -> Self: ... + +class Nonlocal(stmt): + if sys.version_info >= (3, 10): + __match_args__ = ("names",) + names: list[_Identifier] + if sys.version_info >= (3, 13): + def __init__(self, names: list[_Identifier] = ..., **kwargs: Unpack[_Attributes]) -> None: ... + else: + def __init__(self, names: list[_Identifier], **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, names: list[_Identifier] = ..., **kwargs: Unpack[_Attributes]) -> Self: ... + +class Expr(stmt): + if sys.version_info >= (3, 10): + __match_args__ = ("value",) + value: expr + def __init__(self, value: expr, **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, value: expr = ..., **kwargs: Unpack[_Attributes]) -> Self: ... + +class Pass(stmt): ... +class Break(stmt): ... +class Continue(stmt): ... + +class expr(AST): + lineno: int + col_offset: int + end_lineno: int | None + end_col_offset: int | None + def __init__(self, **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, **kwargs: Unpack[_Attributes]) -> Self: ... + +class BoolOp(expr): + if sys.version_info >= (3, 10): + __match_args__ = ("op", "values") + op: boolop + values: list[expr] + if sys.version_info >= (3, 13): + def __init__(self, op: boolop, values: list[expr] = ..., **kwargs: Unpack[_Attributes]) -> None: ... + else: + def __init__(self, op: boolop, values: list[expr], **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, op: boolop = ..., values: list[expr] = ..., **kwargs: Unpack[_Attributes]) -> Self: ... + +class NamedExpr(expr): + if sys.version_info >= (3, 10): + __match_args__ = ("target", "value") + target: Name + value: expr + def __init__(self, target: Name, value: expr, **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, target: Name = ..., value: expr = ..., **kwargs: Unpack[_Attributes]) -> Self: ... + +class BinOp(expr): + if sys.version_info >= (3, 10): + __match_args__ = ("left", "op", "right") + left: expr + op: operator + right: expr + def __init__(self, left: expr, op: operator, right: expr, **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, *, left: expr = ..., op: operator = ..., right: expr = ..., **kwargs: Unpack[_Attributes] + ) -> Self: ... + +class UnaryOp(expr): + if sys.version_info >= (3, 10): + __match_args__ = ("op", "operand") + op: unaryop + operand: expr + def __init__(self, op: unaryop, operand: expr, **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, op: unaryop = ..., operand: expr = ..., **kwargs: Unpack[_Attributes]) -> Self: ... + +class Lambda(expr): + if sys.version_info >= (3, 10): + __match_args__ = ("args", "body") + args: arguments + body: expr + def __init__(self, args: arguments, body: expr, **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, args: arguments = ..., body: expr = ..., **kwargs: Unpack[_Attributes]) -> Self: ... + +class IfExp(expr): + if sys.version_info >= (3, 10): + __match_args__ = ("test", "body", "orelse") + test: expr + body: expr + orelse: expr + def __init__(self, test: expr, body: expr, orelse: expr, **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, *, test: expr = ..., body: expr = ..., orelse: expr = ..., **kwargs: Unpack[_Attributes] + ) -> Self: ... + +class Dict(expr): + if sys.version_info >= (3, 10): + __match_args__ = ("keys", "values") + keys: list[expr | None] + values: list[expr] + if sys.version_info >= (3, 13): + def __init__(self, keys: list[expr | None] = ..., values: list[expr] = ..., **kwargs: Unpack[_Attributes]) -> None: ... + else: + def __init__(self, keys: list[expr | None], values: list[expr], **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, *, keys: list[expr | None] = ..., values: list[expr] = ..., **kwargs: Unpack[_Attributes] + ) -> Self: ... + +class Set(expr): + if sys.version_info >= (3, 10): + __match_args__ = ("elts",) + elts: list[expr] + if sys.version_info >= (3, 13): + def __init__(self, elts: list[expr] = ..., **kwargs: Unpack[_Attributes]) -> None: ... + else: + def __init__(self, elts: list[expr], **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, elts: list[expr] = ..., **kwargs: Unpack[_Attributes]) -> Self: ... + +class ListComp(expr): + if sys.version_info >= (3, 10): + __match_args__ = ("elt", "generators") + elt: expr + generators: list[comprehension] + if sys.version_info >= (3, 13): + def __init__(self, elt: expr, generators: list[comprehension] = ..., **kwargs: Unpack[_Attributes]) -> None: ... + else: + def __init__(self, elt: expr, generators: list[comprehension], **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, *, elt: expr = ..., generators: list[comprehension] = ..., **kwargs: Unpack[_Attributes] + ) -> Self: ... + +class SetComp(expr): + if sys.version_info >= (3, 10): + __match_args__ = ("elt", "generators") + elt: expr + generators: list[comprehension] + if sys.version_info >= (3, 13): + def __init__(self, elt: expr, generators: list[comprehension] = ..., **kwargs: Unpack[_Attributes]) -> None: ... + else: + def __init__(self, elt: expr, generators: list[comprehension], **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, *, elt: expr = ..., generators: list[comprehension] = ..., **kwargs: Unpack[_Attributes] + ) -> Self: ... + +class DictComp(expr): + if sys.version_info >= (3, 10): + __match_args__ = ("key", "value", "generators") + key: expr + value: expr + generators: list[comprehension] + if sys.version_info >= (3, 13): + def __init__( + self, key: expr, value: expr, generators: list[comprehension] = ..., **kwargs: Unpack[_Attributes] + ) -> None: ... + else: + def __init__(self, key: expr, value: expr, generators: list[comprehension], **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, *, key: expr = ..., value: expr = ..., generators: list[comprehension] = ..., **kwargs: Unpack[_Attributes] + ) -> Self: ... + +class GeneratorExp(expr): + if sys.version_info >= (3, 10): + __match_args__ = ("elt", "generators") + elt: expr + generators: list[comprehension] + if sys.version_info >= (3, 13): + def __init__(self, elt: expr, generators: list[comprehension] = ..., **kwargs: Unpack[_Attributes]) -> None: ... + else: + def __init__(self, elt: expr, generators: list[comprehension], **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, *, elt: expr = ..., generators: list[comprehension] = ..., **kwargs: Unpack[_Attributes] + ) -> Self: ... + +class Await(expr): + if sys.version_info >= (3, 10): + __match_args__ = ("value",) + value: expr + def __init__(self, value: expr, **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, value: expr = ..., **kwargs: Unpack[_Attributes]) -> Self: ... + +class Yield(expr): + if sys.version_info >= (3, 10): + __match_args__ = ("value",) + value: expr | None + def __init__(self, value: expr | None = None, **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, value: expr | None = ..., **kwargs: Unpack[_Attributes]) -> Self: ... + +class YieldFrom(expr): + if sys.version_info >= (3, 10): + __match_args__ = ("value",) + value: expr + def __init__(self, value: expr, **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, value: expr = ..., **kwargs: Unpack[_Attributes]) -> Self: ... + +class Compare(expr): + if sys.version_info >= (3, 10): + __match_args__ = ("left", "ops", "comparators") + left: expr + ops: list[cmpop] + comparators: list[expr] + if sys.version_info >= (3, 13): + def __init__( + self, left: expr, ops: list[cmpop] = ..., comparators: list[expr] = ..., **kwargs: Unpack[_Attributes] + ) -> None: ... + else: + def __init__(self, left: expr, ops: list[cmpop], comparators: list[expr], **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, *, left: expr = ..., ops: list[cmpop] = ..., comparators: list[expr] = ..., **kwargs: Unpack[_Attributes] + ) -> Self: ... + +class Call(expr): + if sys.version_info >= (3, 10): + __match_args__ = ("func", "args", "keywords") + func: expr + args: list[expr] + keywords: list[keyword] + if sys.version_info >= (3, 13): + def __init__( + self, func: expr, args: list[expr] = ..., keywords: list[keyword] = ..., **kwargs: Unpack[_Attributes] + ) -> None: ... + else: + def __init__(self, func: expr, args: list[expr], keywords: list[keyword], **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, *, func: expr = ..., args: list[expr] = ..., keywords: list[keyword] = ..., **kwargs: Unpack[_Attributes] + ) -> Self: ... + +class FormattedValue(expr): + if sys.version_info >= (3, 10): + __match_args__ = ("value", "conversion", "format_spec") + value: expr + conversion: int + format_spec: expr | None + def __init__(self, value: expr, conversion: int, format_spec: expr | None = None, **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, *, value: expr = ..., conversion: int = ..., format_spec: expr | None = ..., **kwargs: Unpack[_Attributes] + ) -> Self: ... + +class JoinedStr(expr): + if sys.version_info >= (3, 10): + __match_args__ = ("values",) + values: list[expr] + if sys.version_info >= (3, 13): + def __init__(self, values: list[expr] = ..., **kwargs: Unpack[_Attributes]) -> None: ... + else: + def __init__(self, values: list[expr], **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, values: list[expr] = ..., **kwargs: Unpack[_Attributes]) -> Self: ... + +class Constant(expr): + if sys.version_info >= (3, 10): + __match_args__ = ("value", "kind") + value: Any # None, str, bytes, bool, int, float, complex, Ellipsis + kind: str | None + if sys.version_info < (3, 14): # Aliases for value, for backwards compatibility - s: bytes + s: Any + n: int | float | complex - @deprecated("Replaced by ast.Constant; removed in Python 3.14") - class NameConstant(Constant, metaclass=_ABC): ... + def __init__(self, value: Any, kind: str | None = None, **kwargs: Unpack[_Attributes]) -> None: ... - @deprecated("Replaced by ast.Constant; removed in Python 3.14") - class Ellipsis(Constant, metaclass=_ABC): ... + if sys.version_info >= (3, 14): + def __replace__(self, *, value: Any = ..., kind: str | None = ..., **kwargs: Unpack[_Attributes]) -> Self: ... + +class Attribute(expr): + if sys.version_info >= (3, 10): + __match_args__ = ("value", "attr", "ctx") + value: expr + attr: _Identifier + ctx: expr_context # Not present in Python < 3.13 if not passed to `__init__` + def __init__(self, value: expr, attr: _Identifier, ctx: expr_context = ..., **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, *, value: expr = ..., attr: _Identifier = ..., ctx: expr_context = ..., **kwargs: Unpack[_Attributes] + ) -> Self: ... + +class Subscript(expr): + if sys.version_info >= (3, 10): + __match_args__ = ("value", "slice", "ctx") + value: expr + slice: _Slice + ctx: expr_context # Not present in Python < 3.13 if not passed to `__init__` + def __init__(self, value: expr, slice: _Slice, ctx: expr_context = ..., **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, *, value: expr = ..., slice: _Slice = ..., ctx: expr_context = ..., **kwargs: Unpack[_Attributes] + ) -> Self: ... + +class Starred(expr): + if sys.version_info >= (3, 10): + __match_args__ = ("value", "ctx") + value: expr + ctx: expr_context # Not present in Python < 3.13 if not passed to `__init__` + def __init__(self, value: expr, ctx: expr_context = ..., **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, value: expr = ..., ctx: expr_context = ..., **kwargs: Unpack[_Attributes]) -> Self: ... + +class Name(expr): + if sys.version_info >= (3, 10): + __match_args__ = ("id", "ctx") + id: _Identifier + ctx: expr_context # Not present in Python < 3.13 if not passed to `__init__` + def __init__(self, id: _Identifier, ctx: expr_context = ..., **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, id: _Identifier = ..., ctx: expr_context = ..., **kwargs: Unpack[_Attributes]) -> Self: ... + +class List(expr): + if sys.version_info >= (3, 10): + __match_args__ = ("elts", "ctx") + elts: list[expr] + ctx: expr_context # Not present in Python < 3.13 if not passed to `__init__` + if sys.version_info >= (3, 13): + def __init__(self, elts: list[expr] = ..., ctx: expr_context = ..., **kwargs: Unpack[_Attributes]) -> None: ... + else: + def __init__(self, elts: list[expr], ctx: expr_context = ..., **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, elts: list[expr] = ..., ctx: expr_context = ..., **kwargs: Unpack[_Attributes]) -> Self: ... + +class Tuple(expr): + if sys.version_info >= (3, 10): + __match_args__ = ("elts", "ctx") + elts: list[expr] + ctx: expr_context # Not present in Python < 3.13 if not passed to `__init__` + if sys.version_info >= (3, 9): + dims: list[expr] + if sys.version_info >= (3, 13): + def __init__(self, elts: list[expr] = ..., ctx: expr_context = ..., **kwargs: Unpack[_Attributes]) -> None: ... + else: + def __init__(self, elts: list[expr], ctx: expr_context = ..., **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, elts: list[expr] = ..., ctx: expr_context = ..., **kwargs: Unpack[_Attributes]) -> Self: ... + +class slice(AST): ... # deprecated and moved to ast.py for >= (3, 9) if sys.version_info >= (3, 9): - class slice(AST): ... - class ExtSlice(slice): ... - class Index(slice): ... - class Suite(mod): ... - class AugLoad(expr_context): ... - class AugStore(expr_context): ... - class Param(expr_context): ... + _Slice: typing_extensions.TypeAlias = expr + _SliceAttributes: typing_extensions.TypeAlias = _Attributes +else: + # alias for use with variables named slice + _Slice: typing_extensions.TypeAlias = slice -class NodeVisitor: - def visit(self, node: AST) -> Any: ... - def generic_visit(self, node: AST) -> Any: ... - def visit_Module(self, node: Module) -> Any: ... - def visit_Interactive(self, node: Interactive) -> Any: ... - def visit_Expression(self, node: Expression) -> Any: ... - def visit_FunctionDef(self, node: FunctionDef) -> Any: ... - def visit_AsyncFunctionDef(self, node: AsyncFunctionDef) -> Any: ... - def visit_ClassDef(self, node: ClassDef) -> Any: ... - def visit_Return(self, node: Return) -> Any: ... - def visit_Delete(self, node: Delete) -> Any: ... - def visit_Assign(self, node: Assign) -> Any: ... - def visit_AugAssign(self, node: AugAssign) -> Any: ... - def visit_AnnAssign(self, node: AnnAssign) -> Any: ... - def visit_For(self, node: For) -> Any: ... - def visit_AsyncFor(self, node: AsyncFor) -> Any: ... - def visit_While(self, node: While) -> Any: ... - def visit_If(self, node: If) -> Any: ... - def visit_With(self, node: With) -> Any: ... - def visit_AsyncWith(self, node: AsyncWith) -> Any: ... - def visit_Raise(self, node: Raise) -> Any: ... - def visit_Try(self, node: Try) -> Any: ... - def visit_Assert(self, node: Assert) -> Any: ... - def visit_Import(self, node: Import) -> Any: ... - def visit_ImportFrom(self, node: ImportFrom) -> Any: ... - def visit_Global(self, node: Global) -> Any: ... - def visit_Nonlocal(self, node: Nonlocal) -> Any: ... - def visit_Expr(self, node: Expr) -> Any: ... - def visit_Pass(self, node: Pass) -> Any: ... - def visit_Break(self, node: Break) -> Any: ... - def visit_Continue(self, node: Continue) -> Any: ... - def visit_Slice(self, node: Slice) -> Any: ... - def visit_BoolOp(self, node: BoolOp) -> Any: ... - def visit_BinOp(self, node: BinOp) -> Any: ... - def visit_UnaryOp(self, node: UnaryOp) -> Any: ... - def visit_Lambda(self, node: Lambda) -> Any: ... - def visit_IfExp(self, node: IfExp) -> Any: ... - def visit_Dict(self, node: Dict) -> Any: ... - def visit_Set(self, node: Set) -> Any: ... - def visit_ListComp(self, node: ListComp) -> Any: ... - def visit_SetComp(self, node: SetComp) -> Any: ... - def visit_DictComp(self, node: DictComp) -> Any: ... - def visit_GeneratorExp(self, node: GeneratorExp) -> Any: ... - def visit_Await(self, node: Await) -> Any: ... - def visit_Yield(self, node: Yield) -> Any: ... - def visit_YieldFrom(self, node: YieldFrom) -> Any: ... - def visit_Compare(self, node: Compare) -> Any: ... - def visit_Call(self, node: Call) -> Any: ... - def visit_FormattedValue(self, node: FormattedValue) -> Any: ... - def visit_JoinedStr(self, node: JoinedStr) -> Any: ... - def visit_Constant(self, node: Constant) -> Any: ... - def visit_NamedExpr(self, node: NamedExpr) -> Any: ... - def visit_TypeIgnore(self, node: TypeIgnore) -> Any: ... - def visit_Attribute(self, node: Attribute) -> Any: ... - def visit_Subscript(self, node: Subscript) -> Any: ... - def visit_Starred(self, node: Starred) -> Any: ... - def visit_Name(self, node: Name) -> Any: ... - def visit_List(self, node: List) -> Any: ... - def visit_Tuple(self, node: Tuple) -> Any: ... - def visit_Del(self, node: Del) -> Any: ... - def visit_Load(self, node: Load) -> Any: ... - def visit_Store(self, node: Store) -> Any: ... - def visit_And(self, node: And) -> Any: ... - def visit_Or(self, node: Or) -> Any: ... - def visit_Add(self, node: Add) -> Any: ... - def visit_BitAnd(self, node: BitAnd) -> Any: ... - def visit_BitOr(self, node: BitOr) -> Any: ... - def visit_BitXor(self, node: BitXor) -> Any: ... - def visit_Div(self, node: Div) -> Any: ... - def visit_FloorDiv(self, node: FloorDiv) -> Any: ... - def visit_LShift(self, node: LShift) -> Any: ... - def visit_Mod(self, node: Mod) -> Any: ... - def visit_Mult(self, node: Mult) -> Any: ... - def visit_MatMult(self, node: MatMult) -> Any: ... - def visit_Pow(self, node: Pow) -> Any: ... - def visit_RShift(self, node: RShift) -> Any: ... - def visit_Sub(self, node: Sub) -> Any: ... - def visit_Invert(self, node: Invert) -> Any: ... - def visit_Not(self, node: Not) -> Any: ... - def visit_UAdd(self, node: UAdd) -> Any: ... - def visit_USub(self, node: USub) -> Any: ... - def visit_Eq(self, node: Eq) -> Any: ... - def visit_Gt(self, node: Gt) -> Any: ... - def visit_GtE(self, node: GtE) -> Any: ... - def visit_In(self, node: In) -> Any: ... - def visit_Is(self, node: Is) -> Any: ... - def visit_IsNot(self, node: IsNot) -> Any: ... - def visit_Lt(self, node: Lt) -> Any: ... - def visit_LtE(self, node: LtE) -> Any: ... - def visit_NotEq(self, node: NotEq) -> Any: ... - def visit_NotIn(self, node: NotIn) -> Any: ... - def visit_comprehension(self, node: comprehension) -> Any: ... - def visit_ExceptHandler(self, node: ExceptHandler) -> Any: ... - def visit_arguments(self, node: arguments) -> Any: ... - def visit_arg(self, node: arg) -> Any: ... - def visit_keyword(self, node: keyword) -> Any: ... - def visit_alias(self, node: alias) -> Any: ... - def visit_withitem(self, node: withitem) -> Any: ... + class _SliceAttributes(TypedDict): ... + +class Slice(_Slice): + if sys.version_info >= (3, 10): + __match_args__ = ("lower", "upper", "step") + lower: expr | None + upper: expr | None + step: expr | None + def __init__( + self, lower: expr | None = None, upper: expr | None = None, step: expr | None = None, **kwargs: Unpack[_SliceAttributes] + ) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, + *, + lower: expr | None = ..., + upper: expr | None = ..., + step: expr | None = ..., + **kwargs: Unpack[_SliceAttributes], + ) -> Self: ... + +class ExtSlice(slice): # deprecated and moved to ast.py if sys.version_info >= (3, 9) + dims: list[slice] + def __init__(self, dims: list[slice], **kwargs: Unpack[_SliceAttributes]) -> None: ... + +class Index(slice): # deprecated and moved to ast.py if sys.version_info >= (3, 9) + value: expr + def __init__(self, value: expr, **kwargs: Unpack[_SliceAttributes]) -> None: ... + +class expr_context(AST): ... +class AugLoad(expr_context): ... # deprecated and moved to ast.py if sys.version_info >= (3, 9) +class AugStore(expr_context): ... # deprecated and moved to ast.py if sys.version_info >= (3, 9) +class Param(expr_context): ... # deprecated and moved to ast.py if sys.version_info >= (3, 9) + +class Suite(mod): # deprecated and moved to ast.py if sys.version_info >= (3, 9) + body: list[stmt] + def __init__(self, body: list[stmt]) -> None: ... + +class Load(expr_context): ... +class Store(expr_context): ... +class Del(expr_context): ... +class boolop(AST): ... +class And(boolop): ... +class Or(boolop): ... +class operator(AST): ... +class Add(operator): ... +class Sub(operator): ... +class Mult(operator): ... +class MatMult(operator): ... +class Div(operator): ... +class Mod(operator): ... +class Pow(operator): ... +class LShift(operator): ... +class RShift(operator): ... +class BitOr(operator): ... +class BitXor(operator): ... +class BitAnd(operator): ... +class FloorDiv(operator): ... +class unaryop(AST): ... +class Invert(unaryop): ... +class Not(unaryop): ... +class UAdd(unaryop): ... +class USub(unaryop): ... +class cmpop(AST): ... +class Eq(cmpop): ... +class NotEq(cmpop): ... +class Lt(cmpop): ... +class LtE(cmpop): ... +class Gt(cmpop): ... +class GtE(cmpop): ... +class Is(cmpop): ... +class IsNot(cmpop): ... +class In(cmpop): ... +class NotIn(cmpop): ... + +class comprehension(AST): + if sys.version_info >= (3, 10): + __match_args__ = ("target", "iter", "ifs", "is_async") + target: expr + iter: expr + ifs: list[expr] + is_async: int + if sys.version_info >= (3, 13): + @overload + def __init__(self, target: expr, iter: expr, ifs: list[expr], is_async: int) -> None: ... + @overload + def __init__(self, target: expr, iter: expr, ifs: list[expr] = ..., *, is_async: int) -> None: ... + else: + def __init__(self, target: expr, iter: expr, ifs: list[expr], is_async: int) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, target: expr = ..., iter: expr = ..., ifs: list[expr] = ..., is_async: int = ...) -> Self: ... + +class excepthandler(AST): + lineno: int + col_offset: int + end_lineno: int | None + end_col_offset: int | None + def __init__(self, **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, *, lineno: int = ..., col_offset: int = ..., end_lineno: int | None = ..., end_col_offset: int | None = ... + ) -> Self: ... + +class ExceptHandler(excepthandler): + if sys.version_info >= (3, 10): + __match_args__ = ("type", "name", "body") + type: expr | None + name: _Identifier | None + body: list[stmt] + if sys.version_info >= (3, 13): + def __init__( + self, type: expr | None = None, name: _Identifier | None = None, body: list[stmt] = ..., **kwargs: Unpack[_Attributes] + ) -> None: ... + else: + @overload + def __init__( + self, type: expr | None, name: _Identifier | None, body: list[stmt], **kwargs: Unpack[_Attributes] + ) -> None: ... + @overload + def __init__( + self, type: expr | None = None, name: _Identifier | None = None, *, body: list[stmt], **kwargs: Unpack[_Attributes] + ) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, + *, + type: expr | None = ..., + name: _Identifier | None = ..., + body: list[stmt] = ..., + **kwargs: Unpack[_Attributes], + ) -> Self: ... + +class arguments(AST): if sys.version_info >= (3, 10): - def visit_Match(self, node: Match) -> Any: ... - def visit_match_case(self, node: match_case) -> Any: ... - def visit_MatchValue(self, node: MatchValue) -> Any: ... - def visit_MatchSequence(self, node: MatchSequence) -> Any: ... - def visit_MatchSingleton(self, node: MatchSingleton) -> Any: ... - def visit_MatchStar(self, node: MatchStar) -> Any: ... - def visit_MatchMapping(self, node: MatchMapping) -> Any: ... - def visit_MatchClass(self, node: MatchClass) -> Any: ... - def visit_MatchAs(self, node: MatchAs) -> Any: ... - def visit_MatchOr(self, node: MatchOr) -> Any: ... + __match_args__ = ("posonlyargs", "args", "vararg", "kwonlyargs", "kw_defaults", "kwarg", "defaults") + posonlyargs: list[arg] + args: list[arg] + vararg: arg | None + kwonlyargs: list[arg] + kw_defaults: list[expr | None] + kwarg: arg | None + defaults: list[expr] + if sys.version_info >= (3, 13): + def __init__( + self, + posonlyargs: list[arg] = ..., + args: list[arg] = ..., + vararg: arg | None = None, + kwonlyargs: list[arg] = ..., + kw_defaults: list[expr | None] = ..., + kwarg: arg | None = None, + defaults: list[expr] = ..., + ) -> None: ... + else: + @overload + def __init__( + self, + posonlyargs: list[arg], + args: list[arg], + vararg: arg | None, + kwonlyargs: list[arg], + kw_defaults: list[expr | None], + kwarg: arg | None, + defaults: list[expr], + ) -> None: ... + @overload + def __init__( + self, + posonlyargs: list[arg], + args: list[arg], + vararg: arg | None, + kwonlyargs: list[arg], + kw_defaults: list[expr | None], + kwarg: arg | None = None, + *, + defaults: list[expr], + ) -> None: ... + @overload + def __init__( + self, + posonlyargs: list[arg], + args: list[arg], + vararg: arg | None = None, + *, + kwonlyargs: list[arg], + kw_defaults: list[expr | None], + kwarg: arg | None = None, + defaults: list[expr], + ) -> None: ... - if sys.version_info >= (3, 11): - def visit_TryStar(self, node: TryStar) -> Any: ... + if sys.version_info >= (3, 14): + def __replace__( + self, + *, + posonlyargs: list[arg] = ..., + args: list[arg] = ..., + vararg: arg | None = ..., + kwonlyargs: list[arg] = ..., + kw_defaults: list[expr | None] = ..., + kwarg: arg | None = ..., + defaults: list[expr] = ..., + ) -> Self: ... - if sys.version_info >= (3, 12): - def visit_TypeVar(self, node: TypeVar) -> Any: ... - def visit_ParamSpec(self, node: ParamSpec) -> Any: ... - def visit_TypeVarTuple(self, node: TypeVarTuple) -> Any: ... - def visit_TypeAlias(self, node: TypeAlias) -> Any: ... +class arg(AST): + lineno: int + col_offset: int + end_lineno: int | None + end_col_offset: int | None + if sys.version_info >= (3, 10): + __match_args__ = ("arg", "annotation", "type_comment") + arg: _Identifier + annotation: expr | None + type_comment: str | None + def __init__( + self, arg: _Identifier, annotation: expr | None = None, type_comment: str | None = None, **kwargs: Unpack[_Attributes] + ) -> None: ... - # visit methods for deprecated nodes - def visit_ExtSlice(self, node: ExtSlice) -> Any: ... - def visit_Index(self, node: Index) -> Any: ... - def visit_Suite(self, node: Suite) -> Any: ... - def visit_AugLoad(self, node: AugLoad) -> Any: ... - def visit_AugStore(self, node: AugStore) -> Any: ... - def visit_Param(self, node: Param) -> Any: ... - def visit_Num(self, node: Num) -> Any: ... - def visit_Str(self, node: Str) -> Any: ... - def visit_Bytes(self, node: Bytes) -> Any: ... - def visit_NameConstant(self, node: NameConstant) -> Any: ... - def visit_Ellipsis(self, node: Ellipsis) -> Any: ... + if sys.version_info >= (3, 14): + def __replace__( + self, + *, + arg: _Identifier = ..., + annotation: expr | None = ..., + type_comment: str | None = ..., + **kwargs: Unpack[_Attributes], + ) -> Self: ... -class NodeTransformer(NodeVisitor): - def generic_visit(self, node: AST) -> AST: ... - # TODO: Override the visit_* methods with better return types. - # The usual return type is AST | None, but Iterable[AST] - # is also allowed in some cases -- this needs to be mapped. +class keyword(AST): + lineno: int + col_offset: int + end_lineno: int | None + end_col_offset: int | None + if sys.version_info >= (3, 10): + __match_args__ = ("arg", "value") + arg: _Identifier | None + value: expr + @overload + def __init__(self, arg: _Identifier | None, value: expr, **kwargs: Unpack[_Attributes]) -> None: ... + @overload + def __init__(self, arg: _Identifier | None = None, *, value: expr, **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, arg: _Identifier | None = ..., value: expr = ..., **kwargs: Unpack[_Attributes]) -> Self: ... + +class alias(AST): + lineno: int + col_offset: int + end_lineno: int | None + end_col_offset: int | None + if sys.version_info >= (3, 10): + __match_args__ = ("name", "asname") + name: str + asname: _Identifier | None + def __init__(self, name: str, asname: _Identifier | None = None, **kwargs: Unpack[_Attributes]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, name: str = ..., asname: _Identifier | None = ..., **kwargs: Unpack[_Attributes]) -> Self: ... + +class withitem(AST): + if sys.version_info >= (3, 10): + __match_args__ = ("context_expr", "optional_vars") + context_expr: expr + optional_vars: expr | None + def __init__(self, context_expr: expr, optional_vars: expr | None = None) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, context_expr: expr = ..., optional_vars: expr | None = ...) -> Self: ... + +if sys.version_info >= (3, 10): + class match_case(AST): + __match_args__ = ("pattern", "guard", "body") + pattern: _Pattern + guard: expr | None + body: list[stmt] + if sys.version_info >= (3, 13): + def __init__(self, pattern: _Pattern, guard: expr | None = None, body: list[stmt] = ...) -> None: ... + else: + @overload + def __init__(self, pattern: _Pattern, guard: expr | None, body: list[stmt]) -> None: ... + @overload + def __init__(self, pattern: _Pattern, guard: expr | None = None, *, body: list[stmt]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, pattern: _Pattern = ..., guard: expr | None = ..., body: list[stmt] = ...) -> Self: ... + + class pattern(AST): + lineno: int + col_offset: int + end_lineno: int + end_col_offset: int + def __init__(self, **kwargs: Unpack[_Attributes[int]]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, *, lineno: int = ..., col_offset: int = ..., end_lineno: int = ..., end_col_offset: int = ... + ) -> Self: ... + + # Without the alias, Pyright complains variables named pattern are recursively defined + _Pattern: typing_extensions.TypeAlias = pattern + + class MatchValue(pattern): + __match_args__ = ("value",) + value: expr + def __init__(self, value: expr, **kwargs: Unpack[_Attributes[int]]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, value: expr = ..., **kwargs: Unpack[_Attributes[int]]) -> Self: ... + + class MatchSingleton(pattern): + __match_args__ = ("value",) + value: Literal[True, False] | None + def __init__(self, value: Literal[True, False] | None, **kwargs: Unpack[_Attributes[int]]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, value: Literal[True, False] | None = ..., **kwargs: Unpack[_Attributes[int]]) -> Self: ... + + class MatchSequence(pattern): + __match_args__ = ("patterns",) + patterns: list[pattern] + if sys.version_info >= (3, 13): + def __init__(self, patterns: list[pattern] = ..., **kwargs: Unpack[_Attributes[int]]) -> None: ... + else: + def __init__(self, patterns: list[pattern], **kwargs: Unpack[_Attributes[int]]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, patterns: list[pattern] = ..., **kwargs: Unpack[_Attributes[int]]) -> Self: ... + + class MatchMapping(pattern): + __match_args__ = ("keys", "patterns", "rest") + keys: list[expr] + patterns: list[pattern] + rest: _Identifier | None + if sys.version_info >= (3, 13): + def __init__( + self, + keys: list[expr] = ..., + patterns: list[pattern] = ..., + rest: _Identifier | None = None, + **kwargs: Unpack[_Attributes[int]], + ) -> None: ... + else: + def __init__( + self, + keys: list[expr], + patterns: list[pattern], + rest: _Identifier | None = None, + **kwargs: Unpack[_Attributes[int]], + ) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, + *, + keys: list[expr] = ..., + patterns: list[pattern] = ..., + rest: _Identifier | None = ..., + **kwargs: Unpack[_Attributes[int]], + ) -> Self: ... + + class MatchClass(pattern): + __match_args__ = ("cls", "patterns", "kwd_attrs", "kwd_patterns") + cls: expr + patterns: list[pattern] + kwd_attrs: list[_Identifier] + kwd_patterns: list[pattern] + if sys.version_info >= (3, 13): + def __init__( + self, + cls: expr, + patterns: list[pattern] = ..., + kwd_attrs: list[_Identifier] = ..., + kwd_patterns: list[pattern] = ..., + **kwargs: Unpack[_Attributes[int]], + ) -> None: ... + else: + def __init__( + self, + cls: expr, + patterns: list[pattern], + kwd_attrs: list[_Identifier], + kwd_patterns: list[pattern], + **kwargs: Unpack[_Attributes[int]], + ) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, + *, + cls: expr = ..., + patterns: list[pattern] = ..., + kwd_attrs: list[_Identifier] = ..., + kwd_patterns: list[pattern] = ..., + **kwargs: Unpack[_Attributes[int]], + ) -> Self: ... + + class MatchStar(pattern): + __match_args__ = ("name",) + name: _Identifier | None + def __init__(self, name: _Identifier | None, **kwargs: Unpack[_Attributes[int]]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, name: _Identifier | None = ..., **kwargs: Unpack[_Attributes[int]]) -> Self: ... + + class MatchAs(pattern): + __match_args__ = ("pattern", "name") + pattern: _Pattern | None + name: _Identifier | None + def __init__( + self, pattern: _Pattern | None = None, name: _Identifier | None = None, **kwargs: Unpack[_Attributes[int]] + ) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, *, pattern: _Pattern | None = ..., name: _Identifier | None = ..., **kwargs: Unpack[_Attributes[int]] + ) -> Self: ... + + class MatchOr(pattern): + __match_args__ = ("patterns",) + patterns: list[pattern] + if sys.version_info >= (3, 13): + def __init__(self, patterns: list[pattern] = ..., **kwargs: Unpack[_Attributes[int]]) -> None: ... + else: + def __init__(self, patterns: list[pattern], **kwargs: Unpack[_Attributes[int]]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, patterns: list[pattern] = ..., **kwargs: Unpack[_Attributes[int]]) -> Self: ... + +class type_ignore(AST): ... + +class TypeIgnore(type_ignore): + if sys.version_info >= (3, 10): + __match_args__ = ("lineno", "tag") + lineno: int + tag: str + def __init__(self, lineno: int, tag: str) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, *, lineno: int = ..., tag: str = ...) -> Self: ... + +if sys.version_info >= (3, 12): + class type_param(AST): + lineno: int + col_offset: int + end_lineno: int + end_col_offset: int + def __init__(self, **kwargs: Unpack[_Attributes[int]]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__(self, **kwargs: Unpack[_Attributes[int]]) -> Self: ... + + class TypeVar(type_param): + if sys.version_info >= (3, 13): + __match_args__ = ("name", "bound", "default_value") + else: + __match_args__ = ("name", "bound") + name: _Identifier + bound: expr | None + if sys.version_info >= (3, 13): + default_value: expr | None + def __init__( + self, + name: _Identifier, + bound: expr | None = None, + default_value: expr | None = None, + **kwargs: Unpack[_Attributes[int]], + ) -> None: ... + else: + def __init__(self, name: _Identifier, bound: expr | None = None, **kwargs: Unpack[_Attributes[int]]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, + *, + name: _Identifier = ..., + bound: expr | None = ..., + default_value: expr | None = ..., + **kwargs: Unpack[_Attributes[int]], + ) -> Self: ... + + class ParamSpec(type_param): + if sys.version_info >= (3, 13): + __match_args__ = ("name", "default_value") + else: + __match_args__ = ("name",) + name: _Identifier + if sys.version_info >= (3, 13): + default_value: expr | None + def __init__( + self, name: _Identifier, default_value: expr | None = None, **kwargs: Unpack[_Attributes[int]] + ) -> None: ... + else: + def __init__(self, name: _Identifier, **kwargs: Unpack[_Attributes[int]]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, *, name: _Identifier = ..., default_value: expr | None = ..., **kwargs: Unpack[_Attributes[int]] + ) -> Self: ... + + class TypeVarTuple(type_param): + if sys.version_info >= (3, 13): + __match_args__ = ("name", "default_value") + else: + __match_args__ = ("name",) + name: _Identifier + if sys.version_info >= (3, 13): + default_value: expr | None + def __init__( + self, name: _Identifier, default_value: expr | None = None, **kwargs: Unpack[_Attributes[int]] + ) -> None: ... + else: + def __init__(self, name: _Identifier, **kwargs: Unpack[_Attributes[int]]) -> None: ... + + if sys.version_info >= (3, 14): + def __replace__( + self, *, name: _Identifier = ..., default_value: expr | None = ..., **kwargs: Unpack[_Attributes[int]] + ) -> Self: ... + +class _ABC(type): + if sys.version_info >= (3, 9): + def __init__(cls, *args: Unused) -> None: ... + +if sys.version_info < (3, 14): + @deprecated("Replaced by ast.Constant; removed in Python 3.14") + class Num(Constant, metaclass=_ABC): + value: int | float | complex + + @deprecated("Replaced by ast.Constant; removed in Python 3.14") + class Str(Constant, metaclass=_ABC): + value: str + # Aliases for value, for backwards compatibility + s: str + + @deprecated("Replaced by ast.Constant; removed in Python 3.14") + class Bytes(Constant, metaclass=_ABC): + value: bytes + # Aliases for value, for backwards compatibility + s: bytes + + @deprecated("Replaced by ast.Constant; removed in Python 3.14") + class NameConstant(Constant, metaclass=_ABC): ... + + @deprecated("Replaced by ast.Constant; removed in Python 3.14") + class Ellipsis(Constant, metaclass=_ABC): ... + +# everything below here is defined in ast.py _T = _TypeVar("_T", bound=AST) @@ -332,10 +1865,7 @@ else: feature_version: None | int | tuple[int, int] = None, ) -> AST: ... -if sys.version_info >= (3, 9): - def unparse(ast_obj: AST) -> str: ... - -def copy_location(new_node: _T, old_node: AST) -> _T: ... +def literal_eval(node_or_string: str | AST) -> Any: ... if sys.version_info >= (3, 13): def dump( @@ -355,17 +1885,165 @@ elif sys.version_info >= (3, 9): else: def dump(node: AST, annotate_fields: bool = True, include_attributes: bool = False) -> str: ... +def copy_location(new_node: _T, old_node: AST) -> _T: ... def fix_missing_locations(node: _T) -> _T: ... -def get_docstring(node: AsyncFunctionDef | FunctionDef | ClassDef | Module, clean: bool = True) -> str | None: ... def increment_lineno(node: _T, n: int = 1) -> _T: ... -def iter_child_nodes(node: AST) -> Iterator[AST]: ... def iter_fields(node: AST) -> Iterator[tuple[str, Any]]: ... -def literal_eval(node_or_string: str | AST) -> Any: ... +def iter_child_nodes(node: AST) -> Iterator[AST]: ... +def get_docstring(node: AsyncFunctionDef | FunctionDef | ClassDef | Module, clean: bool = True) -> str | None: ... def get_source_segment(source: str, node: AST, *, padded: bool = False) -> str | None: ... def walk(node: AST) -> Iterator[AST]: ... -if sys.version_info >= (3, 9): - def main() -> None: ... - if sys.version_info >= (3, 14): def compare(left: AST, right: AST, /, *, compare_attributes: bool = False) -> bool: ... + +class NodeVisitor: + def visit(self, node: AST) -> Any: ... + def generic_visit(self, node: AST) -> Any: ... + def visit_Module(self, node: Module) -> Any: ... + def visit_Interactive(self, node: Interactive) -> Any: ... + def visit_Expression(self, node: Expression) -> Any: ... + def visit_FunctionDef(self, node: FunctionDef) -> Any: ... + def visit_AsyncFunctionDef(self, node: AsyncFunctionDef) -> Any: ... + def visit_ClassDef(self, node: ClassDef) -> Any: ... + def visit_Return(self, node: Return) -> Any: ... + def visit_Delete(self, node: Delete) -> Any: ... + def visit_Assign(self, node: Assign) -> Any: ... + def visit_AugAssign(self, node: AugAssign) -> Any: ... + def visit_AnnAssign(self, node: AnnAssign) -> Any: ... + def visit_For(self, node: For) -> Any: ... + def visit_AsyncFor(self, node: AsyncFor) -> Any: ... + def visit_While(self, node: While) -> Any: ... + def visit_If(self, node: If) -> Any: ... + def visit_With(self, node: With) -> Any: ... + def visit_AsyncWith(self, node: AsyncWith) -> Any: ... + def visit_Raise(self, node: Raise) -> Any: ... + def visit_Try(self, node: Try) -> Any: ... + def visit_Assert(self, node: Assert) -> Any: ... + def visit_Import(self, node: Import) -> Any: ... + def visit_ImportFrom(self, node: ImportFrom) -> Any: ... + def visit_Global(self, node: Global) -> Any: ... + def visit_Nonlocal(self, node: Nonlocal) -> Any: ... + def visit_Expr(self, node: Expr) -> Any: ... + def visit_Pass(self, node: Pass) -> Any: ... + def visit_Break(self, node: Break) -> Any: ... + def visit_Continue(self, node: Continue) -> Any: ... + def visit_Slice(self, node: Slice) -> Any: ... + def visit_BoolOp(self, node: BoolOp) -> Any: ... + def visit_BinOp(self, node: BinOp) -> Any: ... + def visit_UnaryOp(self, node: UnaryOp) -> Any: ... + def visit_Lambda(self, node: Lambda) -> Any: ... + def visit_IfExp(self, node: IfExp) -> Any: ... + def visit_Dict(self, node: Dict) -> Any: ... + def visit_Set(self, node: Set) -> Any: ... + def visit_ListComp(self, node: ListComp) -> Any: ... + def visit_SetComp(self, node: SetComp) -> Any: ... + def visit_DictComp(self, node: DictComp) -> Any: ... + def visit_GeneratorExp(self, node: GeneratorExp) -> Any: ... + def visit_Await(self, node: Await) -> Any: ... + def visit_Yield(self, node: Yield) -> Any: ... + def visit_YieldFrom(self, node: YieldFrom) -> Any: ... + def visit_Compare(self, node: Compare) -> Any: ... + def visit_Call(self, node: Call) -> Any: ... + def visit_FormattedValue(self, node: FormattedValue) -> Any: ... + def visit_JoinedStr(self, node: JoinedStr) -> Any: ... + def visit_Constant(self, node: Constant) -> Any: ... + def visit_NamedExpr(self, node: NamedExpr) -> Any: ... + def visit_TypeIgnore(self, node: TypeIgnore) -> Any: ... + def visit_Attribute(self, node: Attribute) -> Any: ... + def visit_Subscript(self, node: Subscript) -> Any: ... + def visit_Starred(self, node: Starred) -> Any: ... + def visit_Name(self, node: Name) -> Any: ... + def visit_List(self, node: List) -> Any: ... + def visit_Tuple(self, node: Tuple) -> Any: ... + def visit_Del(self, node: Del) -> Any: ... + def visit_Load(self, node: Load) -> Any: ... + def visit_Store(self, node: Store) -> Any: ... + def visit_And(self, node: And) -> Any: ... + def visit_Or(self, node: Or) -> Any: ... + def visit_Add(self, node: Add) -> Any: ... + def visit_BitAnd(self, node: BitAnd) -> Any: ... + def visit_BitOr(self, node: BitOr) -> Any: ... + def visit_BitXor(self, node: BitXor) -> Any: ... + def visit_Div(self, node: Div) -> Any: ... + def visit_FloorDiv(self, node: FloorDiv) -> Any: ... + def visit_LShift(self, node: LShift) -> Any: ... + def visit_Mod(self, node: Mod) -> Any: ... + def visit_Mult(self, node: Mult) -> Any: ... + def visit_MatMult(self, node: MatMult) -> Any: ... + def visit_Pow(self, node: Pow) -> Any: ... + def visit_RShift(self, node: RShift) -> Any: ... + def visit_Sub(self, node: Sub) -> Any: ... + def visit_Invert(self, node: Invert) -> Any: ... + def visit_Not(self, node: Not) -> Any: ... + def visit_UAdd(self, node: UAdd) -> Any: ... + def visit_USub(self, node: USub) -> Any: ... + def visit_Eq(self, node: Eq) -> Any: ... + def visit_Gt(self, node: Gt) -> Any: ... + def visit_GtE(self, node: GtE) -> Any: ... + def visit_In(self, node: In) -> Any: ... + def visit_Is(self, node: Is) -> Any: ... + def visit_IsNot(self, node: IsNot) -> Any: ... + def visit_Lt(self, node: Lt) -> Any: ... + def visit_LtE(self, node: LtE) -> Any: ... + def visit_NotEq(self, node: NotEq) -> Any: ... + def visit_NotIn(self, node: NotIn) -> Any: ... + def visit_comprehension(self, node: comprehension) -> Any: ... + def visit_ExceptHandler(self, node: ExceptHandler) -> Any: ... + def visit_arguments(self, node: arguments) -> Any: ... + def visit_arg(self, node: arg) -> Any: ... + def visit_keyword(self, node: keyword) -> Any: ... + def visit_alias(self, node: alias) -> Any: ... + def visit_withitem(self, node: withitem) -> Any: ... + if sys.version_info >= (3, 10): + def visit_Match(self, node: Match) -> Any: ... + def visit_match_case(self, node: match_case) -> Any: ... + def visit_MatchValue(self, node: MatchValue) -> Any: ... + def visit_MatchSequence(self, node: MatchSequence) -> Any: ... + def visit_MatchSingleton(self, node: MatchSingleton) -> Any: ... + def visit_MatchStar(self, node: MatchStar) -> Any: ... + def visit_MatchMapping(self, node: MatchMapping) -> Any: ... + def visit_MatchClass(self, node: MatchClass) -> Any: ... + def visit_MatchAs(self, node: MatchAs) -> Any: ... + def visit_MatchOr(self, node: MatchOr) -> Any: ... + + if sys.version_info >= (3, 11): + def visit_TryStar(self, node: TryStar) -> Any: ... + + if sys.version_info >= (3, 12): + def visit_TypeVar(self, node: TypeVar) -> Any: ... + def visit_ParamSpec(self, node: ParamSpec) -> Any: ... + def visit_TypeVarTuple(self, node: TypeVarTuple) -> Any: ... + def visit_TypeAlias(self, node: TypeAlias) -> Any: ... + + # visit methods for deprecated nodes + def visit_ExtSlice(self, node: ExtSlice) -> Any: ... + def visit_Index(self, node: Index) -> Any: ... + def visit_Suite(self, node: Suite) -> Any: ... + def visit_AugLoad(self, node: AugLoad) -> Any: ... + def visit_AugStore(self, node: AugStore) -> Any: ... + def visit_Param(self, node: Param) -> Any: ... + + if sys.version_info < (3, 14): + @deprecated("Replaced by visit_Constant; removed in Python 3.14") + def visit_Num(self, node: Num) -> Any: ... # type: ignore[deprecated] + @deprecated("Replaced by visit_Constant; removed in Python 3.14") + def visit_Str(self, node: Str) -> Any: ... # type: ignore[deprecated] + @deprecated("Replaced by visit_Constant; removed in Python 3.14") + def visit_Bytes(self, node: Bytes) -> Any: ... # type: ignore[deprecated] + @deprecated("Replaced by visit_Constant; removed in Python 3.14") + def visit_NameConstant(self, node: NameConstant) -> Any: ... # type: ignore[deprecated] + @deprecated("Replaced by visit_Constant; removed in Python 3.14") + def visit_Ellipsis(self, node: Ellipsis) -> Any: ... # type: ignore[deprecated] + +class NodeTransformer(NodeVisitor): + def generic_visit(self, node: AST) -> AST: ... + # TODO: Override the visit_* methods with better return types. + # The usual return type is AST | None, but Iterable[AST] + # is also allowed in some cases -- this needs to be mapped. + +if sys.version_info >= (3, 9): + def unparse(ast_obj: AST) -> str: ... + +if sys.version_info >= (3, 9): + def main() -> None: ... diff --git a/mypy/typeshed/stdlib/asyncio/events.pyi b/mypy/typeshed/stdlib/asyncio/events.pyi index eed688fc792a..ead64070671f 100644 --- a/mypy/typeshed/stdlib/asyncio/events.pyi +++ b/mypy/typeshed/stdlib/asyncio/events.pyi @@ -1,5 +1,11 @@ import ssl import sys +from _asyncio import ( + _get_running_loop as _get_running_loop, + _set_running_loop as _set_running_loop, + get_event_loop as get_event_loop, + get_running_loop as get_running_loop, +) from _typeshed import FileDescriptorLike, ReadableBuffer, StrPath, Unused, WriteableBuffer from abc import ABCMeta, abstractmethod from collections.abc import Callable, Sequence @@ -632,7 +638,6 @@ class BaseDefaultEventLoopPolicy(AbstractEventLoopPolicy, metaclass=ABCMeta): def get_event_loop_policy() -> AbstractEventLoopPolicy: ... def set_event_loop_policy(policy: AbstractEventLoopPolicy | None) -> None: ... -def get_event_loop() -> AbstractEventLoop: ... def set_event_loop(loop: AbstractEventLoop | None) -> None: ... def new_event_loop() -> AbstractEventLoop: ... @@ -646,7 +651,3 @@ if sys.version_info < (3, 14): else: def get_child_watcher() -> AbstractChildWatcher: ... def set_child_watcher(watcher: AbstractChildWatcher) -> None: ... - -def _set_running_loop(loop: AbstractEventLoop | None, /) -> None: ... -def _get_running_loop() -> AbstractEventLoop: ... -def get_running_loop() -> AbstractEventLoop: ... diff --git a/mypy/typeshed/stdlib/asyncio/futures.pyi b/mypy/typeshed/stdlib/asyncio/futures.pyi index e19fd53f3311..28e6ca8c86a3 100644 --- a/mypy/typeshed/stdlib/asyncio/futures.pyi +++ b/mypy/typeshed/stdlib/asyncio/futures.pyi @@ -1,15 +1,10 @@ -import sys -from collections.abc import Awaitable, Callable, Generator, Iterable +from _asyncio import Future as Future from concurrent.futures._base import Future as _ConcurrentFuture -from contextvars import Context -from typing import Any, Literal, TypeVar -from typing_extensions import Self, TypeIs +from typing import Any, TypeVar +from typing_extensions import TypeIs from .events import AbstractEventLoop -if sys.version_info >= (3, 9): - from types import GenericAlias - __all__ = ("Future", "wrap_future", "isfuture") _T = TypeVar("_T") @@ -18,40 +13,4 @@ _T = TypeVar("_T") # but it leads to circular import error in pytype tool. # That's why the import order is reversed. def isfuture(obj: object) -> TypeIs[Future[Any]]: ... - -class Future(Awaitable[_T], Iterable[_T]): - _state: str - @property - def _exception(self) -> BaseException | None: ... - _blocking: bool - @property - def _log_traceback(self) -> bool: ... - @_log_traceback.setter - def _log_traceback(self, val: Literal[False]) -> None: ... - _asyncio_future_blocking: bool # is a part of duck-typing contract for `Future` - def __init__(self, *, loop: AbstractEventLoop | None = ...) -> None: ... - def __del__(self) -> None: ... - def get_loop(self) -> AbstractEventLoop: ... - @property - def _callbacks(self) -> list[tuple[Callable[[Self], Any], Context]]: ... - def add_done_callback(self, fn: Callable[[Self], object], /, *, context: Context | None = None) -> None: ... - if sys.version_info >= (3, 9): - def cancel(self, msg: Any | None = None) -> bool: ... - else: - def cancel(self) -> bool: ... - - def cancelled(self) -> bool: ... - def done(self) -> bool: ... - def result(self) -> _T: ... - def exception(self) -> BaseException | None: ... - def remove_done_callback(self, fn: Callable[[Self], object], /) -> int: ... - def set_result(self, result: _T, /) -> None: ... - def set_exception(self, exception: type | BaseException, /) -> None: ... - def __iter__(self) -> Generator[Any, None, _T]: ... - def __await__(self) -> Generator[Any, None, _T]: ... - @property - def _loop(self) -> AbstractEventLoop: ... - if sys.version_info >= (3, 9): - def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... - def wrap_future(future: _ConcurrentFuture[_T] | Future[_T], *, loop: AbstractEventLoop | None = None) -> Future[_T]: ... diff --git a/mypy/typeshed/stdlib/asyncio/streams.pyi b/mypy/typeshed/stdlib/asyncio/streams.pyi index 0be5249e2169..ed95583c1847 100644 --- a/mypy/typeshed/stdlib/asyncio/streams.pyi +++ b/mypy/typeshed/stdlib/asyncio/streams.pyi @@ -1,7 +1,7 @@ import ssl import sys from _typeshed import ReadableBuffer, StrPath -from collections.abc import AsyncIterator, Awaitable, Callable, Iterable, Sequence, Sized +from collections.abc import Awaitable, Callable, Iterable, Sequence, Sized from types import ModuleType from typing import Any, Protocol, SupportsIndex from typing_extensions import Self, TypeAlias @@ -137,7 +137,7 @@ class StreamWriter: elif sys.version_info >= (3, 11): def __del__(self) -> None: ... -class StreamReader(AsyncIterator[bytes]): +class StreamReader: def __init__(self, limit: int = 65536, loop: events.AbstractEventLoop | None = None) -> None: ... def exception(self) -> Exception: ... def set_exception(self, exc: Exception) -> None: ... diff --git a/mypy/typeshed/stdlib/asyncio/tasks.pyi b/mypy/typeshed/stdlib/asyncio/tasks.pyi index bb423e857399..d1ff7d425ba4 100644 --- a/mypy/typeshed/stdlib/asyncio/tasks.pyi +++ b/mypy/typeshed/stdlib/asyncio/tasks.pyi @@ -1,16 +1,20 @@ import concurrent.futures import sys -from collections.abc import Awaitable, Coroutine, Generator, Iterable, Iterator -from types import FrameType -from typing import Any, Literal, Protocol, TextIO, TypeVar, overload +from _asyncio import ( + Task as Task, + _enter_task as _enter_task, + _leave_task as _leave_task, + _register_task as _register_task, + _unregister_task as _unregister_task, +) +from collections.abc import AsyncIterator, Awaitable, Coroutine, Generator, Iterable, Iterator +from typing import Any, Literal, Protocol, TypeVar, overload from typing_extensions import TypeAlias from . import _CoroutineLike from .events import AbstractEventLoop from .futures import Future -if sys.version_info >= (3, 9): - from types import GenericAlias if sys.version_info >= (3, 11): from contextvars import Context @@ -80,7 +84,12 @@ FIRST_COMPLETED = concurrent.futures.FIRST_COMPLETED FIRST_EXCEPTION = concurrent.futures.FIRST_EXCEPTION ALL_COMPLETED = concurrent.futures.ALL_COMPLETED -if sys.version_info >= (3, 10): +if sys.version_info >= (3, 13): + class _SyncAndAsyncIterator(Iterator[_T_co], AsyncIterator[_T_co], Protocol[_T_co]): ... + + def as_completed(fs: Iterable[_FutureLike[_T]], *, timeout: float | None = None) -> _SyncAndAsyncIterator[Future[_T]]: ... + +elif sys.version_info >= (3, 10): def as_completed(fs: Iterable[_FutureLike[_T]], *, timeout: float | None = None) -> Iterator[Future[_T]]: ... else: @@ -400,58 +409,6 @@ elif sys.version_info >= (3, 9): else: _TaskCompatibleCoro: TypeAlias = Generator[_TaskYieldType, None, _T_co] | Awaitable[_T_co] -# mypy and pyright complain that a subclass of an invariant class shouldn't be covariant. -# While this is true in general, here it's sort-of okay to have a covariant subclass, -# since the only reason why `asyncio.Future` is invariant is the `set_result()` method, -# and `asyncio.Task.set_result()` always raises. -class Task(Future[_T_co]): # type: ignore[type-var] # pyright: ignore[reportInvalidTypeArguments] - if sys.version_info >= (3, 12): - def __init__( - self, - coro: _TaskCompatibleCoro[_T_co], - *, - loop: AbstractEventLoop = ..., - name: str | None = ..., - context: Context | None = None, - eager_start: bool = False, - ) -> None: ... - elif sys.version_info >= (3, 11): - def __init__( - self, - coro: _TaskCompatibleCoro[_T_co], - *, - loop: AbstractEventLoop = ..., - name: str | None = ..., - context: Context | None = None, - ) -> None: ... - else: - def __init__( - self, coro: _TaskCompatibleCoro[_T_co], *, loop: AbstractEventLoop = ..., name: str | None = ... - ) -> None: ... - - if sys.version_info >= (3, 12): - def get_coro(self) -> _TaskCompatibleCoro[_T_co] | None: ... - else: - def get_coro(self) -> _TaskCompatibleCoro[_T_co]: ... - - def get_name(self) -> str: ... - def set_name(self, value: object, /) -> None: ... - if sys.version_info >= (3, 12): - def get_context(self) -> Context: ... - - def get_stack(self, *, limit: int | None = None) -> list[FrameType]: ... - def print_stack(self, *, limit: int | None = None, file: TextIO | None = None) -> None: ... - if sys.version_info >= (3, 11): - def cancelling(self) -> int: ... - def uncancel(self) -> int: ... - if sys.version_info < (3, 9): - @classmethod - def current_task(cls, loop: AbstractEventLoop | None = None) -> Task[Any] | None: ... - @classmethod - def all_tasks(cls, loop: AbstractEventLoop | None = None) -> set[Task[Any]]: ... - if sys.version_info >= (3, 9): - def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... - def all_tasks(loop: AbstractEventLoop | None = None) -> set[Task[Any]]: ... if sys.version_info >= (3, 11): @@ -460,9 +417,10 @@ if sys.version_info >= (3, 11): else: def create_task(coro: _CoroutineLike[_T], *, name: str | None = None) -> Task[_T]: ... -def current_task(loop: AbstractEventLoop | None = None) -> Task[Any] | None: ... -def _enter_task(loop: AbstractEventLoop, task: Task[Any]) -> None: ... -def _leave_task(loop: AbstractEventLoop, task: Task[Any]) -> None: ... +if sys.version_info >= (3, 12): + from _asyncio import current_task as current_task +else: + def current_task(loop: AbstractEventLoop | None = None) -> Task[Any] | None: ... if sys.version_info >= (3, 12): _TaskT_co = TypeVar("_TaskT_co", bound=Task[Any], covariant=True) @@ -499,6 +457,3 @@ if sys.version_info >= (3, 12): name: str | None = None, context: Context | None = None, ) -> Task[_T_co]: ... - -def _register_task(task: Task[Any]) -> None: ... -def _unregister_task(task: Task[Any]) -> None: ... diff --git a/mypy/typeshed/stdlib/builtins.pyi b/mypy/typeshed/stdlib/builtins.pyi index 0999fb1d6c36..1a4ca925168a 100644 --- a/mypy/typeshed/stdlib/builtins.pyi +++ b/mypy/typeshed/stdlib/builtins.pyi @@ -9,6 +9,7 @@ from _typeshed import ( ConvertibleToFloat, ConvertibleToInt, FileDescriptorOrPath, + MaybeNone, OpenBinaryMode, OpenBinaryModeReading, OpenBinaryModeUpdating, @@ -93,6 +94,9 @@ _SupportsAnextT = TypeVar("_SupportsAnextT", bound=SupportsAnext[Any], covariant _AwaitableT = TypeVar("_AwaitableT", bound=Awaitable[Any]) _AwaitableT_co = TypeVar("_AwaitableT_co", bound=Awaitable[Any], covariant=True) _P = ParamSpec("_P") +_StartT = TypeVar("_StartT", covariant=True, default=Any) +_StopT = TypeVar("_StopT", covariant=True, default=Any) +_StepT = TypeVar("_StepT", covariant=True, default=Any) class object: __doc__: str | None @@ -102,7 +106,7 @@ class object: @property def __class__(self) -> type[Self]: ... @__class__.setter - def __class__(self, type: type[object], /) -> None: ... + def __class__(self, type: type[Self], /) -> None: ... def __init__(self) -> None: ... def __new__(cls) -> Self: ... # N.B. `object.__setattr__` and `object.__delattr__` are heavily special-cased by type checkers. @@ -786,7 +790,7 @@ class memoryview(Sequence[_I]): @overload def __setitem__(self, key: slice, value: ReadableBuffer, /) -> None: ... @overload - def __setitem__(self, key: SupportsIndex | tuple[SupportsIndex, ...], value: SupportsIndex, /) -> None: ... + def __setitem__(self, key: SupportsIndex | tuple[SupportsIndex, ...], value: _I, /) -> None: ... if sys.version_info >= (3, 10): def tobytes(self, order: Literal["C", "F", "A"] | None = "C") -> bytes: ... else: @@ -799,6 +803,11 @@ class memoryview(Sequence[_I]): def __buffer__(self, flags: int, /) -> memoryview: ... def __release_buffer__(self, buffer: memoryview, /) -> None: ... + # These are inherited from the Sequence ABC, but don't actually exist on memoryview. + # See https://github.com/python/cpython/issues/125420 + index: ClassVar[None] # type: ignore[assignment] + count: ClassVar[None] # type: ignore[assignment] + @final class bool(int): def __new__(cls, o: object = ..., /) -> Self: ... @@ -833,19 +842,31 @@ class bool(int): def __invert__(self) -> int: ... @final -class slice: +class slice(Generic[_StartT, _StopT, _StepT]): @property - def start(self) -> Any: ... + def start(self) -> _StartT: ... @property - def step(self) -> Any: ... + def step(self) -> _StepT: ... @property - def stop(self) -> Any: ... + def stop(self) -> _StopT: ... + @overload + def __new__(cls, stop: int | None, /) -> slice[int | MaybeNone, int | MaybeNone, int | MaybeNone]: ... + @overload + def __new__( + cls, start: int | None, stop: int | None, step: int | None = None, / + ) -> slice[int | MaybeNone, int | MaybeNone, int | MaybeNone]: ... + @overload + def __new__(cls, stop: _T2, /) -> slice[Any, _T2, Any]: ... @overload - def __new__(cls, stop: Any, /) -> Self: ... + def __new__(cls, start: _T1, stop: _T2, /) -> slice[_T1, _T2, Any]: ... @overload - def __new__(cls, start: Any, stop: Any, step: Any = ..., /) -> Self: ... + def __new__(cls, start: _T1, stop: _T2, step: _T3, /) -> slice[_T1, _T2, _T3]: ... def __eq__(self, value: object, /) -> bool: ... - __hash__: ClassVar[None] # type: ignore[assignment] + if sys.version_info >= (3, 12): + def __hash__(self) -> int: ... + else: + __hash__: ClassVar[None] # type: ignore[assignment] + def indices(self, len: SupportsIndex, /) -> tuple[int, int, int]: ... class tuple(Sequence[_T_co]): @@ -1109,8 +1130,8 @@ class frozenset(AbstractSet[_T_co]): if sys.version_info >= (3, 9): def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... -class enumerate(Iterator[tuple[int, _T]]): - def __new__(cls, iterable: Iterable[_T], start: int = ...) -> Self: ... +class enumerate(Generic[_T]): + def __new__(cls, iterable: Iterable[_T], start: int = 0) -> Self: ... def __iter__(self) -> Self: ... def __next__(self) -> tuple[int, _T]: ... if sys.version_info >= (3, 9): @@ -1165,9 +1186,7 @@ class property: @final class _NotImplementedType(Any): - # A little weird, but typing the __call__ as NotImplemented makes the error message - # for NotImplemented() much better - __call__: NotImplemented # type: ignore[valid-type] # pyright: ignore[reportInvalidTypeForm] + __call__: None NotImplemented: _NotImplementedType @@ -1303,7 +1322,7 @@ else: def exit(code: sys._ExitCode = None) -> NoReturn: ... -class filter(Iterator[_T]): +class filter(Generic[_T]): @overload def __new__(cls, function: None, iterable: Iterable[_T | None], /) -> Self: ... @overload @@ -1364,7 +1383,7 @@ def len(obj: Sized, /) -> int: ... def license() -> None: ... def locals() -> dict[str, Any]: ... -class map(Iterator[_S]): +class map(Generic[_S]): @overload def __new__(cls, func: Callable[[_T1], _S], iter1: Iterable[_T1], /) -> Self: ... @overload @@ -1606,7 +1625,7 @@ def pow(base: _SupportsSomeKindOfPow, exp: float, mod: None = None) -> Any: ... def pow(base: _SupportsSomeKindOfPow, exp: complex, mod: None = None) -> complex: ... def quit(code: sys._ExitCode = None) -> NoReturn: ... -class reversed(Iterator[_T]): +class reversed(Generic[_T]): @overload def __new__(cls, sequence: Reversible[_T], /) -> Iterator[_T]: ... # type: ignore[misc] @overload @@ -1667,7 +1686,7 @@ def vars(object: type, /) -> types.MappingProxyType[str, Any]: ... @overload def vars(object: Any = ..., /) -> dict[str, Any]: ... -class zip(Iterator[_T_co]): +class zip(Generic[_T_co]): if sys.version_info >= (3, 10): @overload def __new__(cls, *, strict: bool = ...) -> zip[Any]: ... @@ -1797,8 +1816,8 @@ class StopIteration(Exception): value: Any class OSError(Exception): - errno: int - strerror: str + errno: int | None + strerror: str | None # filename, filename2 are actually str | bytes | None filename: Any filename2: Any @@ -1846,14 +1865,33 @@ class StopAsyncIteration(Exception): class SyntaxError(Exception): msg: str + filename: str | None lineno: int | None offset: int | None text: str | None - filename: str | None + # Errors are displayed differently if this attribute exists on the exception. + # The value is always None. + print_file_and_line: None if sys.version_info >= (3, 10): end_lineno: int | None end_offset: int | None + @overload + def __init__(self) -> None: ... + @overload + def __init__(self, msg: object, /) -> None: ... + # Second argument is the tuple (filename, lineno, offset, text) + @overload + def __init__(self, msg: str, info: tuple[str | None, int | None, int | None, str | None], /) -> None: ... + if sys.version_info >= (3, 10): + # end_lineno and end_offset must both be provided if one is. + @overload + def __init__( + self, msg: str, info: tuple[str | None, int | None, int | None, str | None, int | None, int | None], / + ) -> None: ... + # If you provide more than two arguments, it still creates the SyntaxError, but + # the arguments from the info tuple are not parsed. This form is omitted. + class SystemError(Exception): ... class TypeError(Exception): ... class ValueError(Exception): ... diff --git a/mypy/typeshed/stdlib/bz2.pyi b/mypy/typeshed/stdlib/bz2.pyi index a7837e1b9ff8..2f869f9697f4 100644 --- a/mypy/typeshed/stdlib/bz2.pyi +++ b/mypy/typeshed/stdlib/bz2.pyi @@ -1,9 +1,10 @@ import _compression import sys +from _bz2 import BZ2Compressor as BZ2Compressor, BZ2Decompressor as BZ2Decompressor from _compression import BaseStream from _typeshed import ReadableBuffer, StrOrBytesPath, WriteableBuffer from collections.abc import Iterable -from typing import IO, Any, Literal, Protocol, SupportsIndex, TextIO, final, overload +from typing import IO, Any, Literal, Protocol, SupportsIndex, TextIO, overload from typing_extensions import Self, TypeAlias __all__ = ["BZ2File", "BZ2Compressor", "BZ2Decompressor", "open", "compress", "decompress"] @@ -125,22 +126,7 @@ class BZ2File(BaseStream, IO[bytes]): def readline(self, size: SupportsIndex = -1) -> bytes: ... # type: ignore[override] def readinto(self, b: WriteableBuffer) -> int: ... def readlines(self, size: SupportsIndex = -1) -> list[bytes]: ... + def peek(self, n: int = 0) -> bytes: ... def seek(self, offset: int, whence: int = 0) -> int: ... def write(self, data: ReadableBuffer) -> int: ... def writelines(self, seq: Iterable[ReadableBuffer]) -> None: ... - -@final -class BZ2Compressor: - def __init__(self, compresslevel: int = ...) -> None: ... - def compress(self, data: ReadableBuffer, /) -> bytes: ... - def flush(self) -> bytes: ... - -@final -class BZ2Decompressor: - def decompress(self, data: ReadableBuffer, max_length: int = -1) -> bytes: ... - @property - def eof(self) -> bool: ... - @property - def needs_input(self) -> bool: ... - @property - def unused_data(self) -> bytes: ... diff --git a/mypy/typeshed/stdlib/code.pyi b/mypy/typeshed/stdlib/code.pyi index 02689238a9a5..54971f3ae93c 100644 --- a/mypy/typeshed/stdlib/code.pyi +++ b/mypy/typeshed/stdlib/code.pyi @@ -12,7 +12,11 @@ class InteractiveInterpreter: def __init__(self, locals: Mapping[str, Any] | None = None) -> None: ... def runsource(self, source: str, filename: str = "", symbol: str = "single") -> bool: ... def runcode(self, code: CodeType) -> None: ... - def showsyntaxerror(self, filename: str | None = None) -> None: ... + if sys.version_info >= (3, 13): + def showsyntaxerror(self, filename: str | None = None, *, source: str = "") -> None: ... + else: + def showsyntaxerror(self, filename: str | None = None) -> None: ... + def showtraceback(self) -> None: ... def write(self, data: str) -> None: ... diff --git a/mypy/typeshed/stdlib/codecs.pyi b/mypy/typeshed/stdlib/codecs.pyi index a41df9752d33..b3c721f1e283 100644 --- a/mypy/typeshed/stdlib/codecs.pyi +++ b/mypy/typeshed/stdlib/codecs.pyi @@ -3,7 +3,7 @@ from _codecs import * from _typeshed import ReadableBuffer from abc import abstractmethod from collections.abc import Callable, Generator, Iterable -from typing import Any, BinaryIO, Final, Literal, Protocol, TextIO +from typing import Any, BinaryIO, ClassVar, Final, Literal, Protocol, TextIO from typing_extensions import Self __all__ = [ @@ -202,6 +202,7 @@ class StreamWriter(Codec): def write(self, object: str) -> None: ... def writelines(self, list: Iterable[str]) -> None: ... def reset(self) -> None: ... + def seek(self, offset: int, whence: int = 0) -> None: ... def __enter__(self) -> Self: ... def __exit__(self, type: type[BaseException] | None, value: BaseException | None, tb: types.TracebackType | None) -> None: ... def __getattr__(self, name: str, getattr: Callable[[Any, str], Any] = ...) -> Any: ... @@ -209,11 +210,14 @@ class StreamWriter(Codec): class StreamReader(Codec): stream: _ReadableStream errors: str + # This is set to str, but some subclasses set to bytes instead. + charbuffertype: ClassVar[type] = ... def __init__(self, stream: _ReadableStream, errors: str = "strict") -> None: ... def read(self, size: int = -1, chars: int = -1, firstline: bool = False) -> str: ... def readline(self, size: int | None = None, keepends: bool = True) -> str: ... def readlines(self, sizehint: int | None = None, keepends: bool = True) -> list[str]: ... def reset(self) -> None: ... + def seek(self, offset: int, whence: int = 0) -> None: ... def __enter__(self) -> Self: ... def __exit__(self, type: type[BaseException] | None, value: BaseException | None, tb: types.TracebackType | None) -> None: ... def __iter__(self) -> Self: ... diff --git a/mypy/typeshed/stdlib/collections/__init__.pyi b/mypy/typeshed/stdlib/collections/__init__.pyi index b2ed53e4427e..2d136318813c 100644 --- a/mypy/typeshed/stdlib/collections/__init__.pyi +++ b/mypy/typeshed/stdlib/collections/__init__.pyi @@ -17,7 +17,6 @@ if sys.version_info >= (3, 10): Mapping, MutableMapping, MutableSequence, - Reversible, Sequence, ValuesView, ) @@ -331,13 +330,13 @@ class Counter(dict[_T, int], Generic[_T]): # The pure-Python implementations of the "views" classes # These are exposed at runtime in `collections/__init__.py` -class _OrderedDictKeysView(KeysView[_KT_co], Reversible[_KT_co]): +class _OrderedDictKeysView(KeysView[_KT_co]): def __reversed__(self) -> Iterator[_KT_co]: ... -class _OrderedDictItemsView(ItemsView[_KT_co, _VT_co], Reversible[tuple[_KT_co, _VT_co]]): +class _OrderedDictItemsView(ItemsView[_KT_co, _VT_co]): def __reversed__(self) -> Iterator[tuple[_KT_co, _VT_co]]: ... -class _OrderedDictValuesView(ValuesView[_VT_co], Reversible[_VT_co]): +class _OrderedDictValuesView(ValuesView[_VT_co]): def __reversed__(self) -> Iterator[_VT_co]: ... # The C implementations of the "views" classes @@ -345,18 +344,18 @@ class _OrderedDictValuesView(ValuesView[_VT_co], Reversible[_VT_co]): # but they are not exposed anywhere) # pyright doesn't have a specific error code for subclassing error! @final -class _odict_keys(dict_keys[_KT_co, _VT_co], Reversible[_KT_co]): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] +class _odict_keys(dict_keys[_KT_co, _VT_co]): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] def __reversed__(self) -> Iterator[_KT_co]: ... @final -class _odict_items(dict_items[_KT_co, _VT_co], Reversible[tuple[_KT_co, _VT_co]]): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] +class _odict_items(dict_items[_KT_co, _VT_co]): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] def __reversed__(self) -> Iterator[tuple[_KT_co, _VT_co]]: ... @final -class _odict_values(dict_values[_KT_co, _VT_co], Reversible[_VT_co], Generic[_KT_co, _VT_co]): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] +class _odict_values(dict_values[_KT_co, _VT_co]): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] def __reversed__(self) -> Iterator[_VT_co]: ... -class OrderedDict(dict[_KT, _VT], Reversible[_KT], Generic[_KT, _VT]): +class OrderedDict(dict[_KT, _VT]): def popitem(self, last: bool = True) -> tuple[_KT, _VT]: ... def move_to_end(self, key: _KT, last: bool = True) -> None: ... def copy(self) -> Self: ... diff --git a/mypy/typeshed/stdlib/concurrent/futures/process.pyi b/mypy/typeshed/stdlib/concurrent/futures/process.pyi index d3706a9c15a6..a1de3d679b23 100644 --- a/mypy/typeshed/stdlib/concurrent/futures/process.pyi +++ b/mypy/typeshed/stdlib/concurrent/futures/process.pyi @@ -19,8 +19,9 @@ _global_shutdown: bool class _ThreadWakeup: _closed: bool - _reader: Connection - _writer: Connection + # Any: Unused send and recv methods + _reader: Connection[Any, Any] + _writer: Connection[Any, Any] def close(self) -> None: ... def wakeup(self) -> None: ... def clear(self) -> None: ... diff --git a/mypy/typeshed/stdlib/configparser.pyi b/mypy/typeshed/stdlib/configparser.pyi index ee5000196e0e..a44dc2e1c035 100644 --- a/mypy/typeshed/stdlib/configparser.pyi +++ b/mypy/typeshed/stdlib/configparser.pyi @@ -1,5 +1,5 @@ import sys -from _typeshed import StrOrBytesPath, SupportsWrite +from _typeshed import MaybeNone, StrOrBytesPath, SupportsWrite from collections.abc import Callable, ItemsView, Iterable, Iterator, Mapping, MutableMapping, Sequence from re import Pattern from typing import Any, ClassVar, Final, Literal, TypeVar, overload @@ -263,11 +263,11 @@ class RawConfigParser(_Parser): ) -> _T: ... # This is incompatible with MutableMapping so we ignore the type @overload # type: ignore[override] - def get(self, section: str, option: str, *, raw: bool = False, vars: _Section | None = None) -> str | Any: ... + def get(self, section: str, option: str, *, raw: bool = False, vars: _Section | None = None) -> str | MaybeNone: ... @overload def get( self, section: str, option: str, *, raw: bool = False, vars: _Section | None = None, fallback: _T - ) -> str | _T | Any: ... + ) -> str | _T | MaybeNone: ... @overload def items(self, *, raw: bool = False, vars: _Section | None = None) -> ItemsView[str, SectionProxy]: ... @overload @@ -277,6 +277,8 @@ class RawConfigParser(_Parser): def remove_option(self, section: str, option: str) -> bool: ... def remove_section(self, section: str) -> bool: ... def optionxform(self, optionstr: str) -> str: ... + @property + def converters(self) -> ConverterMapping: ... class ConfigParser(RawConfigParser): # This is incompatible with MutableMapping so we ignore the type @@ -300,28 +302,34 @@ class SectionProxy(MutableMapping[str, str]): def parser(self) -> RawConfigParser: ... @property def name(self) -> str: ... - def get( # type: ignore[override] + # This is incompatible with MutableMapping so we ignore the type + @overload # type: ignore[override] + def get( + self, option: str, *, raw: bool = False, vars: _Section | None = None, _impl: Any | None = None, **kwargs: Any + ) -> str | None: ... + @overload + def get( self, option: str, - fallback: str | None = None, + fallback: _T, *, raw: bool = False, vars: _Section | None = None, _impl: Any | None = None, **kwargs: Any, - ) -> str | Any: ... # can be None in RawConfigParser's sections + ) -> str | _T: ... # These are partially-applied version of the methods with the same names in # RawConfigParser; the stubs should be kept updated together @overload - def getint(self, option: str, *, raw: bool = ..., vars: _Section | None = ...) -> int: ... + def getint(self, option: str, *, raw: bool = ..., vars: _Section | None = ...) -> int | None: ... @overload def getint(self, option: str, fallback: _T = ..., *, raw: bool = ..., vars: _Section | None = ...) -> int | _T: ... @overload - def getfloat(self, option: str, *, raw: bool = ..., vars: _Section | None = ...) -> float: ... + def getfloat(self, option: str, *, raw: bool = ..., vars: _Section | None = ...) -> float | None: ... @overload def getfloat(self, option: str, fallback: _T = ..., *, raw: bool = ..., vars: _Section | None = ...) -> float | _T: ... @overload - def getboolean(self, option: str, *, raw: bool = ..., vars: _Section | None = ...) -> bool: ... + def getboolean(self, option: str, *, raw: bool = ..., vars: _Section | None = ...) -> bool | None: ... @overload def getboolean(self, option: str, fallback: _T = ..., *, raw: bool = ..., vars: _Section | None = ...) -> bool | _T: ... # SectionProxy can have arbitrary attributes when custom converters are used diff --git a/mypy/typeshed/stdlib/contextlib.pyi b/mypy/typeshed/stdlib/contextlib.pyi index daf218d5a138..dc5d926775f3 100644 --- a/mypy/typeshed/stdlib/contextlib.pyi +++ b/mypy/typeshed/stdlib/contextlib.pyi @@ -1,7 +1,7 @@ import abc import sys from _typeshed import FileDescriptorOrPath, Unused -from abc import abstractmethod +from abc import ABC, abstractmethod from collections.abc import AsyncGenerator, AsyncIterator, Awaitable, Callable, Generator, Iterator from types import TracebackType from typing import IO, Any, Generic, Protocol, TypeVar, overload, runtime_checkable @@ -38,16 +38,22 @@ _P = ParamSpec("_P") _ExitFunc: TypeAlias = Callable[[type[BaseException] | None, BaseException | None, TracebackType | None], bool | None] _CM_EF = TypeVar("_CM_EF", bound=AbstractContextManager[Any, Any] | _ExitFunc) +# mypy and pyright object to this being both ABC and Protocol. +# At runtime it inherits from ABC and is not a Protocol, but it is on the +# allowlist for use as a Protocol. @runtime_checkable -class AbstractContextManager(Protocol[_T_co, _ExitT_co]): +class AbstractContextManager(ABC, Protocol[_T_co, _ExitT_co]): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] def __enter__(self) -> _T_co: ... @abstractmethod def __exit__( self, exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: TracebackType | None, / ) -> _ExitT_co: ... +# mypy and pyright object to this being both ABC and Protocol. +# At runtime it inherits from ABC and is not a Protocol, but it is on the +# allowlist for use as a Protocol. @runtime_checkable -class AbstractAsyncContextManager(Protocol[_T_co, _ExitT_co]): +class AbstractAsyncContextManager(ABC, Protocol[_T_co, _ExitT_co]): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] async def __aenter__(self) -> _T_co: ... @abstractmethod async def __aexit__( @@ -58,9 +64,11 @@ class ContextDecorator: def _recreate_cm(self) -> Self: ... def __call__(self, func: _F) -> _F: ... -class _GeneratorContextManager(AbstractContextManager[_T_co, bool | None], ContextDecorator): +class _GeneratorContextManagerBase: ... + +class _GeneratorContextManager(_GeneratorContextManagerBase, AbstractContextManager[_T_co, bool | None], ContextDecorator): # __init__ and all instance attributes are actually inherited from _GeneratorContextManagerBase - # _GeneratorContextManagerBase is more trouble than it's worth to include in the stub; see #6676 + # adding them there is more trouble than it's worth to include in the stub; see #6676 def __init__(self, func: Callable[..., Iterator[_T_co]], args: tuple[Any, ...], kwds: dict[str, Any]) -> None: ... gen: Generator[_T_co, Any, Any] func: Callable[..., Generator[_T_co, Any, Any]] @@ -84,9 +92,11 @@ if sys.version_info >= (3, 10): def _recreate_cm(self) -> Self: ... def __call__(self, func: _AF) -> _AF: ... - class _AsyncGeneratorContextManager(AbstractAsyncContextManager[_T_co, bool | None], AsyncContextDecorator): + class _AsyncGeneratorContextManager( + _GeneratorContextManagerBase, AbstractAsyncContextManager[_T_co, bool | None], AsyncContextDecorator + ): # __init__ and these attributes are actually defined in the base class _GeneratorContextManagerBase, - # which is more trouble than it's worth to include in the stub (see #6676) + # adding them there is more trouble than it's worth to include in the stub (see #6676) def __init__(self, func: Callable[..., AsyncIterator[_T_co]], args: tuple[Any, ...], kwds: dict[str, Any]) -> None: ... gen: AsyncGenerator[_T_co, Any] func: Callable[..., AsyncGenerator[_T_co, Any]] @@ -97,7 +107,7 @@ if sys.version_info >= (3, 10): ) -> bool | None: ... else: - class _AsyncGeneratorContextManager(AbstractAsyncContextManager[_T_co, bool | None]): + class _AsyncGeneratorContextManager(_GeneratorContextManagerBase, AbstractAsyncContextManager[_T_co, bool | None]): def __init__(self, func: Callable[..., AsyncIterator[_T_co]], args: tuple[Any, ...], kwds: dict[str, Any]) -> None: ... gen: AsyncGenerator[_T_co, Any] func: Callable[..., AsyncGenerator[_T_co, Any]] @@ -143,13 +153,15 @@ class _RedirectStream(AbstractContextManager[_T_io, None]): class redirect_stdout(_RedirectStream[_T_io]): ... class redirect_stderr(_RedirectStream[_T_io]): ... -# In reality this is a subclass of `AbstractContextManager`; -# see #7961 for why we don't do that in the stub -class ExitStack(Generic[_ExitT_co], metaclass=abc.ABCMeta): +class _BaseExitStack(Generic[_ExitT_co]): def enter_context(self, cm: AbstractContextManager[_T, _ExitT_co]) -> _T: ... def push(self, exit: _CM_EF) -> _CM_EF: ... def callback(self, callback: Callable[_P, _T], /, *args: _P.args, **kwds: _P.kwargs) -> Callable[_P, _T]: ... def pop_all(self) -> Self: ... + +# In reality this is a subclass of `AbstractContextManager`; +# see #7961 for why we don't do that in the stub +class ExitStack(_BaseExitStack[_ExitT_co], metaclass=abc.ABCMeta): def close(self) -> None: ... def __enter__(self) -> Self: ... def __exit__( @@ -163,16 +175,12 @@ _ACM_EF = TypeVar("_ACM_EF", bound=AbstractAsyncContextManager[Any, Any] | _Exit # In reality this is a subclass of `AbstractAsyncContextManager`; # see #7961 for why we don't do that in the stub -class AsyncExitStack(Generic[_ExitT_co], metaclass=abc.ABCMeta): - def enter_context(self, cm: AbstractContextManager[_T, _ExitT_co]) -> _T: ... +class AsyncExitStack(_BaseExitStack[_ExitT_co], metaclass=abc.ABCMeta): async def enter_async_context(self, cm: AbstractAsyncContextManager[_T, _ExitT_co]) -> _T: ... - def push(self, exit: _CM_EF) -> _CM_EF: ... def push_async_exit(self, exit: _ACM_EF) -> _ACM_EF: ... - def callback(self, callback: Callable[_P, _T], /, *args: _P.args, **kwds: _P.kwargs) -> Callable[_P, _T]: ... def push_async_callback( self, callback: Callable[_P, Awaitable[_T]], /, *args: _P.args, **kwds: _P.kwargs ) -> Callable[_P, Awaitable[_T]]: ... - def pop_all(self) -> Self: ... async def aclose(self) -> None: ... async def __aenter__(self) -> Self: ... async def __aexit__( diff --git a/mypy/typeshed/stdlib/contextvars.pyi b/mypy/typeshed/stdlib/contextvars.pyi index dd5ea0acbe2c..22dc33006e9d 100644 --- a/mypy/typeshed/stdlib/contextvars.pyi +++ b/mypy/typeshed/stdlib/contextvars.pyi @@ -1,63 +1,3 @@ -import sys -from collections.abc import Callable, Iterator, Mapping -from typing import Any, ClassVar, Generic, TypeVar, final, overload -from typing_extensions import ParamSpec - -if sys.version_info >= (3, 9): - from types import GenericAlias +from _contextvars import Context as Context, ContextVar as ContextVar, Token as Token, copy_context as copy_context __all__ = ("Context", "ContextVar", "Token", "copy_context") - -_T = TypeVar("_T") -_D = TypeVar("_D") -_P = ParamSpec("_P") - -@final -class ContextVar(Generic[_T]): - @overload - def __init__(self, name: str) -> None: ... - @overload - def __init__(self, name: str, *, default: _T) -> None: ... - def __hash__(self) -> int: ... - @property - def name(self) -> str: ... - @overload - def get(self) -> _T: ... - @overload - def get(self, default: _T, /) -> _T: ... - @overload - def get(self, default: _D, /) -> _D | _T: ... - def set(self, value: _T, /) -> Token[_T]: ... - def reset(self, token: Token[_T], /) -> None: ... - if sys.version_info >= (3, 9): - def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... - -@final -class Token(Generic[_T]): - @property - def var(self) -> ContextVar[_T]: ... - @property - def old_value(self) -> Any: ... # returns either _T or MISSING, but that's hard to express - MISSING: ClassVar[object] - if sys.version_info >= (3, 9): - def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... - -def copy_context() -> Context: ... - -# It doesn't make sense to make this generic, because for most Contexts each ContextVar will have -# a different value. -@final -class Context(Mapping[ContextVar[Any], Any]): - def __init__(self) -> None: ... - @overload - def get(self, key: ContextVar[_T], default: None = None, /) -> _T | None: ... - @overload - def get(self, key: ContextVar[_T], default: _T, /) -> _T: ... - @overload - def get(self, key: ContextVar[_T], default: _D, /) -> _T | _D: ... - def run(self, callable: Callable[_P, _T], *args: _P.args, **kwargs: _P.kwargs) -> _T: ... - def copy(self) -> Context: ... - def __getitem__(self, key: ContextVar[_T], /) -> _T: ... - def __iter__(self) -> Iterator[ContextVar[Any]]: ... - def __len__(self) -> int: ... - def __eq__(self, value: object, /) -> bool: ... diff --git a/mypy/typeshed/stdlib/crypt.pyi b/mypy/typeshed/stdlib/crypt.pyi index 294003859286..bd22b5f8daba 100644 --- a/mypy/typeshed/stdlib/crypt.pyi +++ b/mypy/typeshed/stdlib/crypt.pyi @@ -1,8 +1,15 @@ import sys -from typing import Final +from typing import Final, NamedTuple, type_check_only if sys.platform != "win32": - class _Method: ... + @type_check_only + class _MethodBase(NamedTuple): + name: str + ident: str | None + salt_chars: int + total_size: int + + class _Method(_MethodBase): ... METHOD_CRYPT: Final[_Method] METHOD_MD5: Final[_Method] METHOD_SHA256: Final[_Method] diff --git a/mypy/typeshed/stdlib/csv.pyi b/mypy/typeshed/stdlib/csv.pyi index 24f0db332165..4a82de638136 100644 --- a/mypy/typeshed/stdlib/csv.pyi +++ b/mypy/typeshed/stdlib/csv.pyi @@ -1,18 +1,13 @@ import sys - -# actually csv.Dialect is a different class to _csv.Dialect at runtime, but for typing purposes, they're identical from _csv import ( QUOTE_ALL as QUOTE_ALL, QUOTE_MINIMAL as QUOTE_MINIMAL, QUOTE_NONE as QUOTE_NONE, QUOTE_NONNUMERIC as QUOTE_NONNUMERIC, - Dialect as Dialect, Error as Error, __version__ as __version__, _DialectLike, _QuotingType, - _reader, - _writer, field_size_limit as field_size_limit, get_dialect as get_dialect, list_dialects as list_dialects, @@ -24,9 +19,13 @@ from _csv import ( if sys.version_info >= (3, 12): from _csv import QUOTE_NOTNULL as QUOTE_NOTNULL, QUOTE_STRINGS as QUOTE_STRINGS +if sys.version_info >= (3, 10): + from _csv import Reader, Writer +else: + from _csv import _reader as Reader, _writer as Writer from _typeshed import SupportsWrite -from collections.abc import Collection, Iterable, Iterator, Mapping, Sequence +from collections.abc import Collection, Iterable, Mapping, Sequence from typing import Any, Generic, Literal, TypeVar, overload from typing_extensions import Self @@ -61,15 +60,26 @@ if sys.version_info < (3, 13): _T = TypeVar("_T") +class Dialect: + delimiter: str + quotechar: str | None + escapechar: str | None + doublequote: bool + skipinitialspace: bool + lineterminator: str + quoting: _QuotingType + strict: bool + def __init__(self) -> None: ... + class excel(Dialect): ... class excel_tab(excel): ... class unix_dialect(Dialect): ... -class DictReader(Iterator[dict[_T | Any, str | Any]], Generic[_T]): +class DictReader(Generic[_T]): fieldnames: Sequence[_T] | None restkey: _T | None restval: str | Any | None - reader: _reader + reader: Reader dialect: _DialectLike line_num: int @overload @@ -117,7 +127,7 @@ class DictWriter(Generic[_T]): fieldnames: Collection[_T] restval: Any | None extrasaction: Literal["raise", "ignore"] - writer: _writer + writer: Writer def __init__( self, f: SupportsWrite[str], diff --git a/mypy/typeshed/stdlib/ctypes/__init__.pyi b/mypy/typeshed/stdlib/ctypes/__init__.pyi index 40a073d107c7..3e0e7c45bf15 100644 --- a/mypy/typeshed/stdlib/ctypes/__init__.pyi +++ b/mypy/typeshed/stdlib/ctypes/__init__.pyi @@ -10,13 +10,11 @@ from _ctypes import ( _CanCastTo as _CanCastTo, _CArgObject as _CArgObject, _CData as _CData, - _CDataMeta as _CDataMeta, + _CDataType as _CDataType, _CField as _CField, _Pointer as _Pointer, _PointerLike as _PointerLike, _SimpleCData as _SimpleCData, - _StructUnionBase as _StructUnionBase, - _StructUnionMeta as _StructUnionMeta, addressof as addressof, alignment as alignment, byref as byref, @@ -28,7 +26,7 @@ from _ctypes import ( ) from ctypes._endian import BigEndianStructure as BigEndianStructure, LittleEndianStructure as LittleEndianStructure from typing import Any, ClassVar, Generic, TypeVar -from typing_extensions import TypeAlias +from typing_extensions import Self, TypeAlias, deprecated if sys.platform == "win32": from _ctypes import FormatError as FormatError, get_last_error as get_last_error, set_last_error as set_last_error @@ -41,6 +39,7 @@ if sys.version_info >= (3, 9): _T = TypeVar("_T") _DLLT = TypeVar("_DLLT", bound=CDLL) +_CT = TypeVar("_CT", bound=_CData) DEFAULT_MODE: int @@ -48,7 +47,7 @@ class ArgumentError(Exception): ... class CDLL: _func_flags_: ClassVar[int] - _func_restype_: ClassVar[_CData] + _func_restype_: ClassVar[_CDataType] _name: str _handle: int _FuncPtr: type[_FuncPointer] @@ -91,15 +90,21 @@ class _NamedFuncPointer(_FuncPointer): __name__: str def CFUNCTYPE( - restype: type[_CData] | None, *argtypes: type[_CData], use_errno: bool = ..., use_last_error: bool = ... + restype: type[_CData | _CDataType] | None, + *argtypes: type[_CData | _CDataType], + use_errno: bool = ..., + use_last_error: bool = ..., ) -> type[_FuncPointer]: ... if sys.platform == "win32": def WINFUNCTYPE( - restype: type[_CData] | None, *argtypes: type[_CData], use_errno: bool = ..., use_last_error: bool = ... + restype: type[_CData | _CDataType] | None, + *argtypes: type[_CData | _CDataType], + use_errno: bool = ..., + use_last_error: bool = ..., ) -> type[_FuncPointer]: ... -def PYFUNCTYPE(restype: type[_CData] | None, *argtypes: type[_CData]) -> type[_FuncPointer]: ... +def PYFUNCTYPE(restype: type[_CData | _CDataType] | None, *argtypes: type[_CData | _CDataType]) -> type[_FuncPointer]: ... # Any type that can be implicitly converted to c_void_p when passed as a C function argument. # (bytes is not included here, see below.) @@ -112,12 +117,17 @@ _CVoidConstPLike: TypeAlias = _CVoidPLike | bytes _CastT = TypeVar("_CastT", bound=_CanCastTo) -def cast(obj: _CData | _CArgObject | int, typ: type[_CastT]) -> _CastT: ... +def cast(obj: _CData | _CDataType | _CArgObject | int, typ: type[_CastT]) -> _CastT: ... def create_string_buffer(init: int | bytes, size: int | None = None) -> Array[c_char]: ... c_buffer = create_string_buffer def create_unicode_buffer(init: int | str, size: int | None = None) -> Array[c_wchar]: ... +@deprecated("Deprecated in Python 3.13; removal scheduled for Python 3.15") +def SetPointerType( + pointer: type[_Pointer[Any]], cls: Any # noqa: F811 # Redefinition of unused `pointer` from line 22 +) -> None: ... +def ARRAY(typ: _CT, len: int) -> Array[_CT]: ... # Soft Deprecated, no plans to remove if sys.platform == "win32": def DllCanUnloadNow() -> int: ... @@ -126,12 +136,12 @@ if sys.platform == "win32": def memmove(dst: _CVoidPLike, src: _CVoidConstPLike, count: int) -> int: ... def memset(dst: _CVoidPLike, c: int, count: int) -> int: ... -def string_at(address: _CVoidConstPLike, size: int = -1) -> bytes: ... +def string_at(ptr: _CVoidConstPLike, size: int = -1) -> bytes: ... if sys.platform == "win32": def WinError(code: int | None = None, descr: str | None = None) -> OSError: ... -def wstring_at(address: _CVoidConstPLike, size: int = -1) -> str: ... +def wstring_at(ptr: _CVoidConstPLike, size: int = -1) -> str: ... class c_byte(_SimpleCData[int]): ... @@ -140,6 +150,8 @@ class c_char(_SimpleCData[bytes]): class c_char_p(_PointerLike, _SimpleCData[bytes | None]): def __init__(self, value: int | bytes | None = ...) -> None: ... + @classmethod + def from_param(cls, value: Any, /) -> Self | _CArgObject: ... class c_double(_SimpleCData[float]): ... class c_longdouble(_SimpleCData[float]): ... # can be an alias for c_double @@ -155,7 +167,13 @@ class c_uint(_SimpleCData[int]): ... # can be an alias for c_ulong class c_ulong(_SimpleCData[int]): ... class c_ulonglong(_SimpleCData[int]): ... # can be an alias for c_ulong class c_ushort(_SimpleCData[int]): ... -class c_void_p(_PointerLike, _SimpleCData[int | None]): ... + +class c_void_p(_PointerLike, _SimpleCData[int | None]): + @classmethod + def from_param(cls, value: Any, /) -> Self | _CArgObject: ... + +c_voidp = c_void_p # backwards compatibility (to a bug) + class c_wchar(_SimpleCData[str]): ... c_int8 = c_byte @@ -174,6 +192,8 @@ class c_uint64(_SimpleCData[int]): ... class c_wchar_p(_PointerLike, _SimpleCData[str | None]): def __init__(self, value: int | str | None = ...) -> None: ... + @classmethod + def from_param(cls, value: Any, /) -> Self | _CArgObject: ... class c_bool(_SimpleCData[bool]): def __init__(self, value: bool = ...) -> None: ... diff --git a/mypy/typeshed/stdlib/ctypes/macholib/__init__.pyi b/mypy/typeshed/stdlib/ctypes/macholib/__init__.pyi new file mode 100644 index 000000000000..bda5b5a7f4cc --- /dev/null +++ b/mypy/typeshed/stdlib/ctypes/macholib/__init__.pyi @@ -0,0 +1 @@ +__version__: str diff --git a/mypy/typeshed/stdlib/ctypes/macholib/dyld.pyi b/mypy/typeshed/stdlib/ctypes/macholib/dyld.pyi new file mode 100644 index 000000000000..c7e94daa2149 --- /dev/null +++ b/mypy/typeshed/stdlib/ctypes/macholib/dyld.pyi @@ -0,0 +1,8 @@ +from collections.abc import Mapping +from ctypes.macholib.dylib import dylib_info as dylib_info +from ctypes.macholib.framework import framework_info as framework_info + +__all__ = ["dyld_find", "framework_find", "framework_info", "dylib_info"] + +def dyld_find(name: str, executable_path: str | None = None, env: Mapping[str, str] | None = None) -> str: ... +def framework_find(fn: str, executable_path: str | None = None, env: Mapping[str, str] | None = None) -> str: ... diff --git a/mypy/typeshed/stdlib/ctypes/macholib/dylib.pyi b/mypy/typeshed/stdlib/ctypes/macholib/dylib.pyi new file mode 100644 index 000000000000..95945edfd155 --- /dev/null +++ b/mypy/typeshed/stdlib/ctypes/macholib/dylib.pyi @@ -0,0 +1,14 @@ +from typing import TypedDict, type_check_only + +__all__ = ["dylib_info"] + +# Actual result is produced by re.match.groupdict() +@type_check_only +class _DylibInfo(TypedDict): + location: str + name: str + shortname: str + version: str | None + suffix: str | None + +def dylib_info(filename: str) -> _DylibInfo | None: ... diff --git a/mypy/typeshed/stdlib/ctypes/macholib/framework.pyi b/mypy/typeshed/stdlib/ctypes/macholib/framework.pyi new file mode 100644 index 000000000000..e92bf3700e84 --- /dev/null +++ b/mypy/typeshed/stdlib/ctypes/macholib/framework.pyi @@ -0,0 +1,14 @@ +from typing import TypedDict, type_check_only + +__all__ = ["framework_info"] + +# Actual result is produced by re.match.groupdict() +@type_check_only +class _FrameworkInfo(TypedDict): + location: str + name: str + shortname: str + version: str | None + suffix: str | None + +def framework_info(filename: str) -> _FrameworkInfo | None: ... diff --git a/mypy/typeshed/stdlib/ctypes/util.pyi b/mypy/typeshed/stdlib/ctypes/util.pyi index c0274f5e539b..316f7a2b3e2f 100644 --- a/mypy/typeshed/stdlib/ctypes/util.pyi +++ b/mypy/typeshed/stdlib/ctypes/util.pyi @@ -4,3 +4,5 @@ def find_library(name: str) -> str | None: ... if sys.platform == "win32": def find_msvcrt() -> str | None: ... + +def test() -> None: ... diff --git a/mypy/typeshed/stdlib/ctypes/wintypes.pyi b/mypy/typeshed/stdlib/ctypes/wintypes.pyi index 8847860f2002..e938d8f22957 100644 --- a/mypy/typeshed/stdlib/ctypes/wintypes.pyi +++ b/mypy/typeshed/stdlib/ctypes/wintypes.pyi @@ -1,7 +1,7 @@ +from _ctypes import _CArgObject, _CField from ctypes import ( Array, Structure, - _CField, _Pointer, _SimpleCData, c_byte, @@ -21,8 +21,8 @@ from ctypes import ( c_wchar, c_wchar_p, ) -from typing import TypeVar -from typing_extensions import TypeAlias +from typing import Any, TypeVar +from typing_extensions import Self, TypeAlias BYTE = c_byte WORD = c_ushort @@ -241,10 +241,16 @@ LPBYTE = PBYTE PBOOLEAN = PBYTE # LP_c_char -class PCHAR(_Pointer[CHAR]): ... +class PCHAR(_Pointer[CHAR]): + # this is inherited from ctypes.c_char_p, kind of. + @classmethod + def from_param(cls, value: Any, /) -> Self | _CArgObject: ... # LP_c_wchar -class PWCHAR(_Pointer[WCHAR]): ... +class PWCHAR(_Pointer[WCHAR]): + # inherited from ctypes.c_wchar_p, kind of + @classmethod + def from_param(cls, value: Any, /) -> Self | _CArgObject: ... # LP_c_void_p class PHANDLE(_Pointer[HANDLE]): ... diff --git a/mypy/typeshed/stdlib/curses/__init__.pyi b/mypy/typeshed/stdlib/curses/__init__.pyi index 1df184dbaa60..edc64a00cd39 100644 --- a/mypy/typeshed/stdlib/curses/__init__.pyi +++ b/mypy/typeshed/stdlib/curses/__init__.pyi @@ -1,7 +1,9 @@ +import sys from _curses import * -from _curses import _CursesWindow as _CursesWindow +from _curses import window as window +from _typeshed import structseq from collections.abc import Callable -from typing import TypeVar +from typing import Final, TypeVar, final, type_check_only from typing_extensions import Concatenate, ParamSpec # NOTE: The _curses module is ordinarily only available on Unix, but the @@ -19,4 +21,25 @@ COLS: int COLORS: int COLOR_PAIRS: int -def wrapper(func: Callable[Concatenate[_CursesWindow, _P], _T], /, *arg: _P.args, **kwds: _P.kwargs) -> _T: ... +def wrapper(func: Callable[Concatenate[window, _P], _T], /, *arg: _P.args, **kwds: _P.kwargs) -> _T: ... + +# typeshed used the name _CursesWindow for the underlying C class before +# it was mapped to the name 'window' in 3.8. +# Kept here as a legacy alias in case any third-party code is relying on it. +_CursesWindow = window + +# At runtime this class is unexposed and calls itself curses.ncurses_version. +# That name would conflict with the actual curses.ncurses_version, which is +# an instance of this class. +@final +@type_check_only +class _ncurses_version(structseq[int], tuple[int, int, int]): + if sys.version_info >= (3, 10): + __match_args__: Final = ("major", "minor", "patch") + + @property + def major(self) -> int: ... + @property + def minor(self) -> int: ... + @property + def patch(self) -> int: ... diff --git a/mypy/typeshed/stdlib/curses/panel.pyi b/mypy/typeshed/stdlib/curses/panel.pyi index 3d3448bd9584..861559d38bc5 100644 --- a/mypy/typeshed/stdlib/curses/panel.pyi +++ b/mypy/typeshed/stdlib/curses/panel.pyi @@ -1,22 +1 @@ -from _curses import _CursesWindow - -version: str - -class _Curses_Panel: # type is (note the space in the class name) - def above(self) -> _Curses_Panel: ... - def below(self) -> _Curses_Panel: ... - def bottom(self) -> None: ... - def hidden(self) -> bool: ... - def hide(self) -> None: ... - def move(self, y: int, x: int) -> None: ... - def replace(self, win: _CursesWindow) -> None: ... - def set_userptr(self, obj: object) -> None: ... - def show(self) -> None: ... - def top(self) -> None: ... - def userptr(self) -> object: ... - def window(self) -> _CursesWindow: ... - -def bottom_panel() -> _Curses_Panel: ... -def new_panel(win: _CursesWindow, /) -> _Curses_Panel: ... -def top_panel() -> _Curses_Panel: ... -def update_panels() -> _Curses_Panel: ... +from _curses_panel import * diff --git a/mypy/typeshed/stdlib/curses/textpad.pyi b/mypy/typeshed/stdlib/curses/textpad.pyi index ce6eed09b289..48ef67c9d85f 100644 --- a/mypy/typeshed/stdlib/curses/textpad.pyi +++ b/mypy/typeshed/stdlib/curses/textpad.pyi @@ -1,11 +1,11 @@ -from _curses import _CursesWindow +from _curses import window from collections.abc import Callable -def rectangle(win: _CursesWindow, uly: int, ulx: int, lry: int, lrx: int) -> None: ... +def rectangle(win: window, uly: int, ulx: int, lry: int, lrx: int) -> None: ... class Textbox: stripspaces: bool - def __init__(self, win: _CursesWindow, insert_mode: bool = False) -> None: ... + def __init__(self, win: window, insert_mode: bool = False) -> None: ... def edit(self, validate: Callable[[int], int] | None = None) -> str: ... def do_command(self, ch: str | int) -> None: ... def gather(self) -> str: ... diff --git a/mypy/typeshed/stdlib/datetime.pyi b/mypy/typeshed/stdlib/datetime.pyi index e8a4efdc61f3..87037ef39be7 100644 --- a/mypy/typeshed/stdlib/datetime.pyi +++ b/mypy/typeshed/stdlib/datetime.pyi @@ -1,8 +1,8 @@ import sys from abc import abstractmethod from time import struct_time -from typing import ClassVar, Final, NamedTuple, NoReturn, SupportsIndex, final, overload -from typing_extensions import Self, TypeAlias, deprecated +from typing import ClassVar, Final, NoReturn, SupportsIndex, final, overload, type_check_only +from typing_extensions import CapsuleType, Self, TypeAlias, deprecated if sys.version_info >= (3, 11): __all__ = ("date", "datetime", "time", "timedelta", "timezone", "tzinfo", "MINYEAR", "MAXYEAR", "UTC") @@ -40,10 +40,17 @@ if sys.version_info >= (3, 11): UTC: timezone if sys.version_info >= (3, 9): - class _IsoCalendarDate(NamedTuple): - year: int - week: int - weekday: int + # This class calls itself datetime.IsoCalendarDate. It's neither + # NamedTuple nor structseq. + @final + @type_check_only + class _IsoCalendarDate(tuple[int, int, int]): + @property + def year(self) -> int: ... + @property + def week(self) -> int: ... + @property + def weekday(self) -> int: ... class date: min: ClassVar[date] @@ -325,3 +332,5 @@ class datetime(date): def __sub__(self, value: Self, /) -> timedelta: ... @overload def __sub__(self, value: timedelta, /) -> Self: ... + +datetime_CAPI: CapsuleType diff --git a/mypy/typeshed/stdlib/dbm/__init__.pyi b/mypy/typeshed/stdlib/dbm/__init__.pyi index f414763e02a6..7f344060f9ab 100644 --- a/mypy/typeshed/stdlib/dbm/__init__.pyi +++ b/mypy/typeshed/stdlib/dbm/__init__.pyi @@ -2,7 +2,7 @@ import sys from _typeshed import StrOrBytesPath from collections.abc import Iterator, MutableMapping from types import TracebackType -from typing import Literal +from typing import Literal, type_check_only from typing_extensions import Self, TypeAlias __all__ = ["open", "whichdb", "error"] @@ -89,6 +89,8 @@ class _Database(MutableMapping[_KeyType, bytes]): self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None ) -> None: ... +# This class is not exposed. It calls itself dbm.error. +@type_check_only class _error(Exception): ... error: tuple[type[_error], type[OSError]] diff --git a/mypy/typeshed/stdlib/dbm/gnu.pyi b/mypy/typeshed/stdlib/dbm/gnu.pyi index 1d1d541f5477..2dac3d12b0ca 100644 --- a/mypy/typeshed/stdlib/dbm/gnu.pyi +++ b/mypy/typeshed/stdlib/dbm/gnu.pyi @@ -1,47 +1 @@ -import sys -from _typeshed import ReadOnlyBuffer, StrOrBytesPath -from types import TracebackType -from typing import TypeVar, overload -from typing_extensions import Self, TypeAlias - -if sys.platform != "win32": - _T = TypeVar("_T") - _KeyType: TypeAlias = str | ReadOnlyBuffer - _ValueType: TypeAlias = str | ReadOnlyBuffer - - open_flags: str - - class error(OSError): ... - # Actual typename gdbm, not exposed by the implementation - class _gdbm: - def firstkey(self) -> bytes | None: ... - def nextkey(self, key: _KeyType) -> bytes | None: ... - def reorganize(self) -> None: ... - def sync(self) -> None: ... - def close(self) -> None: ... - if sys.version_info >= (3, 13): - def clear(self) -> None: ... - - def __getitem__(self, item: _KeyType) -> bytes: ... - def __setitem__(self, key: _KeyType, value: _ValueType) -> None: ... - def __delitem__(self, key: _KeyType) -> None: ... - def __contains__(self, key: _KeyType) -> bool: ... - def __len__(self) -> int: ... - def __enter__(self) -> Self: ... - def __exit__( - self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None - ) -> None: ... - @overload - def get(self, k: _KeyType) -> bytes | None: ... - @overload - def get(self, k: _KeyType, default: _T) -> bytes | _T: ... - def keys(self) -> list[bytes]: ... - def setdefault(self, k: _KeyType, default: _ValueType = ...) -> bytes: ... - # Don't exist at runtime - __new__: None # type: ignore[assignment] - __init__: None # type: ignore[assignment] - - if sys.version_info >= (3, 11): - def open(filename: StrOrBytesPath, flags: str = "r", mode: int = 0o666, /) -> _gdbm: ... - else: - def open(filename: str, flags: str = "r", mode: int = 0o666, /) -> _gdbm: ... +from _gdbm import * diff --git a/mypy/typeshed/stdlib/dbm/ndbm.pyi b/mypy/typeshed/stdlib/dbm/ndbm.pyi index 4113a7e3ffb9..66c943ab640b 100644 --- a/mypy/typeshed/stdlib/dbm/ndbm.pyi +++ b/mypy/typeshed/stdlib/dbm/ndbm.pyi @@ -1,43 +1 @@ -import sys -from _typeshed import ReadOnlyBuffer, StrOrBytesPath -from types import TracebackType -from typing import TypeVar, overload -from typing_extensions import Self, TypeAlias - -if sys.platform != "win32": - _T = TypeVar("_T") - _KeyType: TypeAlias = str | ReadOnlyBuffer - _ValueType: TypeAlias = str | ReadOnlyBuffer - - class error(OSError): ... - library: str - - # Actual typename dbm, not exposed by the implementation - class _dbm: - def close(self) -> None: ... - if sys.version_info >= (3, 13): - def clear(self) -> None: ... - - def __getitem__(self, item: _KeyType) -> bytes: ... - def __setitem__(self, key: _KeyType, value: _ValueType) -> None: ... - def __delitem__(self, key: _KeyType) -> None: ... - def __len__(self) -> int: ... - def __del__(self) -> None: ... - def __enter__(self) -> Self: ... - def __exit__( - self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None - ) -> None: ... - @overload - def get(self, k: _KeyType) -> bytes | None: ... - @overload - def get(self, k: _KeyType, default: _T) -> bytes | _T: ... - def keys(self) -> list[bytes]: ... - def setdefault(self, k: _KeyType, default: _ValueType = ...) -> bytes: ... - # Don't exist at runtime - __new__: None # type: ignore[assignment] - __init__: None # type: ignore[assignment] - - if sys.version_info >= (3, 11): - def open(filename: StrOrBytesPath, flags: str = "r", mode: int = 0o666, /) -> _dbm: ... - else: - def open(filename: str, flags: str = "r", mode: int = 0o666, /) -> _dbm: ... +from _dbm import * diff --git a/mypy/typeshed/stdlib/decimal.pyi b/mypy/typeshed/stdlib/decimal.pyi index 35fc4405f11b..7f8708a020fd 100644 --- a/mypy/typeshed/stdlib/decimal.pyi +++ b/mypy/typeshed/stdlib/decimal.pyi @@ -1,2 +1,265 @@ -from _decimal import * -from _decimal import __libmpdec_version__ as __libmpdec_version__, __version__ as __version__ +import numbers +from _decimal import ( + HAVE_CONTEXTVAR as HAVE_CONTEXTVAR, + HAVE_THREADS as HAVE_THREADS, + MAX_EMAX as MAX_EMAX, + MAX_PREC as MAX_PREC, + MIN_EMIN as MIN_EMIN, + MIN_ETINY as MIN_ETINY, + ROUND_05UP as ROUND_05UP, + ROUND_CEILING as ROUND_CEILING, + ROUND_DOWN as ROUND_DOWN, + ROUND_FLOOR as ROUND_FLOOR, + ROUND_HALF_DOWN as ROUND_HALF_DOWN, + ROUND_HALF_EVEN as ROUND_HALF_EVEN, + ROUND_HALF_UP as ROUND_HALF_UP, + ROUND_UP as ROUND_UP, + BasicContext as BasicContext, + DefaultContext as DefaultContext, + ExtendedContext as ExtendedContext, + __libmpdec_version__ as __libmpdec_version__, + __version__ as __version__, + getcontext as getcontext, + localcontext as localcontext, + setcontext as setcontext, +) +from collections.abc import Container, Sequence +from types import TracebackType +from typing import Any, ClassVar, Literal, NamedTuple, final, overload, type_check_only +from typing_extensions import Self, TypeAlias + +_Decimal: TypeAlias = Decimal | int +_DecimalNew: TypeAlias = Decimal | float | str | tuple[int, Sequence[int], int] +_ComparableNum: TypeAlias = Decimal | float | numbers.Rational +_TrapType: TypeAlias = type[DecimalException] + +# At runtime, these classes are implemented in C as part of "_decimal". +# However, they consider themselves to live in "decimal", so we'll put them here. + +# This type isn't exposed at runtime. It calls itself decimal.ContextManager +@final +@type_check_only +class _ContextManager: + def __init__(self, new_context: Context) -> None: ... + def __enter__(self) -> Context: ... + def __exit__(self, t: type[BaseException] | None, v: BaseException | None, tb: TracebackType | None) -> None: ... + +class DecimalTuple(NamedTuple): + sign: int + digits: tuple[int, ...] + exponent: int | Literal["n", "N", "F"] + +class DecimalException(ArithmeticError): ... +class Clamped(DecimalException): ... +class InvalidOperation(DecimalException): ... +class ConversionSyntax(InvalidOperation): ... +class DivisionByZero(DecimalException, ZeroDivisionError): ... +class DivisionImpossible(InvalidOperation): ... +class DivisionUndefined(InvalidOperation, ZeroDivisionError): ... +class Inexact(DecimalException): ... +class InvalidContext(InvalidOperation): ... +class Rounded(DecimalException): ... +class Subnormal(DecimalException): ... +class Overflow(Inexact, Rounded): ... +class Underflow(Inexact, Rounded, Subnormal): ... +class FloatOperation(DecimalException, TypeError): ... + +class Decimal: + def __new__(cls, value: _DecimalNew = ..., context: Context | None = ...) -> Self: ... + @classmethod + def from_float(cls, f: float, /) -> Self: ... + def __bool__(self) -> bool: ... + def compare(self, other: _Decimal, context: Context | None = None) -> Decimal: ... + def __hash__(self) -> int: ... + def as_tuple(self) -> DecimalTuple: ... + def as_integer_ratio(self) -> tuple[int, int]: ... + def to_eng_string(self, context: Context | None = None) -> str: ... + def __abs__(self) -> Decimal: ... + def __add__(self, value: _Decimal, /) -> Decimal: ... + def __divmod__(self, value: _Decimal, /) -> tuple[Decimal, Decimal]: ... + def __eq__(self, value: object, /) -> bool: ... + def __floordiv__(self, value: _Decimal, /) -> Decimal: ... + def __ge__(self, value: _ComparableNum, /) -> bool: ... + def __gt__(self, value: _ComparableNum, /) -> bool: ... + def __le__(self, value: _ComparableNum, /) -> bool: ... + def __lt__(self, value: _ComparableNum, /) -> bool: ... + def __mod__(self, value: _Decimal, /) -> Decimal: ... + def __mul__(self, value: _Decimal, /) -> Decimal: ... + def __neg__(self) -> Decimal: ... + def __pos__(self) -> Decimal: ... + def __pow__(self, value: _Decimal, mod: _Decimal | None = None, /) -> Decimal: ... + def __radd__(self, value: _Decimal, /) -> Decimal: ... + def __rdivmod__(self, value: _Decimal, /) -> tuple[Decimal, Decimal]: ... + def __rfloordiv__(self, value: _Decimal, /) -> Decimal: ... + def __rmod__(self, value: _Decimal, /) -> Decimal: ... + def __rmul__(self, value: _Decimal, /) -> Decimal: ... + def __rsub__(self, value: _Decimal, /) -> Decimal: ... + def __rtruediv__(self, value: _Decimal, /) -> Decimal: ... + def __sub__(self, value: _Decimal, /) -> Decimal: ... + def __truediv__(self, value: _Decimal, /) -> Decimal: ... + def remainder_near(self, other: _Decimal, context: Context | None = None) -> Decimal: ... + def __float__(self) -> float: ... + def __int__(self) -> int: ... + def __trunc__(self) -> int: ... + @property + def real(self) -> Decimal: ... + @property + def imag(self) -> Decimal: ... + def conjugate(self) -> Decimal: ... + def __complex__(self) -> complex: ... + @overload + def __round__(self) -> int: ... + @overload + def __round__(self, ndigits: int, /) -> Decimal: ... + def __floor__(self) -> int: ... + def __ceil__(self) -> int: ... + def fma(self, other: _Decimal, third: _Decimal, context: Context | None = None) -> Decimal: ... + def __rpow__(self, value: _Decimal, mod: Context | None = None, /) -> Decimal: ... + def normalize(self, context: Context | None = None) -> Decimal: ... + def quantize(self, exp: _Decimal, rounding: str | None = None, context: Context | None = None) -> Decimal: ... + def same_quantum(self, other: _Decimal, context: Context | None = None) -> bool: ... + def to_integral_exact(self, rounding: str | None = None, context: Context | None = None) -> Decimal: ... + def to_integral_value(self, rounding: str | None = None, context: Context | None = None) -> Decimal: ... + def to_integral(self, rounding: str | None = None, context: Context | None = None) -> Decimal: ... + def sqrt(self, context: Context | None = None) -> Decimal: ... + def max(self, other: _Decimal, context: Context | None = None) -> Decimal: ... + def min(self, other: _Decimal, context: Context | None = None) -> Decimal: ... + def adjusted(self) -> int: ... + def canonical(self) -> Decimal: ... + def compare_signal(self, other: _Decimal, context: Context | None = None) -> Decimal: ... + def compare_total(self, other: _Decimal, context: Context | None = None) -> Decimal: ... + def compare_total_mag(self, other: _Decimal, context: Context | None = None) -> Decimal: ... + def copy_abs(self) -> Decimal: ... + def copy_negate(self) -> Decimal: ... + def copy_sign(self, other: _Decimal, context: Context | None = None) -> Decimal: ... + def exp(self, context: Context | None = None) -> Decimal: ... + def is_canonical(self) -> bool: ... + def is_finite(self) -> bool: ... + def is_infinite(self) -> bool: ... + def is_nan(self) -> bool: ... + def is_normal(self, context: Context | None = None) -> bool: ... + def is_qnan(self) -> bool: ... + def is_signed(self) -> bool: ... + def is_snan(self) -> bool: ... + def is_subnormal(self, context: Context | None = None) -> bool: ... + def is_zero(self) -> bool: ... + def ln(self, context: Context | None = None) -> Decimal: ... + def log10(self, context: Context | None = None) -> Decimal: ... + def logb(self, context: Context | None = None) -> Decimal: ... + def logical_and(self, other: _Decimal, context: Context | None = None) -> Decimal: ... + def logical_invert(self, context: Context | None = None) -> Decimal: ... + def logical_or(self, other: _Decimal, context: Context | None = None) -> Decimal: ... + def logical_xor(self, other: _Decimal, context: Context | None = None) -> Decimal: ... + def max_mag(self, other: _Decimal, context: Context | None = None) -> Decimal: ... + def min_mag(self, other: _Decimal, context: Context | None = None) -> Decimal: ... + def next_minus(self, context: Context | None = None) -> Decimal: ... + def next_plus(self, context: Context | None = None) -> Decimal: ... + def next_toward(self, other: _Decimal, context: Context | None = None) -> Decimal: ... + def number_class(self, context: Context | None = None) -> str: ... + def radix(self) -> Decimal: ... + def rotate(self, other: _Decimal, context: Context | None = None) -> Decimal: ... + def scaleb(self, other: _Decimal, context: Context | None = None) -> Decimal: ... + def shift(self, other: _Decimal, context: Context | None = None) -> Decimal: ... + def __reduce__(self) -> tuple[type[Self], tuple[str]]: ... + def __copy__(self) -> Self: ... + def __deepcopy__(self, memo: Any, /) -> Self: ... + def __format__(self, specifier: str, context: Context | None = ..., /) -> str: ... + +class Context: + # TODO: Context doesn't allow you to delete *any* attributes from instances of the class at runtime, + # even settable attributes like `prec` and `rounding`, + # but that's inexpressable in the stub. + # Type checkers either ignore it or misinterpret it + # if you add a `def __delattr__(self, name: str, /) -> NoReturn` method to the stub + prec: int + rounding: str + Emin: int + Emax: int + capitals: int + clamp: int + traps: dict[_TrapType, bool] + flags: dict[_TrapType, bool] + def __init__( + self, + prec: int | None = ..., + rounding: str | None = ..., + Emin: int | None = ..., + Emax: int | None = ..., + capitals: int | None = ..., + clamp: int | None = ..., + flags: None | dict[_TrapType, bool] | Container[_TrapType] = ..., + traps: None | dict[_TrapType, bool] | Container[_TrapType] = ..., + _ignored_flags: list[_TrapType] | None = ..., + ) -> None: ... + def __reduce__(self) -> tuple[type[Self], tuple[Any, ...]]: ... + def clear_flags(self) -> None: ... + def clear_traps(self) -> None: ... + def copy(self) -> Context: ... + def __copy__(self) -> Context: ... + # see https://github.com/python/cpython/issues/94107 + __hash__: ClassVar[None] # type: ignore[assignment] + def Etiny(self) -> int: ... + def Etop(self) -> int: ... + def create_decimal(self, num: _DecimalNew = "0", /) -> Decimal: ... + def create_decimal_from_float(self, f: float, /) -> Decimal: ... + def abs(self, x: _Decimal, /) -> Decimal: ... + def add(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... + def canonical(self, x: Decimal, /) -> Decimal: ... + def compare(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... + def compare_signal(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... + def compare_total(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... + def compare_total_mag(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... + def copy_abs(self, x: _Decimal, /) -> Decimal: ... + def copy_decimal(self, x: _Decimal, /) -> Decimal: ... + def copy_negate(self, x: _Decimal, /) -> Decimal: ... + def copy_sign(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... + def divide(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... + def divide_int(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... + def divmod(self, x: _Decimal, y: _Decimal, /) -> tuple[Decimal, Decimal]: ... + def exp(self, x: _Decimal, /) -> Decimal: ... + def fma(self, x: _Decimal, y: _Decimal, z: _Decimal, /) -> Decimal: ... + def is_canonical(self, x: _Decimal, /) -> bool: ... + def is_finite(self, x: _Decimal, /) -> bool: ... + def is_infinite(self, x: _Decimal, /) -> bool: ... + def is_nan(self, x: _Decimal, /) -> bool: ... + def is_normal(self, x: _Decimal, /) -> bool: ... + def is_qnan(self, x: _Decimal, /) -> bool: ... + def is_signed(self, x: _Decimal, /) -> bool: ... + def is_snan(self, x: _Decimal, /) -> bool: ... + def is_subnormal(self, x: _Decimal, /) -> bool: ... + def is_zero(self, x: _Decimal, /) -> bool: ... + def ln(self, x: _Decimal, /) -> Decimal: ... + def log10(self, x: _Decimal, /) -> Decimal: ... + def logb(self, x: _Decimal, /) -> Decimal: ... + def logical_and(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... + def logical_invert(self, x: _Decimal, /) -> Decimal: ... + def logical_or(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... + def logical_xor(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... + def max(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... + def max_mag(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... + def min(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... + def min_mag(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... + def minus(self, x: _Decimal, /) -> Decimal: ... + def multiply(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... + def next_minus(self, x: _Decimal, /) -> Decimal: ... + def next_plus(self, x: _Decimal, /) -> Decimal: ... + def next_toward(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... + def normalize(self, x: _Decimal, /) -> Decimal: ... + def number_class(self, x: _Decimal, /) -> str: ... + def plus(self, x: _Decimal, /) -> Decimal: ... + def power(self, a: _Decimal, b: _Decimal, modulo: _Decimal | None = None) -> Decimal: ... + def quantize(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... + def radix(self) -> Decimal: ... + def remainder(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... + def remainder_near(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... + def rotate(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... + def same_quantum(self, x: _Decimal, y: _Decimal, /) -> bool: ... + def scaleb(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... + def shift(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... + def sqrt(self, x: _Decimal, /) -> Decimal: ... + def subtract(self, x: _Decimal, y: _Decimal, /) -> Decimal: ... + def to_eng_string(self, x: _Decimal, /) -> str: ... + def to_sci_string(self, x: _Decimal, /) -> str: ... + def to_integral_exact(self, x: _Decimal, /) -> Decimal: ... + def to_integral_value(self, x: _Decimal, /) -> Decimal: ... + def to_integral(self, x: _Decimal, /) -> Decimal: ... diff --git a/mypy/typeshed/stdlib/distutils/_msvccompiler.pyi b/mypy/typeshed/stdlib/distutils/_msvccompiler.pyi new file mode 100644 index 000000000000..bba9373b72db --- /dev/null +++ b/mypy/typeshed/stdlib/distutils/_msvccompiler.pyi @@ -0,0 +1,13 @@ +from _typeshed import Incomplete +from distutils.ccompiler import CCompiler +from typing import ClassVar, Final + +PLAT_SPEC_TO_RUNTIME: Final[dict[str, str]] +PLAT_TO_VCVARS: Final[dict[str, str]] + +class MSVCCompiler(CCompiler): + compiler_type: ClassVar[str] + executables: ClassVar[dict[Incomplete, Incomplete]] + res_extension: ClassVar[str] + initialized: bool + def initialize(self, plat_name: str | None = None) -> None: ... diff --git a/mypy/typeshed/stdlib/distutils/ccompiler.pyi b/mypy/typeshed/stdlib/distutils/ccompiler.pyi index e0f33f430e5a..5bff209807ee 100644 --- a/mypy/typeshed/stdlib/distutils/ccompiler.pyi +++ b/mypy/typeshed/stdlib/distutils/ccompiler.pyi @@ -1,5 +1,5 @@ from _typeshed import BytesPath, StrPath, Unused -from collections.abc import Callable, Iterable +from collections.abc import Callable, Iterable, Sequence from distutils.file_util import _BytesPathT, _StrPathT from typing import Literal, overload from typing_extensions import TypeAlias, TypeVarTuple, Unpack @@ -63,7 +63,7 @@ class CCompiler: def set_executables(self, **args: str) -> None: ... def compile( self, - sources: list[str], + sources: Sequence[StrPath], output_dir: str | None = None, macros: list[_Macro] | None = None, include_dirs: list[str] | None = None, @@ -165,7 +165,7 @@ class CCompiler: def execute( self, func: Callable[[Unpack[_Ts]], Unused], args: tuple[Unpack[_Ts]], msg: str | None = None, level: int = 1 ) -> None: ... - def spawn(self, cmd: list[str]) -> None: ... + def spawn(self, cmd: Iterable[str]) -> None: ... def mkpath(self, name: str, mode: int = 0o777) -> None: ... @overload def move_file(self, src: StrPath, dst: _StrPathT) -> _StrPathT | str: ... diff --git a/mypy/typeshed/stdlib/distutils/command/bdist.pyi b/mypy/typeshed/stdlib/distutils/command/bdist.pyi index 43d77087f7d8..6f996207077e 100644 --- a/mypy/typeshed/stdlib/distutils/command/bdist.pyi +++ b/mypy/typeshed/stdlib/distutils/command/bdist.pyi @@ -1,6 +1,6 @@ -from _typeshed import Unused +from _typeshed import Incomplete, Unused from collections.abc import Callable -from typing import Any, ClassVar +from typing import ClassVar from ..cmd import Command @@ -15,13 +15,13 @@ class bdist(Command): default_format: ClassVar[dict[str, str]] format_commands: ClassVar[list[str]] format_command: ClassVar[dict[str, tuple[str, str]]] - bdist_base: Any - plat_name: Any - formats: Any - dist_dir: Any + bdist_base: Incomplete + plat_name: Incomplete + formats: Incomplete + dist_dir: Incomplete skip_build: int - group: Any - owner: Any + group: Incomplete + owner: Incomplete def initialize_options(self) -> None: ... def finalize_options(self) -> None: ... def run(self) -> None: ... diff --git a/mypy/typeshed/stdlib/distutils/command/bdist_dumb.pyi b/mypy/typeshed/stdlib/distutils/command/bdist_dumb.pyi index 19997882dd53..297a0c39ed43 100644 --- a/mypy/typeshed/stdlib/distutils/command/bdist_dumb.pyi +++ b/mypy/typeshed/stdlib/distutils/command/bdist_dumb.pyi @@ -1,4 +1,5 @@ -from typing import Any, ClassVar +from _typeshed import Incomplete +from typing import ClassVar from ..cmd import Command @@ -7,15 +8,15 @@ class bdist_dumb(Command): user_options: ClassVar[list[tuple[str, str | None, str]]] boolean_options: ClassVar[list[str]] default_format: ClassVar[dict[str, str]] - bdist_dir: Any - plat_name: Any - format: Any + bdist_dir: Incomplete + plat_name: Incomplete + format: Incomplete keep_temp: int - dist_dir: Any - skip_build: Any + dist_dir: Incomplete + skip_build: Incomplete relative: int - owner: Any - group: Any + owner: Incomplete + group: Incomplete def initialize_options(self) -> None: ... def finalize_options(self) -> None: ... def run(self) -> None: ... diff --git a/mypy/typeshed/stdlib/distutils/command/bdist_msi.pyi b/mypy/typeshed/stdlib/distutils/command/bdist_msi.pyi index d0eac1a3be5b..baeee7d3eccb 100644 --- a/mypy/typeshed/stdlib/distutils/command/bdist_msi.pyi +++ b/mypy/typeshed/stdlib/distutils/command/bdist_msi.pyi @@ -1,42 +1,43 @@ import sys -from typing import Any, ClassVar, Literal +from _typeshed import Incomplete +from typing import ClassVar, Literal from ..cmd import Command if sys.platform == "win32": - from msilib import Dialog + from msilib import Control, Dialog class PyDialog(Dialog): def __init__(self, *args, **kw) -> None: ... def title(self, title) -> None: ... - def back(self, title, next, name: str = "Back", active: bool | Literal[0, 1] = 1): ... - def cancel(self, title, next, name: str = "Cancel", active: bool | Literal[0, 1] = 1): ... - def next(self, title, next, name: str = "Next", active: bool | Literal[0, 1] = 1): ... - def xbutton(self, name, title, next, xpos): ... + def back(self, title, next, name: str = "Back", active: bool | Literal[0, 1] = 1) -> Control: ... + def cancel(self, title, next, name: str = "Cancel", active: bool | Literal[0, 1] = 1) -> Control: ... + def next(self, title, next, name: str = "Next", active: bool | Literal[0, 1] = 1) -> Control: ... + def xbutton(self, name, title, next, xpos) -> Control: ... class bdist_msi(Command): description: str user_options: ClassVar[list[tuple[str, str | None, str]]] boolean_options: ClassVar[list[str]] - all_versions: Any + all_versions: Incomplete other_version: str if sys.version_info >= (3, 9): def __init__(self, *args, **kw) -> None: ... - bdist_dir: Any - plat_name: Any + bdist_dir: Incomplete + plat_name: Incomplete keep_temp: int no_target_compile: int no_target_optimize: int - target_version: Any - dist_dir: Any - skip_build: Any - install_script: Any - pre_install_script: Any - versions: Any + target_version: Incomplete + dist_dir: Incomplete + skip_build: Incomplete + install_script: Incomplete + pre_install_script: Incomplete + versions: Incomplete def initialize_options(self) -> None: ... - install_script_key: Any + install_script_key: Incomplete def finalize_options(self) -> None: ... - db: Any + db: Incomplete def run(self) -> None: ... def add_files(self) -> None: ... def add_find_python(self) -> None: ... diff --git a/mypy/typeshed/stdlib/distutils/command/bdist_rpm.pyi b/mypy/typeshed/stdlib/distutils/command/bdist_rpm.pyi index 89c43e1b974c..83b4161094c5 100644 --- a/mypy/typeshed/stdlib/distutils/command/bdist_rpm.pyi +++ b/mypy/typeshed/stdlib/distutils/command/bdist_rpm.pyi @@ -1,4 +1,5 @@ -from typing import Any, ClassVar +from _typeshed import Incomplete +from typing import ClassVar from ..cmd import Command @@ -7,44 +8,44 @@ class bdist_rpm(Command): user_options: ClassVar[list[tuple[str, str | None, str]]] boolean_options: ClassVar[list[str]] negative_opt: ClassVar[dict[str, str]] - bdist_base: Any - rpm_base: Any - dist_dir: Any - python: Any - fix_python: Any - spec_only: Any - binary_only: Any - source_only: Any - use_bzip2: Any - distribution_name: Any - group: Any - release: Any - serial: Any - vendor: Any - packager: Any - doc_files: Any - changelog: Any - icon: Any - prep_script: Any - build_script: Any - install_script: Any - clean_script: Any - verify_script: Any - pre_install: Any - post_install: Any - pre_uninstall: Any - post_uninstall: Any - prep: Any - provides: Any - requires: Any - conflicts: Any - build_requires: Any - obsoletes: Any + bdist_base: Incomplete + rpm_base: Incomplete + dist_dir: Incomplete + python: Incomplete + fix_python: Incomplete + spec_only: Incomplete + binary_only: Incomplete + source_only: Incomplete + use_bzip2: Incomplete + distribution_name: Incomplete + group: Incomplete + release: Incomplete + serial: Incomplete + vendor: Incomplete + packager: Incomplete + doc_files: Incomplete + changelog: Incomplete + icon: Incomplete + prep_script: Incomplete + build_script: Incomplete + install_script: Incomplete + clean_script: Incomplete + verify_script: Incomplete + pre_install: Incomplete + post_install: Incomplete + pre_uninstall: Incomplete + post_uninstall: Incomplete + prep: Incomplete + provides: Incomplete + requires: Incomplete + conflicts: Incomplete + build_requires: Incomplete + obsoletes: Incomplete keep_temp: int use_rpm_opt_flags: int rpm3_mode: int no_autoreq: int - force_arch: Any + force_arch: Incomplete quiet: int def initialize_options(self) -> None: ... def finalize_options(self) -> None: ... diff --git a/mypy/typeshed/stdlib/distutils/command/build.pyi b/mypy/typeshed/stdlib/distutils/command/build.pyi index 78ba6b7042dc..3ec0c9614d62 100644 --- a/mypy/typeshed/stdlib/distutils/command/build.pyi +++ b/mypy/typeshed/stdlib/distutils/command/build.pyi @@ -1,4 +1,4 @@ -from _typeshed import Unused +from _typeshed import Incomplete, Unused from collections.abc import Callable from typing import Any, ClassVar @@ -12,17 +12,17 @@ class build(Command): boolean_options: ClassVar[list[str]] help_options: ClassVar[list[tuple[str, str | None, str, Callable[[], Unused]]]] build_base: str - build_purelib: Any - build_platlib: Any - build_lib: Any - build_temp: Any - build_scripts: Any - compiler: Any - plat_name: Any - debug: Any + build_purelib: Incomplete + build_platlib: Incomplete + build_lib: Incomplete + build_temp: Incomplete + build_scripts: Incomplete + compiler: Incomplete + plat_name: Incomplete + debug: Incomplete force: int - executable: Any - parallel: Any + executable: Incomplete + parallel: Incomplete def initialize_options(self) -> None: ... def finalize_options(self) -> None: ... def run(self) -> None: ... diff --git a/mypy/typeshed/stdlib/distutils/command/build_clib.pyi b/mypy/typeshed/stdlib/distutils/command/build_clib.pyi index 1f66e2efc20c..69cfbe7120d8 100644 --- a/mypy/typeshed/stdlib/distutils/command/build_clib.pyi +++ b/mypy/typeshed/stdlib/distutils/command/build_clib.pyi @@ -1,6 +1,6 @@ -from _typeshed import Unused +from _typeshed import Incomplete, Unused from collections.abc import Callable -from typing import Any, ClassVar +from typing import ClassVar from ..cmd import Command @@ -11,15 +11,15 @@ class build_clib(Command): user_options: ClassVar[list[tuple[str, str, str]]] boolean_options: ClassVar[list[str]] help_options: ClassVar[list[tuple[str, str | None, str, Callable[[], Unused]]]] - build_clib: Any - build_temp: Any - libraries: Any - include_dirs: Any - define: Any - undef: Any - debug: Any + build_clib: Incomplete + build_temp: Incomplete + libraries: Incomplete + include_dirs: Incomplete + define: Incomplete + undef: Incomplete + debug: Incomplete force: int - compiler: Any + compiler: Incomplete def initialize_options(self) -> None: ... def finalize_options(self) -> None: ... def run(self) -> None: ... diff --git a/mypy/typeshed/stdlib/distutils/command/build_ext.pyi b/mypy/typeshed/stdlib/distutils/command/build_ext.pyi index a0813c314021..c5a9b5d508f0 100644 --- a/mypy/typeshed/stdlib/distutils/command/build_ext.pyi +++ b/mypy/typeshed/stdlib/distutils/command/build_ext.pyi @@ -1,40 +1,40 @@ -from _typeshed import Unused +from _typeshed import Incomplete, Unused from collections.abc import Callable -from typing import Any, ClassVar +from typing import ClassVar from ..cmd import Command -extension_name_re: Any +extension_name_re: Incomplete def show_compilers() -> None: ... class build_ext(Command): description: str - sep_by: Any + sep_by: Incomplete user_options: ClassVar[list[tuple[str, str | None, str]]] boolean_options: ClassVar[list[str]] help_options: ClassVar[list[tuple[str, str | None, str, Callable[[], Unused]]]] - extensions: Any - build_lib: Any - plat_name: Any - build_temp: Any + extensions: Incomplete + build_lib: Incomplete + plat_name: Incomplete + build_temp: Incomplete inplace: int - package: Any - include_dirs: Any - define: Any - undef: Any - libraries: Any - library_dirs: Any - rpath: Any - link_objects: Any - debug: Any - force: Any - compiler: Any - swig: Any - swig_cpp: Any - swig_opts: Any - user: Any - parallel: Any + package: Incomplete + include_dirs: Incomplete + define: Incomplete + undef: Incomplete + libraries: Incomplete + library_dirs: Incomplete + rpath: Incomplete + link_objects: Incomplete + debug: Incomplete + force: Incomplete + compiler: Incomplete + swig: Incomplete + swig_cpp: Incomplete + swig_opts: Incomplete + user: Incomplete + parallel: Incomplete def initialize_options(self) -> None: ... def finalize_options(self) -> None: ... def run(self) -> None: ... diff --git a/mypy/typeshed/stdlib/distutils/command/build_py.pyi b/mypy/typeshed/stdlib/distutils/command/build_py.pyi index 90f06751416a..23ed230bb2d8 100644 --- a/mypy/typeshed/stdlib/distutils/command/build_py.pyi +++ b/mypy/typeshed/stdlib/distutils/command/build_py.pyi @@ -1,4 +1,5 @@ -from typing import Any, ClassVar, Literal +from _typeshed import Incomplete +from typing import ClassVar, Literal from ..cmd import Command from ..util import Mixin2to3 as Mixin2to3 @@ -8,17 +9,17 @@ class build_py(Command): user_options: ClassVar[list[tuple[str, str | None, str]]] boolean_options: ClassVar[list[str]] negative_opt: ClassVar[dict[str, str]] - build_lib: Any - py_modules: Any - package: Any - package_data: Any - package_dir: Any + build_lib: Incomplete + py_modules: Incomplete + package: Incomplete + package_data: Incomplete + package_dir: Incomplete compile: int optimize: int - force: Any + force: Incomplete def initialize_options(self) -> None: ... - packages: Any - data_files: Any + packages: Incomplete + data_files: Incomplete def finalize_options(self) -> None: ... def run(self) -> None: ... def get_data_files(self): ... @@ -32,13 +33,13 @@ class build_py(Command): def find_all_modules(self): ... def get_source_files(self): ... def get_module_outfile(self, build_dir, package, module): ... - def get_outputs(self, include_bytecode: bool | Literal[0, 1] = 1): ... + def get_outputs(self, include_bytecode: bool | Literal[0, 1] = 1) -> list[str]: ... def build_module(self, module, module_file, package): ... def build_modules(self) -> None: ... def build_packages(self) -> None: ... def byte_compile(self, files) -> None: ... class build_py_2to3(build_py, Mixin2to3): - updated_files: Any + updated_files: Incomplete def run(self) -> None: ... def build_module(self, module, module_file, package): ... diff --git a/mypy/typeshed/stdlib/distutils/command/build_scripts.pyi b/mypy/typeshed/stdlib/distutils/command/build_scripts.pyi index 7871bb8a5719..8372919bbd53 100644 --- a/mypy/typeshed/stdlib/distutils/command/build_scripts.pyi +++ b/mypy/typeshed/stdlib/distutils/command/build_scripts.pyi @@ -1,19 +1,20 @@ -from typing import Any, ClassVar +from _typeshed import Incomplete +from typing import ClassVar from ..cmd import Command from ..util import Mixin2to3 as Mixin2to3 -first_line_re: Any +first_line_re: Incomplete class build_scripts(Command): description: str user_options: ClassVar[list[tuple[str, str, str]]] boolean_options: ClassVar[list[str]] - build_dir: Any - scripts: Any - force: Any - executable: Any - outfiles: Any + build_dir: Incomplete + scripts: Incomplete + force: Incomplete + executable: Incomplete + outfiles: Incomplete def initialize_options(self) -> None: ... def finalize_options(self) -> None: ... def get_source_files(self): ... diff --git a/mypy/typeshed/stdlib/distutils/command/check.pyi b/mypy/typeshed/stdlib/distutils/command/check.pyi index e69627d20c7a..2c807fd2c439 100644 --- a/mypy/typeshed/stdlib/distutils/command/check.pyi +++ b/mypy/typeshed/stdlib/distutils/command/check.pyi @@ -1,3 +1,4 @@ +from _typeshed import Incomplete from typing import Any, ClassVar, Final, Literal from typing_extensions import TypeAlias @@ -9,13 +10,13 @@ _Reporter: TypeAlias = Any # really docutils.utils.Reporter # Depends on a third-party stub. Since distutils is deprecated anyway, # it's easier to just suppress the "any subclassing" error. class SilentReporter(_Reporter): - messages: Any + messages: Incomplete def __init__( self, source, report_level, halt_level, - stream: Any | None = ..., + stream: Incomplete | None = ..., debug: bool | Literal[0, 1] = 0, encoding: str = ..., error_handler: str = ..., diff --git a/mypy/typeshed/stdlib/distutils/command/clean.pyi b/mypy/typeshed/stdlib/distutils/command/clean.pyi index 55f0a0eeaf10..0f3768d6dcf4 100644 --- a/mypy/typeshed/stdlib/distutils/command/clean.pyi +++ b/mypy/typeshed/stdlib/distutils/command/clean.pyi @@ -1,4 +1,5 @@ -from typing import Any, ClassVar +from _typeshed import Incomplete +from typing import ClassVar from ..cmd import Command @@ -6,12 +7,12 @@ class clean(Command): description: str user_options: ClassVar[list[tuple[str, str | None, str]]] boolean_options: ClassVar[list[str]] - build_base: Any - build_lib: Any - build_temp: Any - build_scripts: Any - bdist_base: Any - all: Any + build_base: Incomplete + build_lib: Incomplete + build_temp: Incomplete + build_scripts: Incomplete + bdist_base: Incomplete + all: Incomplete def initialize_options(self) -> None: ... def finalize_options(self) -> None: ... def run(self) -> None: ... diff --git a/mypy/typeshed/stdlib/distutils/command/config.pyi b/mypy/typeshed/stdlib/distutils/command/config.pyi index b0910091d5b6..562ff3a5271f 100644 --- a/mypy/typeshed/stdlib/distutils/command/config.pyi +++ b/mypy/typeshed/stdlib/distutils/command/config.pyi @@ -1,7 +1,7 @@ -from _typeshed import StrOrBytesPath +from _typeshed import Incomplete, StrOrBytesPath from collections.abc import Sequence from re import Pattern -from typing import Any, ClassVar, Final, Literal +from typing import ClassVar, Final, Literal from ..ccompiler import CCompiler from ..cmd import Command @@ -81,4 +81,4 @@ class config(Command): self, header: str, include_dirs: Sequence[str] | None = None, library_dirs: Sequence[str] | None = None, lang: str = "c" ) -> bool: ... -def dump_file(filename: StrOrBytesPath, head: Any | None = None) -> None: ... +def dump_file(filename: StrOrBytesPath, head: Incomplete | None = None) -> None: ... diff --git a/mypy/typeshed/stdlib/distutils/command/install.pyi b/mypy/typeshed/stdlib/distutils/command/install.pyi index 24a4eff2fb10..1714e01a2c28 100644 --- a/mypy/typeshed/stdlib/distutils/command/install.pyi +++ b/mypy/typeshed/stdlib/distutils/command/install.pyi @@ -1,4 +1,5 @@ import sys +from _typeshed import Incomplete from collections.abc import Callable from typing import Any, ClassVar, Final, Literal @@ -18,33 +19,33 @@ class install(Command): boolean_options: ClassVar[list[str]] negative_opt: ClassVar[dict[str, str]] prefix: str | None - exec_prefix: Any + exec_prefix: Incomplete home: str | None user: bool - install_base: Any - install_platbase: Any + install_base: Incomplete + install_platbase: Incomplete root: str | None - install_purelib: Any - install_platlib: Any - install_headers: Any + install_purelib: Incomplete + install_platlib: Incomplete + install_headers: Incomplete install_lib: str | None - install_scripts: Any - install_data: Any - install_userbase: Any - install_usersite: Any - compile: Any - optimize: Any - extra_path: Any + install_scripts: Incomplete + install_data: Incomplete + install_userbase: Incomplete + install_usersite: Incomplete + compile: Incomplete + optimize: Incomplete + extra_path: Incomplete install_path_file: int force: int skip_build: int warn_dir: int - build_base: Any - build_lib: Any - record: Any + build_base: Incomplete + build_lib: Incomplete + record: Incomplete def initialize_options(self) -> None: ... - config_vars: Any - install_libbase: Any + config_vars: Incomplete + install_libbase: Incomplete def finalize_options(self) -> None: ... def dump_dirs(self, msg) -> None: ... def finalize_unix(self) -> None: ... @@ -53,8 +54,8 @@ class install(Command): def expand_basedirs(self) -> None: ... def expand_dirs(self) -> None: ... def convert_paths(self, *names) -> None: ... - path_file: Any - extra_dirs: Any + path_file: Incomplete + extra_dirs: Incomplete def handle_extra_path(self) -> None: ... def change_roots(self, *names) -> None: ... def create_home_path(self) -> None: ... diff --git a/mypy/typeshed/stdlib/distutils/command/install_data.pyi b/mypy/typeshed/stdlib/distutils/command/install_data.pyi index 342c7a7ccca4..609de62b04b5 100644 --- a/mypy/typeshed/stdlib/distutils/command/install_data.pyi +++ b/mypy/typeshed/stdlib/distutils/command/install_data.pyi @@ -1,4 +1,5 @@ -from typing import Any, ClassVar +from _typeshed import Incomplete +from typing import ClassVar from ..cmd import Command @@ -6,11 +7,11 @@ class install_data(Command): description: str user_options: ClassVar[list[tuple[str, str | None, str]]] boolean_options: ClassVar[list[str]] - install_dir: Any - outfiles: Any - root: Any + install_dir: Incomplete + outfiles: Incomplete + root: Incomplete force: int - data_files: Any + data_files: Incomplete warn_dir: int def initialize_options(self) -> None: ... def finalize_options(self) -> None: ... diff --git a/mypy/typeshed/stdlib/distutils/command/install_egg_info.pyi b/mypy/typeshed/stdlib/distutils/command/install_egg_info.pyi index 3fd54989d14f..75bb906ce582 100644 --- a/mypy/typeshed/stdlib/distutils/command/install_egg_info.pyi +++ b/mypy/typeshed/stdlib/distutils/command/install_egg_info.pyi @@ -1,14 +1,15 @@ -from typing import Any, ClassVar +from _typeshed import Incomplete +from typing import ClassVar from ..cmd import Command class install_egg_info(Command): description: ClassVar[str] user_options: ClassVar[list[tuple[str, str, str]]] - install_dir: Any + install_dir: Incomplete def initialize_options(self) -> None: ... - target: Any - outputs: Any + target: Incomplete + outputs: Incomplete def finalize_options(self) -> None: ... def run(self) -> None: ... def get_outputs(self) -> list[str]: ... diff --git a/mypy/typeshed/stdlib/distutils/command/install_headers.pyi b/mypy/typeshed/stdlib/distutils/command/install_headers.pyi index 7854d2393a98..3caad8a07dca 100644 --- a/mypy/typeshed/stdlib/distutils/command/install_headers.pyi +++ b/mypy/typeshed/stdlib/distutils/command/install_headers.pyi @@ -1,4 +1,5 @@ -from typing import Any, ClassVar +from _typeshed import Incomplete +from typing import ClassVar from ..cmd import Command @@ -6,9 +7,9 @@ class install_headers(Command): description: str user_options: ClassVar[list[tuple[str, str, str]]] boolean_options: ClassVar[list[str]] - install_dir: Any + install_dir: Incomplete force: int - outfiles: Any + outfiles: Incomplete def initialize_options(self) -> None: ... def finalize_options(self) -> None: ... def run(self) -> None: ... diff --git a/mypy/typeshed/stdlib/distutils/command/install_lib.pyi b/mypy/typeshed/stdlib/distutils/command/install_lib.pyi index 149ecae89781..a537e254904a 100644 --- a/mypy/typeshed/stdlib/distutils/command/install_lib.pyi +++ b/mypy/typeshed/stdlib/distutils/command/install_lib.pyi @@ -1,4 +1,5 @@ -from typing import Any, ClassVar, Final +from _typeshed import Incomplete +from typing import ClassVar, Final from ..cmd import Command @@ -9,12 +10,12 @@ class install_lib(Command): user_options: ClassVar[list[tuple[str, str | None, str]]] boolean_options: ClassVar[list[str]] negative_opt: ClassVar[dict[str, str]] - install_dir: Any - build_dir: Any + install_dir: Incomplete + build_dir: Incomplete force: int - compile: Any - optimize: Any - skip_build: Any + compile: Incomplete + optimize: Incomplete + skip_build: Incomplete def initialize_options(self) -> None: ... def finalize_options(self) -> None: ... def run(self) -> None: ... diff --git a/mypy/typeshed/stdlib/distutils/command/install_scripts.pyi b/mypy/typeshed/stdlib/distutils/command/install_scripts.pyi index 5ee5589ad33d..658594f32e43 100644 --- a/mypy/typeshed/stdlib/distutils/command/install_scripts.pyi +++ b/mypy/typeshed/stdlib/distutils/command/install_scripts.pyi @@ -1,4 +1,5 @@ -from typing import Any, ClassVar +from _typeshed import Incomplete +from typing import ClassVar from ..cmd import Command @@ -6,13 +7,13 @@ class install_scripts(Command): description: str user_options: ClassVar[list[tuple[str, str | None, str]]] boolean_options: ClassVar[list[str]] - install_dir: Any + install_dir: Incomplete force: int - build_dir: Any - skip_build: Any + build_dir: Incomplete + skip_build: Incomplete def initialize_options(self) -> None: ... def finalize_options(self) -> None: ... - outfiles: Any + outfiles: Incomplete def run(self) -> None: ... def get_inputs(self): ... def get_outputs(self): ... diff --git a/mypy/typeshed/stdlib/distutils/command/register.pyi b/mypy/typeshed/stdlib/distutils/command/register.pyi index a5e251d2d01e..cf98e178a9ba 100644 --- a/mypy/typeshed/stdlib/distutils/command/register.pyi +++ b/mypy/typeshed/stdlib/distutils/command/register.pyi @@ -1,3 +1,4 @@ +from _typeshed import Incomplete from collections.abc import Callable from typing import Any, ClassVar @@ -17,4 +18,4 @@ class register(PyPIRCCommand): def verify_metadata(self) -> None: ... def send_metadata(self) -> None: ... def build_post_data(self, action): ... - def post_to_server(self, data, auth: Any | None = None): ... + def post_to_server(self, data, auth: Incomplete | None = None): ... diff --git a/mypy/typeshed/stdlib/distutils/command/sdist.pyi b/mypy/typeshed/stdlib/distutils/command/sdist.pyi index 5b7fe2419551..48a140714dda 100644 --- a/mypy/typeshed/stdlib/distutils/command/sdist.pyi +++ b/mypy/typeshed/stdlib/distutils/command/sdist.pyi @@ -1,4 +1,4 @@ -from _typeshed import Unused +from _typeshed import Incomplete, Unused from collections.abc import Callable from typing import Any, ClassVar @@ -16,22 +16,22 @@ class sdist(Command): # Any to work around variance issues sub_commands: ClassVar[list[tuple[str, Callable[[Any], bool] | None]]] READMES: ClassVar[tuple[str, ...]] - template: Any - manifest: Any + template: Incomplete + manifest: Incomplete use_defaults: int prune: int manifest_only: int force_manifest: int - formats: Any + formats: Incomplete keep_temp: int - dist_dir: Any - archive_files: Any + dist_dir: Incomplete + archive_files: Incomplete metadata_check: int - owner: Any - group: Any + owner: Incomplete + group: Incomplete def initialize_options(self) -> None: ... def finalize_options(self) -> None: ... - filelist: Any + filelist: Incomplete def run(self) -> None: ... def check_metadata(self) -> None: ... def get_file_list(self) -> None: ... diff --git a/mypy/typeshed/stdlib/distutils/command/upload.pyi b/mypy/typeshed/stdlib/distutils/command/upload.pyi index e6b77825c5f5..afcfbaf48677 100644 --- a/mypy/typeshed/stdlib/distutils/command/upload.pyi +++ b/mypy/typeshed/stdlib/distutils/command/upload.pyi @@ -1,4 +1,5 @@ -from typing import Any, ClassVar +from _typeshed import Incomplete +from typing import ClassVar from ..config import PyPIRCCommand @@ -8,10 +9,10 @@ class upload(PyPIRCCommand): password: str show_response: int sign: bool - identity: Any + identity: Incomplete def initialize_options(self) -> None: ... - repository: Any - realm: Any + repository: Incomplete + realm: Incomplete def finalize_options(self) -> None: ... def run(self) -> None: ... def upload_file(self, command: str, pyversion: str, filename: str) -> None: ... diff --git a/mypy/typeshed/stdlib/distutils/core.pyi b/mypy/typeshed/stdlib/distutils/core.pyi index a4d21f8ddd7b..174f24991351 100644 --- a/mypy/typeshed/stdlib/distutils/core.pyi +++ b/mypy/typeshed/stdlib/distutils/core.pyi @@ -1,4 +1,4 @@ -from _typeshed import StrOrBytesPath +from _typeshed import Incomplete, StrOrBytesPath from collections.abc import Mapping from distutils.cmd import Command as Command from distutils.dist import Distribution as Distribution @@ -32,7 +32,7 @@ def setup( distclass: type[Distribution] = ..., script_name: str = ..., script_args: list[str] = ..., - options: Mapping[str, Any] = ..., + options: Mapping[str, Incomplete] = ..., license: str = ..., keywords: list[str] | str = ..., platforms: list[str] | str = ..., @@ -43,7 +43,7 @@ def setup( provides: list[str] = ..., requires: list[str] = ..., command_packages: list[str] = ..., - command_options: Mapping[str, Mapping[str, tuple[Any, Any]]] = ..., + command_options: Mapping[str, Mapping[str, tuple[Incomplete, Incomplete]]] = ..., package_data: Mapping[str, list[str]] = ..., include_package_data: bool | Literal[0, 1] = ..., libraries: list[str] = ..., @@ -52,6 +52,7 @@ def setup( include_dirs: list[str] = ..., password: str = ..., fullname: str = ..., + # Custom Distributions could accept more params **attrs: Any, ) -> Distribution: ... def run_setup(script_name: str, script_args: list[str] | None = None, stop_after: str = "run") -> Distribution: ... diff --git a/mypy/typeshed/stdlib/distutils/log.pyi b/mypy/typeshed/stdlib/distutils/log.pyi index 0ea135c28371..7246dd6be0cd 100644 --- a/mypy/typeshed/stdlib/distutils/log.pyi +++ b/mypy/typeshed/stdlib/distutils/log.pyi @@ -8,6 +8,7 @@ FATAL: Final = 5 class Log: def __init__(self, threshold: int = 3) -> None: ... + # Arbitrary msg args' type depends on the format method def log(self, level: int, msg: str, *args: Any) -> None: ... def debug(self, msg: str, *args: Any) -> None: ... def info(self, msg: str, *args: Any) -> None: ... diff --git a/mypy/typeshed/stdlib/distutils/spawn.pyi b/mypy/typeshed/stdlib/distutils/spawn.pyi index 50d89aeb9e5f..ae07a49504fe 100644 --- a/mypy/typeshed/stdlib/distutils/spawn.pyi +++ b/mypy/typeshed/stdlib/distutils/spawn.pyi @@ -1,6 +1,10 @@ +from collections.abc import Iterable from typing import Literal def spawn( - cmd: list[str], search_path: bool | Literal[0, 1] = 1, verbose: bool | Literal[0, 1] = 0, dry_run: bool | Literal[0, 1] = 0 + cmd: Iterable[str], + search_path: bool | Literal[0, 1] = 1, + verbose: bool | Literal[0, 1] = 0, + dry_run: bool | Literal[0, 1] = 0, ) -> None: ... def find_executable(executable: str, path: str | None = None) -> str | None: ... diff --git a/mypy/typeshed/stdlib/doctest.pyi b/mypy/typeshed/stdlib/doctest.pyi index 4380083027a6..562b5a5bdac9 100644 --- a/mypy/typeshed/stdlib/doctest.pyi +++ b/mypy/typeshed/stdlib/doctest.pyi @@ -3,7 +3,7 @@ import types import unittest from _typeshed import ExcInfo from collections.abc import Callable -from typing import Any, ClassVar, NamedTuple +from typing import Any, NamedTuple, type_check_only from typing_extensions import Self, TypeAlias __all__ = [ @@ -42,17 +42,15 @@ __all__ = [ "debug", ] -# MyPy errors on conditionals within named tuples. - if sys.version_info >= (3, 13): - class TestResults(NamedTuple): - def __new__(cls, failed: int, attempted: int, *, skipped: int = 0) -> Self: ... # type: ignore[misc] - skipped: int + @type_check_only + class _TestResultsBase(NamedTuple): failed: int attempted: int - _fields: ClassVar = ("failed", "attempted") # type: ignore[misc] - __match_args__ = ("failed", "attempted") # type: ignore[misc] - __doc__: None # type: ignore[misc] + + class TestResults(_TestResultsBase): + def __new__(cls, failed: int, attempted: int, *, skipped: int = 0) -> Self: ... + skipped: int else: class TestResults(NamedTuple): diff --git a/mypy/typeshed/stdlib/email/__init__.pyi b/mypy/typeshed/stdlib/email/__init__.pyi index fca302f5f1a7..f564ced105bd 100644 --- a/mypy/typeshed/stdlib/email/__init__.pyi +++ b/mypy/typeshed/stdlib/email/__init__.pyi @@ -4,6 +4,29 @@ from email.policy import Policy from typing import IO from typing_extensions import TypeAlias +# At runtime, listing submodules in __all__ without them being imported is +# valid, and causes them to be included in a star import. See #6523 + +__all__ = [ # noqa: F822 # Undefined names in __all__ + "base64mime", # pyright: ignore[reportUnsupportedDunderAll] + "charset", # pyright: ignore[reportUnsupportedDunderAll] + "encoders", # pyright: ignore[reportUnsupportedDunderAll] + "errors", # pyright: ignore[reportUnsupportedDunderAll] + "feedparser", # pyright: ignore[reportUnsupportedDunderAll] + "generator", # pyright: ignore[reportUnsupportedDunderAll] + "header", # pyright: ignore[reportUnsupportedDunderAll] + "iterators", # pyright: ignore[reportUnsupportedDunderAll] + "message", # pyright: ignore[reportUnsupportedDunderAll] + "message_from_file", + "message_from_binary_file", + "message_from_string", + "message_from_bytes", + "mime", # pyright: ignore[reportUnsupportedDunderAll] + "parser", # pyright: ignore[reportUnsupportedDunderAll] + "quoprimime", # pyright: ignore[reportUnsupportedDunderAll] + "utils", # pyright: ignore[reportUnsupportedDunderAll] +] + # Definitions imported by multiple submodules in typeshed _ParamType: TypeAlias = str | tuple[str | None, str | None, str] # noqa: Y047 _ParamsType: TypeAlias = str | None | tuple[str, str | None, str] # noqa: Y047 @@ -12,18 +35,3 @@ def message_from_string(s: str, _class: Callable[[], Message] = ..., *, policy: def message_from_bytes(s: bytes | bytearray, _class: Callable[[], Message] = ..., *, policy: Policy = ...) -> Message: ... def message_from_file(fp: IO[str], _class: Callable[[], Message] = ..., *, policy: Policy = ...) -> Message: ... def message_from_binary_file(fp: IO[bytes], _class: Callable[[], Message] = ..., *, policy: Policy = ...) -> Message: ... - -# Names in __all__ with no definition: -# base64mime -# charset -# encoders -# errors -# feedparser -# generator -# header -# iterators -# message -# mime -# parser -# quoprimime -# utils diff --git a/mypy/typeshed/stdlib/email/_policybase.pyi b/mypy/typeshed/stdlib/email/_policybase.pyi index 9e1f653c9d78..f5dbbd96da14 100644 --- a/mypy/typeshed/stdlib/email/_policybase.pyi +++ b/mypy/typeshed/stdlib/email/_policybase.pyi @@ -1,11 +1,31 @@ from abc import ABCMeta, abstractmethod -from collections.abc import Callable from email.errors import MessageDefect from email.header import Header from email.message import Message +from typing import Generic, Protocol, TypeVar, type_check_only from typing_extensions import Self -class _PolicyBase: +__all__ = ["Policy", "Compat32", "compat32"] + +_MessageT = TypeVar("_MessageT", bound=Message, default=Message) + +@type_check_only +class _MessageFactory(Protocol[_MessageT]): + def __call__(self, policy: Policy[_MessageT]) -> _MessageT: ... + +# Policy below is the only known direct subclass of _PolicyBase. We therefore +# assume that the __init__ arguments and attributes of _PolicyBase are +# the same as those of Policy. +class _PolicyBase(Generic[_MessageT]): + max_line_length: int | None + linesep: str + cte_type: str + raise_on_defect: bool + mangle_from_: bool + message_factory: _MessageFactory[_MessageT] | None + # Added in Python 3.8.20, 3.9.20, 3.10.15, 3.11.10, 3.12.5 + verify_generated_headers: bool + def __init__( self, *, @@ -14,7 +34,7 @@ class _PolicyBase: cte_type: str = "8bit", raise_on_defect: bool = False, mangle_from_: bool = ..., # default depends on sub-class - message_factory: Callable[[Policy], Message] | None = None, + message_factory: _MessageFactory[_MessageT] | None = None, # Added in Python 3.8.20, 3.9.20, 3.10.15, 3.11.10, 3.12.5 verify_generated_headers: bool = True, ) -> None: ... @@ -26,24 +46,15 @@ class _PolicyBase: cte_type: str = ..., raise_on_defect: bool = ..., mangle_from_: bool = ..., - message_factory: Callable[[Policy], Message] | None = ..., + message_factory: _MessageFactory[_MessageT] | None = ..., # Added in Python 3.8.20, 3.9.20, 3.10.15, 3.11.10, 3.12.5 verify_generated_headers: bool = ..., ) -> Self: ... def __add__(self, other: Policy) -> Self: ... -class Policy(_PolicyBase, metaclass=ABCMeta): - max_line_length: int | None - linesep: str - cte_type: str - raise_on_defect: bool - mangle_from_: bool - message_factory: Callable[[Policy], Message] | None - # Added in Python 3.8.20, 3.9.20, 3.10.15, 3.11.10, 3.12.5 - verify_generated_headers: bool - - def handle_defect(self, obj: Message, defect: MessageDefect) -> None: ... - def register_defect(self, obj: Message, defect: MessageDefect) -> None: ... +class Policy(_PolicyBase[_MessageT], metaclass=ABCMeta): + def handle_defect(self, obj: _MessageT, defect: MessageDefect) -> None: ... + def register_defect(self, obj: _MessageT, defect: MessageDefect) -> None: ... def header_max_count(self, name: str) -> int | None: ... @abstractmethod def header_source_parse(self, sourcelines: list[str]) -> tuple[str, str]: ... @@ -56,11 +67,11 @@ class Policy(_PolicyBase, metaclass=ABCMeta): @abstractmethod def fold_binary(self, name: str, value: str) -> bytes: ... -class Compat32(Policy): +class Compat32(Policy[_MessageT]): def header_source_parse(self, sourcelines: list[str]) -> tuple[str, str]: ... def header_store_parse(self, name: str, value: str) -> tuple[str, str]: ... def header_fetch_parse(self, name: str, value: str) -> str | Header: ... # type: ignore[override] def fold(self, name: str, value: str) -> str: ... def fold_binary(self, name: str, value: str) -> bytes: ... -compat32: Compat32 +compat32: Compat32[Message] diff --git a/mypy/typeshed/stdlib/email/feedparser.pyi b/mypy/typeshed/stdlib/email/feedparser.pyi index 22920fc99c69..8c268ca1ae18 100644 --- a/mypy/typeshed/stdlib/email/feedparser.pyi +++ b/mypy/typeshed/stdlib/email/feedparser.pyi @@ -5,19 +5,19 @@ from typing import Generic, TypeVar, overload __all__ = ["FeedParser", "BytesFeedParser"] -_MessageT = TypeVar("_MessageT", bound=Message) +_MessageT = TypeVar("_MessageT", bound=Message, default=Message) class FeedParser(Generic[_MessageT]): @overload - def __init__(self: FeedParser[Message], _factory: None = None, *, policy: Policy = ...) -> None: ... + def __init__(self: FeedParser[Message], _factory: None = None, *, policy: Policy[Message] = ...) -> None: ... @overload - def __init__(self, _factory: Callable[[], _MessageT], *, policy: Policy = ...) -> None: ... + def __init__(self, _factory: Callable[[], _MessageT], *, policy: Policy[_MessageT] = ...) -> None: ... def feed(self, data: str) -> None: ... def close(self) -> _MessageT: ... class BytesFeedParser(FeedParser[_MessageT]): @overload - def __init__(self: BytesFeedParser[Message], _factory: None = None, *, policy: Policy = ...) -> None: ... + def __init__(self: BytesFeedParser[Message], _factory: None = None, *, policy: Policy[Message] = ...) -> None: ... @overload - def __init__(self, _factory: Callable[[], _MessageT], *, policy: Policy = ...) -> None: ... + def __init__(self, _factory: Callable[[], _MessageT], *, policy: Policy[_MessageT] = ...) -> None: ... def feed(self, data: bytes | bytearray) -> None: ... # type: ignore[override] diff --git a/mypy/typeshed/stdlib/email/generator.pyi b/mypy/typeshed/stdlib/email/generator.pyi index faa6551fc925..dfa0604a20a9 100644 --- a/mypy/typeshed/stdlib/email/generator.pyi +++ b/mypy/typeshed/stdlib/email/generator.pyi @@ -1,34 +1,71 @@ from _typeshed import SupportsWrite from email.message import Message from email.policy import Policy +from typing import Any, Generic, TypeVar, overload from typing_extensions import Self __all__ = ["Generator", "DecodedGenerator", "BytesGenerator"] -class Generator: - def clone(self, fp: SupportsWrite[str]) -> Self: ... - def write(self, s: str) -> None: ... +# By default, generators do not have a message policy. +_MessageT = TypeVar("_MessageT", bound=Message, default=Any) + +class Generator(Generic[_MessageT]): + maxheaderlen: int | None + policy: Policy[_MessageT] | None + @overload + def __init__( + self: Generator[Any], # The Policy of the message is used. + outfp: SupportsWrite[str], + mangle_from_: bool | None = None, + maxheaderlen: int | None = None, + *, + policy: None = None, + ) -> None: ... + @overload def __init__( self, outfp: SupportsWrite[str], mangle_from_: bool | None = None, maxheaderlen: int | None = None, *, - policy: Policy | None = None, + policy: Policy[_MessageT], ) -> None: ... - def flatten(self, msg: Message, unixfrom: bool = False, linesep: str | None = None) -> None: ... + def write(self, s: str) -> None: ... + def flatten(self, msg: _MessageT, unixfrom: bool = False, linesep: str | None = None) -> None: ... + def clone(self, fp: SupportsWrite[str]) -> Self: ... -class BytesGenerator(Generator): +class BytesGenerator(Generator[_MessageT]): + @overload + def __init__( + self: BytesGenerator[Any], # The Policy of the message is used. + outfp: SupportsWrite[bytes], + mangle_from_: bool | None = None, + maxheaderlen: int | None = None, + *, + policy: None = None, + ) -> None: ... + @overload def __init__( self, outfp: SupportsWrite[bytes], mangle_from_: bool | None = None, maxheaderlen: int | None = None, *, - policy: Policy | None = None, + policy: Policy[_MessageT], ) -> None: ... -class DecodedGenerator(Generator): +class DecodedGenerator(Generator[_MessageT]): + @overload + def __init__( + self: DecodedGenerator[Any], # The Policy of the message is used. + outfp: SupportsWrite[str], + mangle_from_: bool | None = None, + maxheaderlen: int | None = None, + fmt: str | None = None, + *, + policy: None = None, + ) -> None: ... + @overload def __init__( self, outfp: SupportsWrite[str], @@ -36,5 +73,5 @@ class DecodedGenerator(Generator): maxheaderlen: int | None = None, fmt: str | None = None, *, - policy: Policy | None = None, + policy: Policy[_MessageT], ) -> None: ... diff --git a/mypy/typeshed/stdlib/email/message.pyi b/mypy/typeshed/stdlib/email/message.pyi index 7e80f13adb8f..ebad05a1cf7b 100644 --- a/mypy/typeshed/stdlib/email/message.pyi +++ b/mypy/typeshed/stdlib/email/message.pyi @@ -1,3 +1,4 @@ +from _typeshed import MaybeNone from collections.abc import Generator, Iterator, Sequence from email import _ParamsType, _ParamType from email.charset import Charset @@ -30,26 +31,29 @@ class _SupportsDecodeToPayload(Protocol): def decode(self, encoding: str, errors: str, /) -> _PayloadType | _MultipartPayloadType: ... class Message(Generic[_HeaderT, _HeaderParamT]): - policy: Policy # undocumented + # The policy attributes and arguments in this class and its subclasses + # would ideally use Policy[Self], but this is not possible. + policy: Policy[Any] # undocumented preamble: str | None epilogue: str | None defects: list[MessageDefect] + def __init__(self, policy: Policy[Any] = ...) -> None: ... def is_multipart(self) -> bool: ... def set_unixfrom(self, unixfrom: str) -> None: ... def get_unixfrom(self) -> str | None: ... def attach(self, payload: _PayloadType) -> None: ... # `i: int` without a multipart payload results in an error - # `| Any`: can be None for cleared or unset payload, but annoying to check + # `| MaybeNone` acts like `| Any`: can be None for cleared or unset payload, but annoying to check @overload # multipart def get_payload(self, i: int, decode: Literal[True]) -> None: ... @overload # multipart - def get_payload(self, i: int, decode: Literal[False] = False) -> _PayloadType | Any: ... + def get_payload(self, i: int, decode: Literal[False] = False) -> _PayloadType | MaybeNone: ... @overload # either - def get_payload(self, i: None = None, decode: Literal[False] = False) -> _PayloadType | _MultipartPayloadType | Any: ... + def get_payload(self, i: None = None, decode: Literal[False] = False) -> _PayloadType | _MultipartPayloadType | MaybeNone: ... @overload # not multipart - def get_payload(self, i: None = None, *, decode: Literal[True]) -> _EncodedPayloadType | Any: ... + def get_payload(self, i: None = None, *, decode: Literal[True]) -> _EncodedPayloadType | MaybeNone: ... @overload # not multipart, IDEM but w/o kwarg - def get_payload(self, i: None, decode: Literal[True]) -> _EncodedPayloadType | Any: ... + def get_payload(self, i: None, decode: Literal[True]) -> _EncodedPayloadType | MaybeNone: ... # If `charset=None` and payload supports both `encode` AND `decode`, # then an invalid payload could be passed, but this is unlikely # Not[_SupportsEncodeToPayload] @@ -72,7 +76,7 @@ class Message(Generic[_HeaderT, _HeaderParamT]): # This is important for protocols using __getitem__, like SupportsKeysAndGetItem # Morally, the return type should be `AnyOf[_HeaderType, None]`, # so using "the Any trick" instead. - def __getitem__(self, name: str) -> _HeaderT | Any: ... + def __getitem__(self, name: str) -> _HeaderT | MaybeNone: ... def __setitem__(self, name: str, val: _HeaderParamT) -> None: ... def __delitem__(self, name: str) -> None: ... def keys(self) -> list[str]: ... @@ -126,8 +130,8 @@ class Message(Generic[_HeaderT, _HeaderParamT]): def get_charsets(self, failobj: _T) -> list[str | _T]: ... def walk(self) -> Generator[Self, None, None]: ... def get_content_disposition(self) -> str | None: ... - def as_string(self, unixfrom: bool = False, maxheaderlen: int = 0, policy: Policy | None = None) -> str: ... - def as_bytes(self, unixfrom: bool = False, policy: Policy | None = None) -> bytes: ... + def as_string(self, unixfrom: bool = False, maxheaderlen: int = 0, policy: Policy[Any] | None = None) -> str: ... + def as_bytes(self, unixfrom: bool = False, policy: Policy[Any] | None = None) -> bytes: ... def __bytes__(self) -> bytes: ... def set_param( self, @@ -139,13 +143,12 @@ class Message(Generic[_HeaderT, _HeaderParamT]): language: str = "", replace: bool = False, ) -> None: ... - def __init__(self, policy: Policy = ...) -> None: ... # The following two methods are undocumented, but a source code comment states that they are public API def set_raw(self, name: str, value: _HeaderParamT) -> None: ... def raw_items(self) -> Iterator[tuple[str, _HeaderT]]: ... class MIMEPart(Message[_HeaderRegistryT, _HeaderRegistryParamT]): - def __init__(self, policy: Policy | None = None) -> None: ... + def __init__(self, policy: Policy[Any] | None = None) -> None: ... def get_body(self, preferencelist: Sequence[str] = ("related", "html", "plain")) -> MIMEPart[_HeaderRegistryT] | None: ... def attach(self, payload: Self) -> None: ... # type: ignore[override] # The attachments are created via type(self) in the attach method. It's theoretically @@ -163,7 +166,7 @@ class MIMEPart(Message[_HeaderRegistryT, _HeaderRegistryParamT]): def add_attachment(self, *args: Any, content_manager: ContentManager | None = ..., **kw: Any) -> None: ... def clear(self) -> None: ... def clear_content(self) -> None: ... - def as_string(self, unixfrom: bool = False, maxheaderlen: int | None = None, policy: Policy | None = None) -> str: ... + def as_string(self, unixfrom: bool = False, maxheaderlen: int | None = None, policy: Policy[Any] | None = None) -> str: ... def is_attachment(self) -> bool: ... class EmailMessage(MIMEPart): ... diff --git a/mypy/typeshed/stdlib/email/parser.pyi b/mypy/typeshed/stdlib/email/parser.pyi index fecb29d90b2e..a1a57b4eef4b 100644 --- a/mypy/typeshed/stdlib/email/parser.pyi +++ b/mypy/typeshed/stdlib/email/parser.pyi @@ -12,9 +12,9 @@ _MessageT = TypeVar("_MessageT", bound=Message, default=Message) class Parser(Generic[_MessageT]): @overload - def __init__(self: Parser[Message[str, str]], _class: None = None, *, policy: Policy = ...) -> None: ... + def __init__(self: Parser[Message[str, str]], _class: None = None, *, policy: Policy[Message[str, str]] = ...) -> None: ... @overload - def __init__(self, _class: Callable[[], _MessageT], *, policy: Policy = ...) -> None: ... + def __init__(self, _class: Callable[[], _MessageT], *, policy: Policy[_MessageT] = ...) -> None: ... def parse(self, fp: SupportsRead[str], headersonly: bool = False) -> _MessageT: ... def parsestr(self, text: str, headersonly: bool = False) -> _MessageT: ... @@ -25,9 +25,11 @@ class HeaderParser(Parser[_MessageT]): class BytesParser(Generic[_MessageT]): parser: Parser[_MessageT] @overload - def __init__(self: BytesParser[Message[str, str]], _class: None = None, *, policy: Policy = ...) -> None: ... + def __init__( + self: BytesParser[Message[str, str]], _class: None = None, *, policy: Policy[Message[str, str]] = ... + ) -> None: ... @overload - def __init__(self, _class: Callable[[], _MessageT], *, policy: Policy = ...) -> None: ... + def __init__(self, _class: Callable[[], _MessageT], *, policy: Policy[_MessageT] = ...) -> None: ... def parse(self, fp: _WrappedBuffer, headersonly: bool = False) -> _MessageT: ... def parsebytes(self, text: bytes | bytearray, headersonly: bool = False) -> _MessageT: ... diff --git a/mypy/typeshed/stdlib/email/policy.pyi b/mypy/typeshed/stdlib/email/policy.pyi index 5f1cf934eb3c..5b145bcf2318 100644 --- a/mypy/typeshed/stdlib/email/policy.pyi +++ b/mypy/typeshed/stdlib/email/policy.pyi @@ -1,16 +1,37 @@ from collections.abc import Callable -from email._policybase import Compat32 as Compat32, Policy as Policy, compat32 as compat32 +from email._policybase import Compat32 as Compat32, Policy as Policy, _MessageFactory, compat32 as compat32 from email.contentmanager import ContentManager -from email.message import Message -from typing import Any +from email.message import EmailMessage, Message +from typing import Any, TypeVar, overload +from typing_extensions import Self __all__ = ["Compat32", "compat32", "Policy", "EmailPolicy", "default", "strict", "SMTP", "HTTP"] -class EmailPolicy(Policy): +_MessageT = TypeVar("_MessageT", bound=Message, default=Message) + +class EmailPolicy(Policy[_MessageT]): utf8: bool refold_source: str header_factory: Callable[[str, Any], Any] content_manager: ContentManager + @overload + def __init__( + self: EmailPolicy[EmailMessage], + *, + max_line_length: int | None = ..., + linesep: str = ..., + cte_type: str = ..., + raise_on_defect: bool = ..., + mangle_from_: bool = ..., + message_factory: None = None, + # Added in Python 3.8.20, 3.9.20, 3.10.15, 3.11.10, 3.12.5 + verify_generated_headers: bool = ..., + utf8: bool = ..., + refold_source: str = ..., + header_factory: Callable[[str, str], str] = ..., + content_manager: ContentManager = ..., + ) -> None: ... + @overload def __init__( self, *, @@ -19,7 +40,9 @@ class EmailPolicy(Policy): cte_type: str = ..., raise_on_defect: bool = ..., mangle_from_: bool = ..., - message_factory: Callable[[Policy], Message] | None = ..., + message_factory: _MessageFactory[_MessageT] | None = ..., + # Added in Python 3.8.20, 3.9.20, 3.10.15, 3.11.10, 3.12.5 + verify_generated_headers: bool = ..., utf8: bool = ..., refold_source: str = ..., header_factory: Callable[[str, str], str] = ..., @@ -30,9 +53,25 @@ class EmailPolicy(Policy): def header_fetch_parse(self, name: str, value: str) -> Any: ... def fold(self, name: str, value: str) -> Any: ... def fold_binary(self, name: str, value: str) -> bytes: ... + def clone( + self, + *, + max_line_length: int | None = ..., + linesep: str = ..., + cte_type: str = ..., + raise_on_defect: bool = ..., + mangle_from_: bool = ..., + message_factory: _MessageFactory[_MessageT] | None = ..., + # Added in Python 3.8.20, 3.9.20, 3.10.15, 3.11.10, 3.12.5 + verify_generated_headers: bool = ..., + utf8: bool = ..., + refold_source: str = ..., + header_factory: Callable[[str, str], str] = ..., + content_manager: ContentManager = ..., + ) -> Self: ... -default: EmailPolicy -SMTP: EmailPolicy -SMTPUTF8: EmailPolicy -HTTP: EmailPolicy -strict: EmailPolicy +default: EmailPolicy[EmailMessage] +SMTP: EmailPolicy[EmailMessage] +SMTPUTF8: EmailPolicy[EmailMessage] +HTTP: EmailPolicy[EmailMessage] +strict: EmailPolicy[EmailMessage] diff --git a/mypy/typeshed/stdlib/encodings/aliases.pyi b/mypy/typeshed/stdlib/encodings/aliases.pyi new file mode 100644 index 000000000000..079af85d51ee --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/aliases.pyi @@ -0,0 +1 @@ +aliases: dict[str, str] diff --git a/mypy/typeshed/stdlib/encodings/ascii.pyi b/mypy/typeshed/stdlib/encodings/ascii.pyi new file mode 100644 index 000000000000..a85585af32ed --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/ascii.pyi @@ -0,0 +1,30 @@ +import codecs +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + # At runtime, this is codecs.ascii_encode + @staticmethod + def encode(str: str, errors: str | None = None, /) -> tuple[bytes, int]: ... + # At runtime, this is codecs.ascii_decode + @staticmethod + def decode(data: ReadableBuffer, errors: str | None = None, /) -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +# Note: encode being a decode function and decode being an encode function is accurate to runtime. +class StreamConverter(StreamWriter, StreamReader): # type: ignore[misc] # incompatible methods in base classes + # At runtime, this is codecs.ascii_decode + @staticmethod + def encode(data: ReadableBuffer, errors: str | None = None, /) -> tuple[str, int]: ... # type: ignore[override] + # At runtime, this is codecs.ascii_encode + @staticmethod + def decode(str: str, errors: str | None = None, /) -> tuple[bytes, int]: ... # type: ignore[override] + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/base64_codec.pyi b/mypy/typeshed/stdlib/encodings/base64_codec.pyi new file mode 100644 index 000000000000..0c4f1cb1fe59 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/base64_codec.pyi @@ -0,0 +1,26 @@ +import codecs +from _typeshed import ReadableBuffer +from typing import ClassVar + +# This codec is bytes to bytes. + +def base64_encode(input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ... +def base64_decode(input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ... + +class Codec(codecs.Codec): + def encode(self, input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ... # type: ignore[override] + def decode(self, input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ... # type: ignore[override] + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: ReadableBuffer, final: bool = False) -> bytes: ... # type: ignore[override] + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> bytes: ... # type: ignore[override] + +class StreamWriter(Codec, codecs.StreamWriter): + charbuffertype: ClassVar[type] = ... + +class StreamReader(Codec, codecs.StreamReader): + charbuffertype: ClassVar[type] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/big5.pyi b/mypy/typeshed/stdlib/encodings/big5.pyi new file mode 100644 index 000000000000..d613026a5a86 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/big5.pyi @@ -0,0 +1,23 @@ +import _multibytecodec as mbc +import codecs +from typing import ClassVar + +codec: mbc._MultibyteCodec + +class Codec(codecs.Codec): + encode = codec.encode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + decode = codec.decode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + +class IncrementalEncoder(mbc.MultibyteIncrementalEncoder, codecs.IncrementalEncoder): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class IncrementalDecoder(mbc.MultibyteIncrementalDecoder, codecs.IncrementalDecoder): + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamReader(Codec, mbc.MultibyteStreamReader, codecs.StreamReader): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamWriter(Codec, mbc.MultibyteStreamWriter, codecs.StreamWriter): + codec: ClassVar[mbc._MultibyteCodec] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/big5hkscs.pyi b/mypy/typeshed/stdlib/encodings/big5hkscs.pyi new file mode 100644 index 000000000000..d613026a5a86 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/big5hkscs.pyi @@ -0,0 +1,23 @@ +import _multibytecodec as mbc +import codecs +from typing import ClassVar + +codec: mbc._MultibyteCodec + +class Codec(codecs.Codec): + encode = codec.encode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + decode = codec.decode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + +class IncrementalEncoder(mbc.MultibyteIncrementalEncoder, codecs.IncrementalEncoder): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class IncrementalDecoder(mbc.MultibyteIncrementalDecoder, codecs.IncrementalDecoder): + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamReader(Codec, mbc.MultibyteStreamReader, codecs.StreamReader): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamWriter(Codec, mbc.MultibyteStreamWriter, codecs.StreamWriter): + codec: ClassVar[mbc._MultibyteCodec] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/bz2_codec.pyi b/mypy/typeshed/stdlib/encodings/bz2_codec.pyi new file mode 100644 index 000000000000..468346a93da9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/bz2_codec.pyi @@ -0,0 +1,26 @@ +import codecs +from _typeshed import ReadableBuffer +from typing import ClassVar + +# This codec is bytes to bytes. + +def bz2_encode(input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ... +def bz2_decode(input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ... + +class Codec(codecs.Codec): + def encode(self, input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ... # type: ignore[override] + def decode(self, input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ... # type: ignore[override] + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: ReadableBuffer, final: bool = False) -> bytes: ... # type: ignore[override] + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> bytes: ... # type: ignore[override] + +class StreamWriter(Codec, codecs.StreamWriter): + charbuffertype: ClassVar[type] = ... + +class StreamReader(Codec, codecs.StreamReader): + charbuffertype: ClassVar[type] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/charmap.pyi b/mypy/typeshed/stdlib/encodings/charmap.pyi new file mode 100644 index 000000000000..a971a15860b5 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/charmap.pyi @@ -0,0 +1,33 @@ +import codecs +from _codecs import _CharMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + # At runtime, this is codecs.charmap_encode + @staticmethod + def encode(str: str, errors: str | None = None, mapping: _CharMap | None = None, /) -> tuple[bytes, int]: ... + # At runtime, this is codecs.charmap_decode + @staticmethod + def decode(data: ReadableBuffer, errors: str | None = None, mapping: _CharMap | None = None, /) -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + mapping: _CharMap | None + def __init__(self, errors: str = "strict", mapping: _CharMap | None = None) -> None: ... + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + mapping: _CharMap | None + def __init__(self, errors: str = "strict", mapping: _CharMap | None = None) -> None: ... + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): + mapping: _CharMap | None + def __init__(self, stream: codecs._WritableStream, errors: str = "strict", mapping: _CharMap | None = None) -> None: ... + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... # type: ignore[override] + +class StreamReader(Codec, codecs.StreamReader): + mapping: _CharMap | None + def __init__(self, stream: codecs._ReadableStream, errors: str = "strict", mapping: _CharMap | None = None) -> None: ... + def decode(self, input: ReadableBuffer, errors: str = "strict") -> tuple[str, int]: ... # type: ignore[override] + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/cp037.pyi b/mypy/typeshed/stdlib/encodings/cp037.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp037.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/cp1006.pyi b/mypy/typeshed/stdlib/encodings/cp1006.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp1006.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/cp1026.pyi b/mypy/typeshed/stdlib/encodings/cp1026.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp1026.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/cp1125.pyi b/mypy/typeshed/stdlib/encodings/cp1125.pyi new file mode 100644 index 000000000000..42781b489298 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp1125.pyi @@ -0,0 +1,21 @@ +import codecs +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_map: dict[int, int | None] +decoding_table: str +encoding_map: dict[int, int] diff --git a/mypy/typeshed/stdlib/encodings/cp1140.pyi b/mypy/typeshed/stdlib/encodings/cp1140.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp1140.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/cp1250.pyi b/mypy/typeshed/stdlib/encodings/cp1250.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp1250.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/cp1251.pyi b/mypy/typeshed/stdlib/encodings/cp1251.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp1251.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/cp1252.pyi b/mypy/typeshed/stdlib/encodings/cp1252.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp1252.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/cp1253.pyi b/mypy/typeshed/stdlib/encodings/cp1253.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp1253.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/cp1254.pyi b/mypy/typeshed/stdlib/encodings/cp1254.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp1254.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/cp1255.pyi b/mypy/typeshed/stdlib/encodings/cp1255.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp1255.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/cp1256.pyi b/mypy/typeshed/stdlib/encodings/cp1256.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp1256.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/cp1257.pyi b/mypy/typeshed/stdlib/encodings/cp1257.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp1257.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/cp1258.pyi b/mypy/typeshed/stdlib/encodings/cp1258.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp1258.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/cp273.pyi b/mypy/typeshed/stdlib/encodings/cp273.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp273.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/cp424.pyi b/mypy/typeshed/stdlib/encodings/cp424.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp424.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/cp437.pyi b/mypy/typeshed/stdlib/encodings/cp437.pyi new file mode 100644 index 000000000000..42781b489298 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp437.pyi @@ -0,0 +1,21 @@ +import codecs +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_map: dict[int, int | None] +decoding_table: str +encoding_map: dict[int, int] diff --git a/mypy/typeshed/stdlib/encodings/cp500.pyi b/mypy/typeshed/stdlib/encodings/cp500.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp500.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/cp720.pyi b/mypy/typeshed/stdlib/encodings/cp720.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp720.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/cp737.pyi b/mypy/typeshed/stdlib/encodings/cp737.pyi new file mode 100644 index 000000000000..42781b489298 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp737.pyi @@ -0,0 +1,21 @@ +import codecs +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_map: dict[int, int | None] +decoding_table: str +encoding_map: dict[int, int] diff --git a/mypy/typeshed/stdlib/encodings/cp775.pyi b/mypy/typeshed/stdlib/encodings/cp775.pyi new file mode 100644 index 000000000000..42781b489298 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp775.pyi @@ -0,0 +1,21 @@ +import codecs +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_map: dict[int, int | None] +decoding_table: str +encoding_map: dict[int, int] diff --git a/mypy/typeshed/stdlib/encodings/cp850.pyi b/mypy/typeshed/stdlib/encodings/cp850.pyi new file mode 100644 index 000000000000..42781b489298 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp850.pyi @@ -0,0 +1,21 @@ +import codecs +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_map: dict[int, int | None] +decoding_table: str +encoding_map: dict[int, int] diff --git a/mypy/typeshed/stdlib/encodings/cp852.pyi b/mypy/typeshed/stdlib/encodings/cp852.pyi new file mode 100644 index 000000000000..42781b489298 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp852.pyi @@ -0,0 +1,21 @@ +import codecs +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_map: dict[int, int | None] +decoding_table: str +encoding_map: dict[int, int] diff --git a/mypy/typeshed/stdlib/encodings/cp855.pyi b/mypy/typeshed/stdlib/encodings/cp855.pyi new file mode 100644 index 000000000000..42781b489298 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp855.pyi @@ -0,0 +1,21 @@ +import codecs +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_map: dict[int, int | None] +decoding_table: str +encoding_map: dict[int, int] diff --git a/mypy/typeshed/stdlib/encodings/cp856.pyi b/mypy/typeshed/stdlib/encodings/cp856.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp856.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/cp857.pyi b/mypy/typeshed/stdlib/encodings/cp857.pyi new file mode 100644 index 000000000000..42781b489298 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp857.pyi @@ -0,0 +1,21 @@ +import codecs +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_map: dict[int, int | None] +decoding_table: str +encoding_map: dict[int, int] diff --git a/mypy/typeshed/stdlib/encodings/cp858.pyi b/mypy/typeshed/stdlib/encodings/cp858.pyi new file mode 100644 index 000000000000..42781b489298 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp858.pyi @@ -0,0 +1,21 @@ +import codecs +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_map: dict[int, int | None] +decoding_table: str +encoding_map: dict[int, int] diff --git a/mypy/typeshed/stdlib/encodings/cp860.pyi b/mypy/typeshed/stdlib/encodings/cp860.pyi new file mode 100644 index 000000000000..42781b489298 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp860.pyi @@ -0,0 +1,21 @@ +import codecs +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_map: dict[int, int | None] +decoding_table: str +encoding_map: dict[int, int] diff --git a/mypy/typeshed/stdlib/encodings/cp861.pyi b/mypy/typeshed/stdlib/encodings/cp861.pyi new file mode 100644 index 000000000000..42781b489298 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp861.pyi @@ -0,0 +1,21 @@ +import codecs +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_map: dict[int, int | None] +decoding_table: str +encoding_map: dict[int, int] diff --git a/mypy/typeshed/stdlib/encodings/cp862.pyi b/mypy/typeshed/stdlib/encodings/cp862.pyi new file mode 100644 index 000000000000..42781b489298 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp862.pyi @@ -0,0 +1,21 @@ +import codecs +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_map: dict[int, int | None] +decoding_table: str +encoding_map: dict[int, int] diff --git a/mypy/typeshed/stdlib/encodings/cp863.pyi b/mypy/typeshed/stdlib/encodings/cp863.pyi new file mode 100644 index 000000000000..42781b489298 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp863.pyi @@ -0,0 +1,21 @@ +import codecs +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_map: dict[int, int | None] +decoding_table: str +encoding_map: dict[int, int] diff --git a/mypy/typeshed/stdlib/encodings/cp864.pyi b/mypy/typeshed/stdlib/encodings/cp864.pyi new file mode 100644 index 000000000000..42781b489298 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp864.pyi @@ -0,0 +1,21 @@ +import codecs +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_map: dict[int, int | None] +decoding_table: str +encoding_map: dict[int, int] diff --git a/mypy/typeshed/stdlib/encodings/cp865.pyi b/mypy/typeshed/stdlib/encodings/cp865.pyi new file mode 100644 index 000000000000..42781b489298 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp865.pyi @@ -0,0 +1,21 @@ +import codecs +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_map: dict[int, int | None] +decoding_table: str +encoding_map: dict[int, int] diff --git a/mypy/typeshed/stdlib/encodings/cp866.pyi b/mypy/typeshed/stdlib/encodings/cp866.pyi new file mode 100644 index 000000000000..42781b489298 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp866.pyi @@ -0,0 +1,21 @@ +import codecs +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_map: dict[int, int | None] +decoding_table: str +encoding_map: dict[int, int] diff --git a/mypy/typeshed/stdlib/encodings/cp869.pyi b/mypy/typeshed/stdlib/encodings/cp869.pyi new file mode 100644 index 000000000000..42781b489298 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp869.pyi @@ -0,0 +1,21 @@ +import codecs +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_map: dict[int, int | None] +decoding_table: str +encoding_map: dict[int, int] diff --git a/mypy/typeshed/stdlib/encodings/cp874.pyi b/mypy/typeshed/stdlib/encodings/cp874.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp874.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/cp875.pyi b/mypy/typeshed/stdlib/encodings/cp875.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp875.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/cp932.pyi b/mypy/typeshed/stdlib/encodings/cp932.pyi new file mode 100644 index 000000000000..d613026a5a86 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp932.pyi @@ -0,0 +1,23 @@ +import _multibytecodec as mbc +import codecs +from typing import ClassVar + +codec: mbc._MultibyteCodec + +class Codec(codecs.Codec): + encode = codec.encode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + decode = codec.decode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + +class IncrementalEncoder(mbc.MultibyteIncrementalEncoder, codecs.IncrementalEncoder): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class IncrementalDecoder(mbc.MultibyteIncrementalDecoder, codecs.IncrementalDecoder): + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamReader(Codec, mbc.MultibyteStreamReader, codecs.StreamReader): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamWriter(Codec, mbc.MultibyteStreamWriter, codecs.StreamWriter): + codec: ClassVar[mbc._MultibyteCodec] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/cp949.pyi b/mypy/typeshed/stdlib/encodings/cp949.pyi new file mode 100644 index 000000000000..d613026a5a86 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp949.pyi @@ -0,0 +1,23 @@ +import _multibytecodec as mbc +import codecs +from typing import ClassVar + +codec: mbc._MultibyteCodec + +class Codec(codecs.Codec): + encode = codec.encode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + decode = codec.decode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + +class IncrementalEncoder(mbc.MultibyteIncrementalEncoder, codecs.IncrementalEncoder): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class IncrementalDecoder(mbc.MultibyteIncrementalDecoder, codecs.IncrementalDecoder): + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamReader(Codec, mbc.MultibyteStreamReader, codecs.StreamReader): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamWriter(Codec, mbc.MultibyteStreamWriter, codecs.StreamWriter): + codec: ClassVar[mbc._MultibyteCodec] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/cp950.pyi b/mypy/typeshed/stdlib/encodings/cp950.pyi new file mode 100644 index 000000000000..d613026a5a86 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/cp950.pyi @@ -0,0 +1,23 @@ +import _multibytecodec as mbc +import codecs +from typing import ClassVar + +codec: mbc._MultibyteCodec + +class Codec(codecs.Codec): + encode = codec.encode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + decode = codec.decode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + +class IncrementalEncoder(mbc.MultibyteIncrementalEncoder, codecs.IncrementalEncoder): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class IncrementalDecoder(mbc.MultibyteIncrementalDecoder, codecs.IncrementalDecoder): + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamReader(Codec, mbc.MultibyteStreamReader, codecs.StreamReader): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamWriter(Codec, mbc.MultibyteStreamWriter, codecs.StreamWriter): + codec: ClassVar[mbc._MultibyteCodec] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/euc_jis_2004.pyi b/mypy/typeshed/stdlib/encodings/euc_jis_2004.pyi new file mode 100644 index 000000000000..d613026a5a86 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/euc_jis_2004.pyi @@ -0,0 +1,23 @@ +import _multibytecodec as mbc +import codecs +from typing import ClassVar + +codec: mbc._MultibyteCodec + +class Codec(codecs.Codec): + encode = codec.encode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + decode = codec.decode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + +class IncrementalEncoder(mbc.MultibyteIncrementalEncoder, codecs.IncrementalEncoder): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class IncrementalDecoder(mbc.MultibyteIncrementalDecoder, codecs.IncrementalDecoder): + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamReader(Codec, mbc.MultibyteStreamReader, codecs.StreamReader): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamWriter(Codec, mbc.MultibyteStreamWriter, codecs.StreamWriter): + codec: ClassVar[mbc._MultibyteCodec] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/euc_jisx0213.pyi b/mypy/typeshed/stdlib/encodings/euc_jisx0213.pyi new file mode 100644 index 000000000000..d613026a5a86 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/euc_jisx0213.pyi @@ -0,0 +1,23 @@ +import _multibytecodec as mbc +import codecs +from typing import ClassVar + +codec: mbc._MultibyteCodec + +class Codec(codecs.Codec): + encode = codec.encode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + decode = codec.decode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + +class IncrementalEncoder(mbc.MultibyteIncrementalEncoder, codecs.IncrementalEncoder): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class IncrementalDecoder(mbc.MultibyteIncrementalDecoder, codecs.IncrementalDecoder): + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamReader(Codec, mbc.MultibyteStreamReader, codecs.StreamReader): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamWriter(Codec, mbc.MultibyteStreamWriter, codecs.StreamWriter): + codec: ClassVar[mbc._MultibyteCodec] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/euc_jp.pyi b/mypy/typeshed/stdlib/encodings/euc_jp.pyi new file mode 100644 index 000000000000..d613026a5a86 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/euc_jp.pyi @@ -0,0 +1,23 @@ +import _multibytecodec as mbc +import codecs +from typing import ClassVar + +codec: mbc._MultibyteCodec + +class Codec(codecs.Codec): + encode = codec.encode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + decode = codec.decode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + +class IncrementalEncoder(mbc.MultibyteIncrementalEncoder, codecs.IncrementalEncoder): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class IncrementalDecoder(mbc.MultibyteIncrementalDecoder, codecs.IncrementalDecoder): + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamReader(Codec, mbc.MultibyteStreamReader, codecs.StreamReader): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamWriter(Codec, mbc.MultibyteStreamWriter, codecs.StreamWriter): + codec: ClassVar[mbc._MultibyteCodec] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/euc_kr.pyi b/mypy/typeshed/stdlib/encodings/euc_kr.pyi new file mode 100644 index 000000000000..d613026a5a86 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/euc_kr.pyi @@ -0,0 +1,23 @@ +import _multibytecodec as mbc +import codecs +from typing import ClassVar + +codec: mbc._MultibyteCodec + +class Codec(codecs.Codec): + encode = codec.encode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + decode = codec.decode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + +class IncrementalEncoder(mbc.MultibyteIncrementalEncoder, codecs.IncrementalEncoder): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class IncrementalDecoder(mbc.MultibyteIncrementalDecoder, codecs.IncrementalDecoder): + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamReader(Codec, mbc.MultibyteStreamReader, codecs.StreamReader): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamWriter(Codec, mbc.MultibyteStreamWriter, codecs.StreamWriter): + codec: ClassVar[mbc._MultibyteCodec] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/gb18030.pyi b/mypy/typeshed/stdlib/encodings/gb18030.pyi new file mode 100644 index 000000000000..d613026a5a86 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/gb18030.pyi @@ -0,0 +1,23 @@ +import _multibytecodec as mbc +import codecs +from typing import ClassVar + +codec: mbc._MultibyteCodec + +class Codec(codecs.Codec): + encode = codec.encode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + decode = codec.decode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + +class IncrementalEncoder(mbc.MultibyteIncrementalEncoder, codecs.IncrementalEncoder): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class IncrementalDecoder(mbc.MultibyteIncrementalDecoder, codecs.IncrementalDecoder): + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamReader(Codec, mbc.MultibyteStreamReader, codecs.StreamReader): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamWriter(Codec, mbc.MultibyteStreamWriter, codecs.StreamWriter): + codec: ClassVar[mbc._MultibyteCodec] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/gb2312.pyi b/mypy/typeshed/stdlib/encodings/gb2312.pyi new file mode 100644 index 000000000000..d613026a5a86 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/gb2312.pyi @@ -0,0 +1,23 @@ +import _multibytecodec as mbc +import codecs +from typing import ClassVar + +codec: mbc._MultibyteCodec + +class Codec(codecs.Codec): + encode = codec.encode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + decode = codec.decode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + +class IncrementalEncoder(mbc.MultibyteIncrementalEncoder, codecs.IncrementalEncoder): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class IncrementalDecoder(mbc.MultibyteIncrementalDecoder, codecs.IncrementalDecoder): + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamReader(Codec, mbc.MultibyteStreamReader, codecs.StreamReader): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamWriter(Codec, mbc.MultibyteStreamWriter, codecs.StreamWriter): + codec: ClassVar[mbc._MultibyteCodec] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/gbk.pyi b/mypy/typeshed/stdlib/encodings/gbk.pyi new file mode 100644 index 000000000000..d613026a5a86 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/gbk.pyi @@ -0,0 +1,23 @@ +import _multibytecodec as mbc +import codecs +from typing import ClassVar + +codec: mbc._MultibyteCodec + +class Codec(codecs.Codec): + encode = codec.encode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + decode = codec.decode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + +class IncrementalEncoder(mbc.MultibyteIncrementalEncoder, codecs.IncrementalEncoder): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class IncrementalDecoder(mbc.MultibyteIncrementalDecoder, codecs.IncrementalDecoder): + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamReader(Codec, mbc.MultibyteStreamReader, codecs.StreamReader): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamWriter(Codec, mbc.MultibyteStreamWriter, codecs.StreamWriter): + codec: ClassVar[mbc._MultibyteCodec] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/hex_codec.pyi b/mypy/typeshed/stdlib/encodings/hex_codec.pyi new file mode 100644 index 000000000000..3fd4fe38898a --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/hex_codec.pyi @@ -0,0 +1,26 @@ +import codecs +from _typeshed import ReadableBuffer +from typing import ClassVar + +# This codec is bytes to bytes. + +def hex_encode(input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ... +def hex_decode(input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ... + +class Codec(codecs.Codec): + def encode(self, input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ... # type: ignore[override] + def decode(self, input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ... # type: ignore[override] + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: ReadableBuffer, final: bool = False) -> bytes: ... # type: ignore[override] + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> bytes: ... # type: ignore[override] + +class StreamWriter(Codec, codecs.StreamWriter): + charbuffertype: ClassVar[type] = ... + +class StreamReader(Codec, codecs.StreamReader): + charbuffertype: ClassVar[type] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/hp_roman8.pyi b/mypy/typeshed/stdlib/encodings/hp_roman8.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/hp_roman8.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/hz.pyi b/mypy/typeshed/stdlib/encodings/hz.pyi new file mode 100644 index 000000000000..d613026a5a86 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/hz.pyi @@ -0,0 +1,23 @@ +import _multibytecodec as mbc +import codecs +from typing import ClassVar + +codec: mbc._MultibyteCodec + +class Codec(codecs.Codec): + encode = codec.encode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + decode = codec.decode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + +class IncrementalEncoder(mbc.MultibyteIncrementalEncoder, codecs.IncrementalEncoder): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class IncrementalDecoder(mbc.MultibyteIncrementalDecoder, codecs.IncrementalDecoder): + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamReader(Codec, mbc.MultibyteStreamReader, codecs.StreamReader): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamWriter(Codec, mbc.MultibyteStreamWriter, codecs.StreamWriter): + codec: ClassVar[mbc._MultibyteCodec] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/idna.pyi b/mypy/typeshed/stdlib/encodings/idna.pyi new file mode 100644 index 000000000000..3e2c8baf1cb2 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/idna.pyi @@ -0,0 +1,26 @@ +import codecs +import re +from _typeshed import ReadableBuffer + +dots: re.Pattern[str] +ace_prefix: bytes +sace_prefix: str + +def nameprep(label: str) -> str: ... +def ToASCII(label: str) -> bytes: ... +def ToUnicode(label: bytes | str) -> str: ... + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: ReadableBuffer | str, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.BufferedIncrementalEncoder): + def _buffer_encode(self, input: str, errors: str, final: bool) -> tuple[bytes, int]: ... + +class IncrementalDecoder(codecs.BufferedIncrementalDecoder): + def _buffer_decode(self, input: ReadableBuffer | str, errors: str, final: bool) -> tuple[str, int]: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/iso2022_jp.pyi b/mypy/typeshed/stdlib/encodings/iso2022_jp.pyi new file mode 100644 index 000000000000..d613026a5a86 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/iso2022_jp.pyi @@ -0,0 +1,23 @@ +import _multibytecodec as mbc +import codecs +from typing import ClassVar + +codec: mbc._MultibyteCodec + +class Codec(codecs.Codec): + encode = codec.encode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + decode = codec.decode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + +class IncrementalEncoder(mbc.MultibyteIncrementalEncoder, codecs.IncrementalEncoder): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class IncrementalDecoder(mbc.MultibyteIncrementalDecoder, codecs.IncrementalDecoder): + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamReader(Codec, mbc.MultibyteStreamReader, codecs.StreamReader): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamWriter(Codec, mbc.MultibyteStreamWriter, codecs.StreamWriter): + codec: ClassVar[mbc._MultibyteCodec] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/iso2022_jp_1.pyi b/mypy/typeshed/stdlib/encodings/iso2022_jp_1.pyi new file mode 100644 index 000000000000..d613026a5a86 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/iso2022_jp_1.pyi @@ -0,0 +1,23 @@ +import _multibytecodec as mbc +import codecs +from typing import ClassVar + +codec: mbc._MultibyteCodec + +class Codec(codecs.Codec): + encode = codec.encode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + decode = codec.decode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + +class IncrementalEncoder(mbc.MultibyteIncrementalEncoder, codecs.IncrementalEncoder): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class IncrementalDecoder(mbc.MultibyteIncrementalDecoder, codecs.IncrementalDecoder): + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamReader(Codec, mbc.MultibyteStreamReader, codecs.StreamReader): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamWriter(Codec, mbc.MultibyteStreamWriter, codecs.StreamWriter): + codec: ClassVar[mbc._MultibyteCodec] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/iso2022_jp_2.pyi b/mypy/typeshed/stdlib/encodings/iso2022_jp_2.pyi new file mode 100644 index 000000000000..d613026a5a86 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/iso2022_jp_2.pyi @@ -0,0 +1,23 @@ +import _multibytecodec as mbc +import codecs +from typing import ClassVar + +codec: mbc._MultibyteCodec + +class Codec(codecs.Codec): + encode = codec.encode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + decode = codec.decode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + +class IncrementalEncoder(mbc.MultibyteIncrementalEncoder, codecs.IncrementalEncoder): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class IncrementalDecoder(mbc.MultibyteIncrementalDecoder, codecs.IncrementalDecoder): + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamReader(Codec, mbc.MultibyteStreamReader, codecs.StreamReader): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamWriter(Codec, mbc.MultibyteStreamWriter, codecs.StreamWriter): + codec: ClassVar[mbc._MultibyteCodec] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/iso2022_jp_2004.pyi b/mypy/typeshed/stdlib/encodings/iso2022_jp_2004.pyi new file mode 100644 index 000000000000..d613026a5a86 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/iso2022_jp_2004.pyi @@ -0,0 +1,23 @@ +import _multibytecodec as mbc +import codecs +from typing import ClassVar + +codec: mbc._MultibyteCodec + +class Codec(codecs.Codec): + encode = codec.encode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + decode = codec.decode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + +class IncrementalEncoder(mbc.MultibyteIncrementalEncoder, codecs.IncrementalEncoder): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class IncrementalDecoder(mbc.MultibyteIncrementalDecoder, codecs.IncrementalDecoder): + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamReader(Codec, mbc.MultibyteStreamReader, codecs.StreamReader): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamWriter(Codec, mbc.MultibyteStreamWriter, codecs.StreamWriter): + codec: ClassVar[mbc._MultibyteCodec] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/iso2022_jp_3.pyi b/mypy/typeshed/stdlib/encodings/iso2022_jp_3.pyi new file mode 100644 index 000000000000..d613026a5a86 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/iso2022_jp_3.pyi @@ -0,0 +1,23 @@ +import _multibytecodec as mbc +import codecs +from typing import ClassVar + +codec: mbc._MultibyteCodec + +class Codec(codecs.Codec): + encode = codec.encode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + decode = codec.decode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + +class IncrementalEncoder(mbc.MultibyteIncrementalEncoder, codecs.IncrementalEncoder): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class IncrementalDecoder(mbc.MultibyteIncrementalDecoder, codecs.IncrementalDecoder): + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamReader(Codec, mbc.MultibyteStreamReader, codecs.StreamReader): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamWriter(Codec, mbc.MultibyteStreamWriter, codecs.StreamWriter): + codec: ClassVar[mbc._MultibyteCodec] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/iso2022_jp_ext.pyi b/mypy/typeshed/stdlib/encodings/iso2022_jp_ext.pyi new file mode 100644 index 000000000000..d613026a5a86 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/iso2022_jp_ext.pyi @@ -0,0 +1,23 @@ +import _multibytecodec as mbc +import codecs +from typing import ClassVar + +codec: mbc._MultibyteCodec + +class Codec(codecs.Codec): + encode = codec.encode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + decode = codec.decode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + +class IncrementalEncoder(mbc.MultibyteIncrementalEncoder, codecs.IncrementalEncoder): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class IncrementalDecoder(mbc.MultibyteIncrementalDecoder, codecs.IncrementalDecoder): + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamReader(Codec, mbc.MultibyteStreamReader, codecs.StreamReader): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamWriter(Codec, mbc.MultibyteStreamWriter, codecs.StreamWriter): + codec: ClassVar[mbc._MultibyteCodec] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/iso2022_kr.pyi b/mypy/typeshed/stdlib/encodings/iso2022_kr.pyi new file mode 100644 index 000000000000..d613026a5a86 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/iso2022_kr.pyi @@ -0,0 +1,23 @@ +import _multibytecodec as mbc +import codecs +from typing import ClassVar + +codec: mbc._MultibyteCodec + +class Codec(codecs.Codec): + encode = codec.encode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + decode = codec.decode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + +class IncrementalEncoder(mbc.MultibyteIncrementalEncoder, codecs.IncrementalEncoder): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class IncrementalDecoder(mbc.MultibyteIncrementalDecoder, codecs.IncrementalDecoder): + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamReader(Codec, mbc.MultibyteStreamReader, codecs.StreamReader): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamWriter(Codec, mbc.MultibyteStreamWriter, codecs.StreamWriter): + codec: ClassVar[mbc._MultibyteCodec] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/iso8859_1.pyi b/mypy/typeshed/stdlib/encodings/iso8859_1.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/iso8859_1.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/iso8859_10.pyi b/mypy/typeshed/stdlib/encodings/iso8859_10.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/iso8859_10.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/iso8859_11.pyi b/mypy/typeshed/stdlib/encodings/iso8859_11.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/iso8859_11.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/iso8859_13.pyi b/mypy/typeshed/stdlib/encodings/iso8859_13.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/iso8859_13.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/iso8859_14.pyi b/mypy/typeshed/stdlib/encodings/iso8859_14.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/iso8859_14.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/iso8859_15.pyi b/mypy/typeshed/stdlib/encodings/iso8859_15.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/iso8859_15.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/iso8859_16.pyi b/mypy/typeshed/stdlib/encodings/iso8859_16.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/iso8859_16.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/iso8859_2.pyi b/mypy/typeshed/stdlib/encodings/iso8859_2.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/iso8859_2.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/iso8859_3.pyi b/mypy/typeshed/stdlib/encodings/iso8859_3.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/iso8859_3.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/iso8859_4.pyi b/mypy/typeshed/stdlib/encodings/iso8859_4.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/iso8859_4.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/iso8859_5.pyi b/mypy/typeshed/stdlib/encodings/iso8859_5.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/iso8859_5.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/iso8859_6.pyi b/mypy/typeshed/stdlib/encodings/iso8859_6.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/iso8859_6.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/iso8859_7.pyi b/mypy/typeshed/stdlib/encodings/iso8859_7.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/iso8859_7.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/iso8859_8.pyi b/mypy/typeshed/stdlib/encodings/iso8859_8.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/iso8859_8.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/iso8859_9.pyi b/mypy/typeshed/stdlib/encodings/iso8859_9.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/iso8859_9.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/johab.pyi b/mypy/typeshed/stdlib/encodings/johab.pyi new file mode 100644 index 000000000000..d613026a5a86 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/johab.pyi @@ -0,0 +1,23 @@ +import _multibytecodec as mbc +import codecs +from typing import ClassVar + +codec: mbc._MultibyteCodec + +class Codec(codecs.Codec): + encode = codec.encode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + decode = codec.decode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + +class IncrementalEncoder(mbc.MultibyteIncrementalEncoder, codecs.IncrementalEncoder): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class IncrementalDecoder(mbc.MultibyteIncrementalDecoder, codecs.IncrementalDecoder): + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamReader(Codec, mbc.MultibyteStreamReader, codecs.StreamReader): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamWriter(Codec, mbc.MultibyteStreamWriter, codecs.StreamWriter): + codec: ClassVar[mbc._MultibyteCodec] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/koi8_r.pyi b/mypy/typeshed/stdlib/encodings/koi8_r.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/koi8_r.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/koi8_t.pyi b/mypy/typeshed/stdlib/encodings/koi8_t.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/koi8_t.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/koi8_u.pyi b/mypy/typeshed/stdlib/encodings/koi8_u.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/koi8_u.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/kz1048.pyi b/mypy/typeshed/stdlib/encodings/kz1048.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/kz1048.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/latin_1.pyi b/mypy/typeshed/stdlib/encodings/latin_1.pyi new file mode 100644 index 000000000000..3b06773eac03 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/latin_1.pyi @@ -0,0 +1,30 @@ +import codecs +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + # At runtime, this is codecs.latin_1_encode + @staticmethod + def encode(str: str, errors: str | None = None, /) -> tuple[bytes, int]: ... + # At runtime, this is codecs.latin_1_decode + @staticmethod + def decode(data: ReadableBuffer, errors: str | None = None, /) -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +# Note: encode being a decode function and decode being an encode function is accurate to runtime. +class StreamConverter(StreamWriter, StreamReader): # type: ignore[misc] # incompatible methods in base classes + # At runtime, this is codecs.latin_1_decode + @staticmethod + def encode(data: ReadableBuffer, errors: str | None = None, /) -> tuple[str, int]: ... # type: ignore[override] + # At runtime, this is codecs.latin_1_encode + @staticmethod + def decode(str: str, errors: str | None = None, /) -> tuple[bytes, int]: ... # type: ignore[override] + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/mac_arabic.pyi b/mypy/typeshed/stdlib/encodings/mac_arabic.pyi new file mode 100644 index 000000000000..42781b489298 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/mac_arabic.pyi @@ -0,0 +1,21 @@ +import codecs +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_map: dict[int, int | None] +decoding_table: str +encoding_map: dict[int, int] diff --git a/mypy/typeshed/stdlib/encodings/mac_centeuro.pyi b/mypy/typeshed/stdlib/encodings/mac_centeuro.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/mac_centeuro.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/mac_croatian.pyi b/mypy/typeshed/stdlib/encodings/mac_croatian.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/mac_croatian.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/mac_cyrillic.pyi b/mypy/typeshed/stdlib/encodings/mac_cyrillic.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/mac_cyrillic.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/mac_farsi.pyi b/mypy/typeshed/stdlib/encodings/mac_farsi.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/mac_farsi.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/mac_greek.pyi b/mypy/typeshed/stdlib/encodings/mac_greek.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/mac_greek.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/mac_iceland.pyi b/mypy/typeshed/stdlib/encodings/mac_iceland.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/mac_iceland.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/mac_latin2.pyi b/mypy/typeshed/stdlib/encodings/mac_latin2.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/mac_latin2.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/mac_roman.pyi b/mypy/typeshed/stdlib/encodings/mac_roman.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/mac_roman.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/mac_romanian.pyi b/mypy/typeshed/stdlib/encodings/mac_romanian.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/mac_romanian.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/mac_turkish.pyi b/mypy/typeshed/stdlib/encodings/mac_turkish.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/mac_turkish.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/mbcs.pyi b/mypy/typeshed/stdlib/encodings/mbcs.pyi new file mode 100644 index 000000000000..2c2917d63f6d --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/mbcs.pyi @@ -0,0 +1,28 @@ +import codecs +import sys +from _typeshed import ReadableBuffer + +if sys.platform == "win32": + encode = codecs.mbcs_encode + + def decode(input: ReadableBuffer, errors: str | None = "strict") -> tuple[str, int]: ... + + class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + + class IncrementalDecoder(codecs.BufferedIncrementalDecoder): + # At runtime, this is codecs.mbcs_decode + @staticmethod + def _buffer_decode(data: ReadableBuffer, errors: str | None = None, final: bool = False, /) -> tuple[str, int]: ... + + class StreamWriter(codecs.StreamWriter): + # At runtime, this is codecs.mbcs_encode + @staticmethod + def encode(str: str, errors: str | None = None, /) -> tuple[bytes, int]: ... + + class StreamReader(codecs.StreamReader): + # At runtime, this is codecs.mbcs_decode + @staticmethod + def decode(data: ReadableBuffer, errors: str | None = None, final: bool = False, /) -> tuple[str, int]: ... + + def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/oem.pyi b/mypy/typeshed/stdlib/encodings/oem.pyi new file mode 100644 index 000000000000..376c12c445f4 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/oem.pyi @@ -0,0 +1,28 @@ +import codecs +import sys +from _typeshed import ReadableBuffer + +if sys.platform == "win32": + encode = codecs.oem_encode + + def decode(input: ReadableBuffer, errors: str | None = "strict") -> tuple[str, int]: ... + + class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + + class IncrementalDecoder(codecs.BufferedIncrementalDecoder): + # At runtime, this is codecs.oem_decode + @staticmethod + def _buffer_decode(data: ReadableBuffer, errors: str | None = None, final: bool = False, /) -> tuple[str, int]: ... + + class StreamWriter(codecs.StreamWriter): + # At runtime, this is codecs.oem_encode + @staticmethod + def encode(str: str, errors: str | None = None, /) -> tuple[bytes, int]: ... + + class StreamReader(codecs.StreamReader): + # At runtime, this is codecs.oem_decode + @staticmethod + def decode(data: ReadableBuffer, errors: str | None = None, final: bool = False, /) -> tuple[str, int]: ... + + def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/palmos.pyi b/mypy/typeshed/stdlib/encodings/palmos.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/palmos.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/ptcp154.pyi b/mypy/typeshed/stdlib/encodings/ptcp154.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/ptcp154.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/punycode.pyi b/mypy/typeshed/stdlib/encodings/punycode.pyi new file mode 100644 index 000000000000..eb99e667b416 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/punycode.pyi @@ -0,0 +1,33 @@ +import codecs +from typing import Literal + +def segregate(str: str) -> tuple[bytes, list[int]]: ... +def selective_len(str: str, max: int) -> int: ... +def selective_find(str: str, char: str, index: int, pos: int) -> tuple[int, int]: ... +def insertion_unsort(str: str, extended: list[int]) -> list[int]: ... +def T(j: int, bias: int) -> int: ... + +digits: Literal[b"abcdefghijklmnopqrstuvwxyz0123456789"] + +def generate_generalized_integer(N: int, bias: int) -> bytes: ... +def adapt(delta: int, first: bool, numchars: int) -> int: ... +def generate_integers(baselen: int, deltas: list[int]) -> bytes: ... +def punycode_encode(text: str) -> bytes: ... +def decode_generalized_number(extended: bytes, extpos: int, bias: int, errors: str) -> tuple[int, int | None]: ... +def insertion_sort(base: str, extended: bytes, errors: str) -> str: ... +def punycode_decode(text: memoryview | bytes | bytearray | str, errors: str) -> str: ... + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: memoryview | bytes | bytearray | str, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: memoryview | bytes | bytearray | str, final: bool = False) -> str: ... # type: ignore[override] + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/quopri_codec.pyi b/mypy/typeshed/stdlib/encodings/quopri_codec.pyi new file mode 100644 index 000000000000..e9deadd8d463 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/quopri_codec.pyi @@ -0,0 +1,26 @@ +import codecs +from _typeshed import ReadableBuffer +from typing import ClassVar + +# This codec is bytes to bytes. + +def quopri_encode(input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ... +def quopri_decode(input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ... + +class Codec(codecs.Codec): + def encode(self, input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ... # type: ignore[override] + def decode(self, input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ... # type: ignore[override] + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: ReadableBuffer, final: bool = False) -> bytes: ... # type: ignore[override] + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> bytes: ... # type: ignore[override] + +class StreamWriter(Codec, codecs.StreamWriter): + charbuffertype: ClassVar[type] = ... + +class StreamReader(Codec, codecs.StreamReader): + charbuffertype: ClassVar[type] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/raw_unicode_escape.pyi b/mypy/typeshed/stdlib/encodings/raw_unicode_escape.pyi new file mode 100644 index 000000000000..74abb4623fab --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/raw_unicode_escape.pyi @@ -0,0 +1,34 @@ +import codecs +import sys +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + # At runtime, this is codecs.raw_unicode_escape_encode + @staticmethod + def encode(str: str, errors: str | None = None, /) -> tuple[bytes, int]: ... + # At runtime, this is codecs.raw_unicode_escape_decode + if sys.version_info >= (3, 9): + @staticmethod + def decode(data: str | ReadableBuffer, errors: str | None = None, final: bool = True, /) -> tuple[str, int]: ... + else: + @staticmethod + def decode(data: str | ReadableBuffer, errors: str | None = None, /) -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +if sys.version_info >= (3, 9): + class IncrementalDecoder(codecs.BufferedIncrementalDecoder): + def _buffer_decode(self, input: str | ReadableBuffer, errors: str | None, final: bool) -> tuple[str, int]: ... + +else: + class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: str | ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... + +class StreamReader(Codec, codecs.StreamReader): + if sys.version_info >= (3, 9): + def decode(self, input: str | ReadableBuffer, errors: str = "strict") -> tuple[str, int]: ... # type: ignore[override] + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/rot_13.pyi b/mypy/typeshed/stdlib/encodings/rot_13.pyi new file mode 100644 index 000000000000..8d71bc957594 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/rot_13.pyi @@ -0,0 +1,23 @@ +import codecs +from _typeshed import SupportsRead, SupportsWrite + +# This codec is string to string. + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[str, int]: ... # type: ignore[override] + def decode(self, input: str, errors: str = "strict") -> tuple[str, int]: ... # type: ignore[override] + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> str: ... # type: ignore[override] + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: str, final: bool = False) -> str: ... # type: ignore[override] + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +rot13_map: dict[int, int] + +def rot13(infile: SupportsRead[str], outfile: SupportsWrite[str]) -> None: ... diff --git a/mypy/typeshed/stdlib/encodings/shift_jis.pyi b/mypy/typeshed/stdlib/encodings/shift_jis.pyi new file mode 100644 index 000000000000..d613026a5a86 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/shift_jis.pyi @@ -0,0 +1,23 @@ +import _multibytecodec as mbc +import codecs +from typing import ClassVar + +codec: mbc._MultibyteCodec + +class Codec(codecs.Codec): + encode = codec.encode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + decode = codec.decode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + +class IncrementalEncoder(mbc.MultibyteIncrementalEncoder, codecs.IncrementalEncoder): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class IncrementalDecoder(mbc.MultibyteIncrementalDecoder, codecs.IncrementalDecoder): + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamReader(Codec, mbc.MultibyteStreamReader, codecs.StreamReader): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamWriter(Codec, mbc.MultibyteStreamWriter, codecs.StreamWriter): + codec: ClassVar[mbc._MultibyteCodec] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/shift_jis_2004.pyi b/mypy/typeshed/stdlib/encodings/shift_jis_2004.pyi new file mode 100644 index 000000000000..d613026a5a86 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/shift_jis_2004.pyi @@ -0,0 +1,23 @@ +import _multibytecodec as mbc +import codecs +from typing import ClassVar + +codec: mbc._MultibyteCodec + +class Codec(codecs.Codec): + encode = codec.encode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + decode = codec.decode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + +class IncrementalEncoder(mbc.MultibyteIncrementalEncoder, codecs.IncrementalEncoder): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class IncrementalDecoder(mbc.MultibyteIncrementalDecoder, codecs.IncrementalDecoder): + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamReader(Codec, mbc.MultibyteStreamReader, codecs.StreamReader): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamWriter(Codec, mbc.MultibyteStreamWriter, codecs.StreamWriter): + codec: ClassVar[mbc._MultibyteCodec] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/shift_jisx0213.pyi b/mypy/typeshed/stdlib/encodings/shift_jisx0213.pyi new file mode 100644 index 000000000000..d613026a5a86 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/shift_jisx0213.pyi @@ -0,0 +1,23 @@ +import _multibytecodec as mbc +import codecs +from typing import ClassVar + +codec: mbc._MultibyteCodec + +class Codec(codecs.Codec): + encode = codec.encode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + decode = codec.decode # type: ignore[assignment] # pyright: ignore[reportAssignmentType] + +class IncrementalEncoder(mbc.MultibyteIncrementalEncoder, codecs.IncrementalEncoder): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class IncrementalDecoder(mbc.MultibyteIncrementalDecoder, codecs.IncrementalDecoder): + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamReader(Codec, mbc.MultibyteStreamReader, codecs.StreamReader): # type: ignore[misc] + codec: ClassVar[mbc._MultibyteCodec] = ... + +class StreamWriter(Codec, mbc.MultibyteStreamWriter, codecs.StreamWriter): + codec: ClassVar[mbc._MultibyteCodec] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/tis_620.pyi b/mypy/typeshed/stdlib/encodings/tis_620.pyi new file mode 100644 index 000000000000..f62195662ce9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/tis_620.pyi @@ -0,0 +1,21 @@ +import codecs +from _codecs import _EncodingMap +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: bytes, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... + +decoding_table: str +encoding_table: _EncodingMap diff --git a/mypy/typeshed/stdlib/encodings/undefined.pyi b/mypy/typeshed/stdlib/encodings/undefined.pyi new file mode 100644 index 000000000000..4775dac752f2 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/undefined.pyi @@ -0,0 +1,20 @@ +import codecs +from _typeshed import ReadableBuffer + +# These return types are just to match the base types. In reality, these always +# raise an error. + +class Codec(codecs.Codec): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + def decode(self, input: ReadableBuffer, errors: str = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... +class StreamReader(Codec, codecs.StreamReader): ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/unicode_escape.pyi b/mypy/typeshed/stdlib/encodings/unicode_escape.pyi new file mode 100644 index 000000000000..1e942f57916e --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/unicode_escape.pyi @@ -0,0 +1,34 @@ +import codecs +import sys +from _typeshed import ReadableBuffer + +class Codec(codecs.Codec): + # At runtime, this is codecs.unicode_escape_encode + @staticmethod + def encode(str: str, errors: str | None = None, /) -> tuple[bytes, int]: ... + # At runtime, this is codecs.unicode_escape_decode + if sys.version_info >= (3, 9): + @staticmethod + def decode(data: str | ReadableBuffer, errors: str | None = None, final: bool = True, /) -> tuple[str, int]: ... + else: + @staticmethod + def decode(data: str | ReadableBuffer, errors: str | None = None, /) -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +if sys.version_info >= (3, 9): + class IncrementalDecoder(codecs.BufferedIncrementalDecoder): + def _buffer_decode(self, input: str | ReadableBuffer, errors: str | None, final: bool) -> tuple[str, int]: ... + +else: + class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: str | ReadableBuffer, final: bool = False) -> str: ... + +class StreamWriter(Codec, codecs.StreamWriter): ... + +class StreamReader(Codec, codecs.StreamReader): + if sys.version_info >= (3, 9): + def decode(self, input: str | ReadableBuffer, errors: str = "strict") -> tuple[str, int]: ... # type: ignore[override] + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/utf_16.pyi b/mypy/typeshed/stdlib/encodings/utf_16.pyi new file mode 100644 index 000000000000..3b712cde420a --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/utf_16.pyi @@ -0,0 +1,20 @@ +import codecs +from _typeshed import ReadableBuffer + +encode = codecs.utf_16_encode + +def decode(input: ReadableBuffer, errors: str | None = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.BufferedIncrementalDecoder): + def _buffer_decode(self, input: ReadableBuffer, errors: str, final: bool) -> tuple[str, int]: ... + +class StreamWriter(codecs.StreamWriter): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + +class StreamReader(codecs.StreamReader): + def decode(self, input: ReadableBuffer, errors: str = "strict") -> tuple[str, int]: ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/utf_16_be.pyi b/mypy/typeshed/stdlib/encodings/utf_16_be.pyi new file mode 100644 index 000000000000..cc7d1534fc69 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/utf_16_be.pyi @@ -0,0 +1,26 @@ +import codecs +from _typeshed import ReadableBuffer + +encode = codecs.utf_16_be_encode + +def decode(input: ReadableBuffer, errors: str | None = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.BufferedIncrementalDecoder): + # At runtime, this is codecs.utf_16_be_decode + @staticmethod + def _buffer_decode(data: ReadableBuffer, errors: str | None = None, final: bool = False, /) -> tuple[str, int]: ... + +class StreamWriter(codecs.StreamWriter): + # At runtime, this is codecs.utf_16_be_encode + @staticmethod + def encode(str: str, errors: str | None = None, /) -> tuple[bytes, int]: ... + +class StreamReader(codecs.StreamReader): + # At runtime, this is codecs.utf_16_be_decode + @staticmethod + def decode(data: ReadableBuffer, errors: str | None = None, final: bool = False, /) -> tuple[str, int]: ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/utf_16_le.pyi b/mypy/typeshed/stdlib/encodings/utf_16_le.pyi new file mode 100644 index 000000000000..ba103eb088e3 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/utf_16_le.pyi @@ -0,0 +1,26 @@ +import codecs +from _typeshed import ReadableBuffer + +encode = codecs.utf_16_le_encode + +def decode(input: ReadableBuffer, errors: str | None = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.BufferedIncrementalDecoder): + # At runtime, this is codecs.utf_16_le_decode + @staticmethod + def _buffer_decode(data: ReadableBuffer, errors: str | None = None, final: bool = False, /) -> tuple[str, int]: ... + +class StreamWriter(codecs.StreamWriter): + # At runtime, this is codecs.utf_16_le_encode + @staticmethod + def encode(str: str, errors: str | None = None, /) -> tuple[bytes, int]: ... + +class StreamReader(codecs.StreamReader): + # At runtime, this is codecs.utf_16_le_decode + @staticmethod + def decode(data: ReadableBuffer, errors: str | None = None, final: bool = False, /) -> tuple[str, int]: ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/utf_32.pyi b/mypy/typeshed/stdlib/encodings/utf_32.pyi new file mode 100644 index 000000000000..c925be712c72 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/utf_32.pyi @@ -0,0 +1,20 @@ +import codecs +from _typeshed import ReadableBuffer + +encode = codecs.utf_32_encode + +def decode(input: ReadableBuffer, errors: str | None = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.BufferedIncrementalDecoder): + def _buffer_decode(self, input: ReadableBuffer, errors: str, final: bool) -> tuple[str, int]: ... + +class StreamWriter(codecs.StreamWriter): + def encode(self, input: str, errors: str = "strict") -> tuple[bytes, int]: ... + +class StreamReader(codecs.StreamReader): + def decode(self, input: ReadableBuffer, errors: str = "strict") -> tuple[str, int]: ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/utf_32_be.pyi b/mypy/typeshed/stdlib/encodings/utf_32_be.pyi new file mode 100644 index 000000000000..9d28f5199c50 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/utf_32_be.pyi @@ -0,0 +1,26 @@ +import codecs +from _typeshed import ReadableBuffer + +encode = codecs.utf_32_be_encode + +def decode(input: ReadableBuffer, errors: str | None = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.BufferedIncrementalDecoder): + # At runtime, this is codecs.utf_32_be_decode + @staticmethod + def _buffer_decode(data: ReadableBuffer, errors: str | None = None, final: bool = False, /) -> tuple[str, int]: ... + +class StreamWriter(codecs.StreamWriter): + # At runtime, this is codecs.utf_32_be_encode + @staticmethod + def encode(str: str, errors: str | None = None, /) -> tuple[bytes, int]: ... + +class StreamReader(codecs.StreamReader): + # At runtime, this is codecs.utf_32_be_decode + @staticmethod + def decode(data: ReadableBuffer, errors: str | None = None, final: bool = False, /) -> tuple[str, int]: ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/utf_32_le.pyi b/mypy/typeshed/stdlib/encodings/utf_32_le.pyi new file mode 100644 index 000000000000..5be14a91a3e6 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/utf_32_le.pyi @@ -0,0 +1,26 @@ +import codecs +from _typeshed import ReadableBuffer + +encode = codecs.utf_32_le_encode + +def decode(input: ReadableBuffer, errors: str | None = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.BufferedIncrementalDecoder): + # At runtime, this is codecs.utf_32_le_decode + @staticmethod + def _buffer_decode(data: ReadableBuffer, errors: str | None = None, final: bool = False, /) -> tuple[str, int]: ... + +class StreamWriter(codecs.StreamWriter): + # At runtime, this is codecs.utf_32_le_encode + @staticmethod + def encode(str: str, errors: str | None = None, /) -> tuple[bytes, int]: ... + +class StreamReader(codecs.StreamReader): + # At runtime, this is codecs.utf_32_le_decode + @staticmethod + def decode(data: ReadableBuffer, errors: str | None = None, final: bool = False, /) -> tuple[str, int]: ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/utf_7.pyi b/mypy/typeshed/stdlib/encodings/utf_7.pyi new file mode 100644 index 000000000000..dc1162f34c28 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/utf_7.pyi @@ -0,0 +1,26 @@ +import codecs +from _typeshed import ReadableBuffer + +encode = codecs.utf_7_encode + +def decode(input: ReadableBuffer, errors: str | None = "strict") -> tuple[str, int]: ... + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: str, final: bool = False) -> bytes: ... + +class IncrementalDecoder(codecs.BufferedIncrementalDecoder): + # At runtime, this is codecs.utf_7_decode + @staticmethod + def _buffer_decode(data: ReadableBuffer, errors: str | None = None, final: bool = False, /) -> tuple[str, int]: ... + +class StreamWriter(codecs.StreamWriter): + # At runtime, this is codecs.utf_7_encode + @staticmethod + def encode(str: str, errors: str | None = None, /) -> tuple[bytes, int]: ... + +class StreamReader(codecs.StreamReader): + # At runtime, this is codecs.utf_7_decode + @staticmethod + def decode(data: ReadableBuffer, errors: str | None = None, final: bool = False, /) -> tuple[str, int]: ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/utf_8.pyi b/mypy/typeshed/stdlib/encodings/utf_8.pyi index bb745399eb8c..918712d80473 100644 --- a/mypy/typeshed/stdlib/encodings/utf_8.pyi +++ b/mypy/typeshed/stdlib/encodings/utf_8.pyi @@ -1,21 +1,26 @@ import codecs from _typeshed import ReadableBuffer +encode = codecs.utf_8_encode + +def decode(input: ReadableBuffer, errors: str | None = "strict") -> tuple[str, int]: ... + class IncrementalEncoder(codecs.IncrementalEncoder): def encode(self, input: str, final: bool = False) -> bytes: ... class IncrementalDecoder(codecs.BufferedIncrementalDecoder): + # At runtime, this is codecs.utf_8_decode @staticmethod def _buffer_decode(data: ReadableBuffer, errors: str | None = None, final: bool = False, /) -> tuple[str, int]: ... class StreamWriter(codecs.StreamWriter): + # At runtime, this is codecs.utf_8_encode @staticmethod def encode(str: str, errors: str | None = None, /) -> tuple[bytes, int]: ... class StreamReader(codecs.StreamReader): + # At runtime, this is codecs.utf_8_decode @staticmethod def decode(data: ReadableBuffer, errors: str | None = None, final: bool = False, /) -> tuple[str, int]: ... def getregentry() -> codecs.CodecInfo: ... -def encode(str: str, errors: str | None = None, /) -> tuple[bytes, int]: ... -def decode(input: ReadableBuffer, errors: str | None = "strict") -> tuple[str, int]: ... diff --git a/mypy/typeshed/stdlib/encodings/uu_codec.pyi b/mypy/typeshed/stdlib/encodings/uu_codec.pyi new file mode 100644 index 000000000000..e32ba8ac0a1a --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/uu_codec.pyi @@ -0,0 +1,28 @@ +import codecs +from _typeshed import ReadableBuffer +from typing import ClassVar + +# This codec is bytes to bytes. + +def uu_encode( + input: ReadableBuffer, errors: str = "strict", filename: str = "", mode: int = 0o666 +) -> tuple[bytes, int]: ... +def uu_decode(input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ... + +class Codec(codecs.Codec): + def encode(self, input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ... # type: ignore[override] + def decode(self, input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ... # type: ignore[override] + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: ReadableBuffer, final: bool = False) -> bytes: ... # type: ignore[override] + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> bytes: ... # type: ignore[override] + +class StreamWriter(Codec, codecs.StreamWriter): + charbuffertype: ClassVar[type] = ... + +class StreamReader(Codec, codecs.StreamReader): + charbuffertype: ClassVar[type] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/encodings/zlib_codec.pyi b/mypy/typeshed/stdlib/encodings/zlib_codec.pyi new file mode 100644 index 000000000000..0f13d0e810e9 --- /dev/null +++ b/mypy/typeshed/stdlib/encodings/zlib_codec.pyi @@ -0,0 +1,26 @@ +import codecs +from _typeshed import ReadableBuffer +from typing import ClassVar + +# This codec is bytes to bytes. + +def zlib_encode(input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ... +def zlib_decode(input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ... + +class Codec(codecs.Codec): + def encode(self, input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ... # type: ignore[override] + def decode(self, input: ReadableBuffer, errors: str = "strict") -> tuple[bytes, int]: ... # type: ignore[override] + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input: ReadableBuffer, final: bool = False) -> bytes: ... # type: ignore[override] + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input: ReadableBuffer, final: bool = False) -> bytes: ... # type: ignore[override] + +class StreamWriter(Codec, codecs.StreamWriter): + charbuffertype: ClassVar[type] = ... + +class StreamReader(Codec, codecs.StreamReader): + charbuffertype: ClassVar[type] = ... + +def getregentry() -> codecs.CodecInfo: ... diff --git a/mypy/typeshed/stdlib/enum.pyi b/mypy/typeshed/stdlib/enum.pyi index 5c82b07c4185..3b6c325522d7 100644 --- a/mypy/typeshed/stdlib/enum.pyi +++ b/mypy/typeshed/stdlib/enum.pyi @@ -316,13 +316,24 @@ else: __rand__ = __and__ __rxor__ = __xor__ -# subclassing IntFlag so it picks up all implemented base functions, best modeling behavior of enum.auto() -class auto(IntFlag): +class auto: _value_: Any @_magic_enum_attr def value(self) -> Any: ... def __new__(cls) -> Self: ... + # These don't exist, but auto is basically immediately replaced with + # either an int or a str depending on the type of the enum. StrEnum's auto + # shouldn't have these, but they're needed for int versions of auto (mostly the __or__). + # Ideally type checkers would special case auto enough to handle this, + # but until then this is a slightly inaccurate helping hand. + def __or__(self, other: int | Self) -> Self: ... + def __and__(self, other: int | Self) -> Self: ... + def __xor__(self, other: int | Self) -> Self: ... + __ror__ = __or__ + __rand__ = __and__ + __rxor__ = __xor__ + if sys.version_info >= (3, 11): def pickle_by_global_name(self: Enum, proto: int) -> str: ... def pickle_by_enum_name(self: _EnumMemberT, proto: int) -> tuple[Callable[..., Any], tuple[type[_EnumMemberT], str]]: ... diff --git a/mypy/typeshed/stdlib/fcntl.pyi b/mypy/typeshed/stdlib/fcntl.pyi index 376611f166b8..71078b3b4579 100644 --- a/mypy/typeshed/stdlib/fcntl.pyi +++ b/mypy/typeshed/stdlib/fcntl.pyi @@ -70,8 +70,10 @@ if sys.platform != "win32": LOCK_RW: int LOCK_WRITE: int - # These are highly problematic, they might be present or not, depends on the specific OS. if sys.platform == "linux": + # Constants for the POSIX STREAMS interface. Present in glibc until 2.29 (released February 2019). + # Never implemented on BSD, and considered "obsolescent" starting in POSIX 2008. + # Probably still used on Solaris. I_ATMARK: int I_CANPUT: int I_CKBAND: int diff --git a/mypy/typeshed/stdlib/fileinput.pyi b/mypy/typeshed/stdlib/fileinput.pyi index 1e6aa78e2607..bf6daad0aea7 100644 --- a/mypy/typeshed/stdlib/fileinput.pyi +++ b/mypy/typeshed/stdlib/fileinput.pyi @@ -1,8 +1,8 @@ import sys from _typeshed import AnyStr_co, StrOrBytesPath -from collections.abc import Callable, Iterable, Iterator +from collections.abc import Callable, Iterable from types import TracebackType -from typing import IO, Any, AnyStr, Literal, Protocol, overload +from typing import IO, Any, AnyStr, Generic, Literal, Protocol, overload from typing_extensions import Self, TypeAlias if sys.version_info >= (3, 9): @@ -107,7 +107,7 @@ def fileno() -> int: ... def isfirstline() -> bool: ... def isstdin() -> bool: ... -class FileInput(Iterator[AnyStr]): +class FileInput(Generic[AnyStr]): if sys.version_info >= (3, 10): # encoding and errors are added @overload diff --git a/mypy/typeshed/stdlib/fractions.pyi b/mypy/typeshed/stdlib/fractions.pyi index 086aff50344c..fbcfa868cc1b 100644 --- a/mypy/typeshed/stdlib/fractions.pyi +++ b/mypy/typeshed/stdlib/fractions.pyi @@ -2,7 +2,7 @@ import sys from collections.abc import Callable from decimal import Decimal from numbers import Integral, Rational, Real -from typing import Any, Literal, SupportsIndex, overload +from typing import Any, Literal, Protocol, SupportsIndex, overload from typing_extensions import Self, TypeAlias _ComparableNum: TypeAlias = int | float | Decimal | Real @@ -20,11 +20,19 @@ else: @overload def gcd(a: Integral, b: Integral) -> Integral: ... +class _ConvertibleToIntegerRatio(Protocol): + def as_integer_ratio(self) -> tuple[int | Rational, int | Rational]: ... + class Fraction(Rational): @overload def __new__(cls, numerator: int | Rational = 0, denominator: int | Rational | None = None) -> Self: ... @overload def __new__(cls, value: float | Decimal | str, /) -> Self: ... + + if sys.version_info >= (3, 14): + @overload + def __new__(cls, value: _ConvertibleToIntegerRatio) -> Self: ... + @classmethod def from_float(cls, f: float) -> Self: ... @classmethod diff --git a/mypy/typeshed/stdlib/getopt.pyi b/mypy/typeshed/stdlib/getopt.pyi index bc9d4da4796b..bcc8d9750b19 100644 --- a/mypy/typeshed/stdlib/getopt.pyi +++ b/mypy/typeshed/stdlib/getopt.pyi @@ -1,7 +1,11 @@ +from collections.abc import Iterable + __all__ = ["GetoptError", "error", "getopt", "gnu_getopt"] -def getopt(args: list[str], shortopts: str, longopts: list[str] = []) -> tuple[list[tuple[str, str]], list[str]]: ... -def gnu_getopt(args: list[str], shortopts: str, longopts: list[str] = []) -> tuple[list[tuple[str, str]], list[str]]: ... +def getopt(args: list[str], shortopts: str, longopts: Iterable[str] | str = []) -> tuple[list[tuple[str, str]], list[str]]: ... +def gnu_getopt( + args: list[str], shortopts: str, longopts: Iterable[str] | str = [] +) -> tuple[list[tuple[str, str]], list[str]]: ... class GetoptError(Exception): msg: str diff --git a/mypy/typeshed/stdlib/gettext.pyi b/mypy/typeshed/stdlib/gettext.pyi index 4c17c0dc5de4..d8fd92a00e13 100644 --- a/mypy/typeshed/stdlib/gettext.pyi +++ b/mypy/typeshed/stdlib/gettext.pyi @@ -167,3 +167,5 @@ if sys.version_info < (3, 11): def bind_textdomain_codeset(domain: str, codeset: str | None = None) -> str: ... Catalog = translation + +def c2py(plural: str) -> Callable[[int], int]: ... diff --git a/mypy/typeshed/stdlib/hashlib.pyi b/mypy/typeshed/stdlib/hashlib.pyi index 93bd986c9d31..db6f8635054d 100644 --- a/mypy/typeshed/stdlib/hashlib.pyi +++ b/mypy/typeshed/stdlib/hashlib.pyi @@ -1,8 +1,19 @@ import sys +from _blake2 import blake2b as blake2b, blake2s as blake2s +from _hashlib import ( + HASH, + openssl_md5 as md5, + openssl_sha1 as sha1, + openssl_sha224 as sha224, + openssl_sha256 as sha256, + openssl_sha384 as sha384, + openssl_sha512 as sha512, + pbkdf2_hmac as pbkdf2_hmac, + scrypt as scrypt, +) from _typeshed import ReadableBuffer from collections.abc import Callable, Set as AbstractSet -from typing import Protocol, final -from typing_extensions import Self +from typing import Protocol, type_check_only if sys.version_info >= (3, 11): __all__ = ( @@ -48,112 +59,35 @@ else: "pbkdf2_hmac", ) -class _Hash: - @property - def digest_size(self) -> int: ... - @property - def block_size(self) -> int: ... - @property - def name(self) -> str: ... - def __init__(self, data: ReadableBuffer = ...) -> None: ... - def copy(self) -> Self: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def update(self, data: ReadableBuffer, /) -> None: ... - if sys.version_info >= (3, 9): - def new(name: str, data: ReadableBuffer = b"", *, usedforsecurity: bool = ...) -> _Hash: ... - def md5(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> _Hash: ... - def sha1(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> _Hash: ... - def sha224(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> _Hash: ... - def sha256(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> _Hash: ... - def sha384(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> _Hash: ... - def sha512(string: ReadableBuffer = b"", *, usedforsecurity: bool = True) -> _Hash: ... + def new(name: str, data: ReadableBuffer = b"", *, usedforsecurity: bool = ...) -> HASH: ... + from _hashlib import ( + openssl_sha3_224 as sha3_224, + openssl_sha3_256 as sha3_256, + openssl_sha3_384 as sha3_384, + openssl_sha3_512 as sha3_512, + openssl_shake_128 as shake_128, + openssl_shake_256 as shake_256, + ) else: - def new(name: str, data: ReadableBuffer = b"") -> _Hash: ... - def md5(string: ReadableBuffer = b"") -> _Hash: ... - def sha1(string: ReadableBuffer = b"") -> _Hash: ... - def sha224(string: ReadableBuffer = b"") -> _Hash: ... - def sha256(string: ReadableBuffer = b"") -> _Hash: ... - def sha384(string: ReadableBuffer = b"") -> _Hash: ... - def sha512(string: ReadableBuffer = b"") -> _Hash: ... + @type_check_only + class _VarLenHash(HASH): + def digest(self, length: int) -> bytes: ... # type: ignore[override] + def hexdigest(self, length: int) -> str: ... # type: ignore[override] + + def new(name: str, data: ReadableBuffer = b"") -> HASH: ... + # At runtime these aren't functions but classes imported from _sha3 + def sha3_224(string: ReadableBuffer = b"") -> HASH: ... + def sha3_256(string: ReadableBuffer = b"") -> HASH: ... + def sha3_384(string: ReadableBuffer = b"") -> HASH: ... + def sha3_512(string: ReadableBuffer = b"") -> HASH: ... + def shake_128(string: ReadableBuffer = b"") -> _VarLenHash: ... + def shake_256(string: ReadableBuffer = b"") -> _VarLenHash: ... algorithms_guaranteed: AbstractSet[str] algorithms_available: AbstractSet[str] -def pbkdf2_hmac( - hash_name: str, password: ReadableBuffer, salt: ReadableBuffer, iterations: int, dklen: int | None = None -) -> bytes: ... - -class _VarLenHash: - digest_size: int - block_size: int - name: str - def __init__(self, data: ReadableBuffer = ...) -> None: ... - def copy(self) -> _VarLenHash: ... - def digest(self, length: int, /) -> bytes: ... - def hexdigest(self, length: int, /) -> str: ... - def update(self, data: ReadableBuffer, /) -> None: ... - -sha3_224 = _Hash -sha3_256 = _Hash -sha3_384 = _Hash -sha3_512 = _Hash -shake_128 = _VarLenHash -shake_256 = _VarLenHash - -def scrypt( - password: ReadableBuffer, *, salt: ReadableBuffer, n: int, r: int, p: int, maxmem: int = 0, dklen: int = 64 -) -> bytes: ... -@final -class _BlakeHash(_Hash): - MAX_DIGEST_SIZE: int - MAX_KEY_SIZE: int - PERSON_SIZE: int - SALT_SIZE: int - - if sys.version_info >= (3, 9): - def __init__( - self, - data: ReadableBuffer = ..., - /, - *, - digest_size: int = ..., - key: ReadableBuffer = ..., - salt: ReadableBuffer = ..., - person: ReadableBuffer = ..., - fanout: int = ..., - depth: int = ..., - leaf_size: int = ..., - node_offset: int = ..., - node_depth: int = ..., - inner_size: int = ..., - last_node: bool = ..., - usedforsecurity: bool = ..., - ) -> None: ... - else: - def __init__( - self, - data: ReadableBuffer = ..., - /, - *, - digest_size: int = ..., - key: ReadableBuffer = ..., - salt: ReadableBuffer = ..., - person: ReadableBuffer = ..., - fanout: int = ..., - depth: int = ..., - leaf_size: int = ..., - node_offset: int = ..., - node_depth: int = ..., - inner_size: int = ..., - last_node: bool = ..., - ) -> None: ... - -blake2b = _BlakeHash -blake2s = _BlakeHash - if sys.version_info >= (3, 11): class _BytesIOLike(Protocol): def getbuffer(self) -> ReadableBuffer: ... @@ -163,5 +97,8 @@ if sys.version_info >= (3, 11): def readable(self) -> bool: ... def file_digest( - fileobj: _BytesIOLike | _FileDigestFileObj, digest: str | Callable[[], _Hash], /, *, _bufsize: int = 262144 - ) -> _Hash: ... + fileobj: _BytesIOLike | _FileDigestFileObj, digest: str | Callable[[], HASH], /, *, _bufsize: int = 262144 + ) -> HASH: ... + +# Legacy typing-only alias +_Hash = HASH diff --git a/mypy/typeshed/stdlib/hmac.pyi b/mypy/typeshed/stdlib/hmac.pyi index ac1372dd1e9c..efd649ec39a8 100644 --- a/mypy/typeshed/stdlib/hmac.pyi +++ b/mypy/typeshed/stdlib/hmac.pyi @@ -1,12 +1,12 @@ +import sys +from _hashlib import HASH as _HashlibHash from _typeshed import ReadableBuffer, SizedBuffer from collections.abc import Callable from types import ModuleType -from typing import Any, AnyStr, overload +from typing import AnyStr, overload from typing_extensions import TypeAlias -# TODO more precise type for object of hashlib -_Hash: TypeAlias = Any -_DigestMod: TypeAlias = str | Callable[[], _Hash] | ModuleType +_DigestMod: TypeAlias = str | Callable[[], _HashlibHash] | ModuleType trans_5C: bytes trans_36: bytes @@ -31,8 +31,12 @@ class HMAC: def hexdigest(self) -> str: ... def copy(self) -> HMAC: ... -@overload -def compare_digest(a: ReadableBuffer, b: ReadableBuffer, /) -> bool: ... -@overload -def compare_digest(a: AnyStr, b: AnyStr, /) -> bool: ... def digest(key: SizedBuffer, msg: ReadableBuffer, digest: _DigestMod) -> bytes: ... + +if sys.version_info >= (3, 9): + from _hashlib import compare_digest as compare_digest +else: + @overload + def compare_digest(a: ReadableBuffer, b: ReadableBuffer, /) -> bool: ... + @overload + def compare_digest(a: AnyStr, b: AnyStr, /) -> bool: ... diff --git a/mypy/typeshed/stdlib/http/client.pyi b/mypy/typeshed/stdlib/http/client.pyi index f68d9d0ca7d7..3db764ef1e7c 100644 --- a/mypy/typeshed/stdlib/http/client.pyi +++ b/mypy/typeshed/stdlib/http/client.pyi @@ -3,10 +3,10 @@ import io import ssl import sys import types -from _typeshed import ReadableBuffer, SupportsRead, SupportsReadline, WriteableBuffer +from _typeshed import MaybeNone, ReadableBuffer, SupportsRead, SupportsReadline, WriteableBuffer from collections.abc import Callable, Iterable, Iterator, Mapping from socket import socket -from typing import Any, BinaryIO, TypeVar, overload +from typing import BinaryIO, TypeVar, overload from typing_extensions import Self, TypeAlias __all__ = [ @@ -34,6 +34,7 @@ __all__ = [ _DataType: TypeAlias = SupportsRead[bytes] | Iterable[ReadableBuffer] | ReadableBuffer _T = TypeVar("_T") _MessageT = TypeVar("_MessageT", bound=email.message.Message) +_HeaderValue: TypeAlias = ReadableBuffer | str | int HTTP_PORT: int HTTPS_PORT: int @@ -153,7 +154,7 @@ class HTTPConnection: timeout: float | None host: str port: int - sock: socket | Any # can be `None` if `.connect()` was not called + sock: socket | MaybeNone # can be `None` if `.connect()` was not called def __init__( self, host: str, @@ -167,7 +168,7 @@ class HTTPConnection: method: str, url: str, body: _DataType | str | None = None, - headers: Mapping[str, str] = {}, + headers: Mapping[str, _HeaderValue] = {}, *, encode_chunked: bool = False, ) -> None: ... @@ -180,13 +181,13 @@ class HTTPConnection: def connect(self) -> None: ... def close(self) -> None: ... def putrequest(self, method: str, url: str, skip_host: bool = False, skip_accept_encoding: bool = False) -> None: ... - def putheader(self, header: str | bytes, *argument: str | bytes) -> None: ... + def putheader(self, header: str | bytes, *values: _HeaderValue) -> None: ... def endheaders(self, message_body: _DataType | None = None, *, encode_chunked: bool = False) -> None: ... def send(self, data: _DataType | str) -> None: ... class HTTPSConnection(HTTPConnection): # Can be `None` if `.connect()` was not called: - sock: ssl.SSLSocket | Any + sock: ssl.SSLSocket | MaybeNone if sys.version_info >= (3, 12): def __init__( self, diff --git a/mypy/typeshed/stdlib/http/cookiejar.pyi b/mypy/typeshed/stdlib/http/cookiejar.pyi index 56097f163afd..31e1d3fc8378 100644 --- a/mypy/typeshed/stdlib/http/cookiejar.pyi +++ b/mypy/typeshed/stdlib/http/cookiejar.pyi @@ -1,6 +1,6 @@ import sys from _typeshed import StrPath -from collections.abc import Iterable, Iterator, Sequence +from collections.abc import Iterator, Sequence from http.client import HTTPResponse from re import Pattern from typing import ClassVar, TypeVar, overload @@ -21,7 +21,7 @@ _T = TypeVar("_T") class LoadError(OSError): ... -class CookieJar(Iterable[Cookie]): +class CookieJar: non_word_re: ClassVar[Pattern[str]] # undocumented quote_re: ClassVar[Pattern[str]] # undocumented strict_domain_re: ClassVar[Pattern[str]] # undocumented diff --git a/mypy/typeshed/stdlib/importlib/__init__.pyi b/mypy/typeshed/stdlib/importlib/__init__.pyi index 8506efc01171..cab81512e92f 100644 --- a/mypy/typeshed/stdlib/importlib/__init__.pyi +++ b/mypy/typeshed/stdlib/importlib/__init__.pyi @@ -1,19 +1,10 @@ import sys -from collections.abc import Mapping, Sequence +from importlib._bootstrap import __import__ as __import__ from importlib.abc import Loader from types import ModuleType __all__ = ["__import__", "import_module", "invalidate_caches", "reload"] -# Signature of `builtins.__import__` should be kept identical to `importlib.__import__` -def __import__( - name: str, - globals: Mapping[str, object] | None = None, - locals: Mapping[str, object] | None = None, - fromlist: Sequence[str] = (), - level: int = 0, -) -> ModuleType: ... - # `importlib.import_module` return type should be kept the same as `builtins.__import__` def import_module(name: str, package: str | None = None) -> ModuleType: ... diff --git a/mypy/typeshed/stdlib/importlib/_bootstrap.pyi b/mypy/typeshed/stdlib/importlib/_bootstrap.pyi new file mode 100644 index 000000000000..02427ff42062 --- /dev/null +++ b/mypy/typeshed/stdlib/importlib/_bootstrap.pyi @@ -0,0 +1,2 @@ +from _frozen_importlib import * +from _frozen_importlib import __import__ as __import__, _init_module_attrs as _init_module_attrs diff --git a/mypy/typeshed/stdlib/importlib/_bootstrap_external.pyi b/mypy/typeshed/stdlib/importlib/_bootstrap_external.pyi new file mode 100644 index 000000000000..6210ce7083af --- /dev/null +++ b/mypy/typeshed/stdlib/importlib/_bootstrap_external.pyi @@ -0,0 +1,2 @@ +from _frozen_importlib_external import * +from _frozen_importlib_external import _NamespaceLoader as _NamespaceLoader diff --git a/mypy/typeshed/stdlib/importlib/abc.pyi b/mypy/typeshed/stdlib/importlib/abc.pyi index 4a0a70d0930d..588377d7d871 100644 --- a/mypy/typeshed/stdlib/importlib/abc.pyi +++ b/mypy/typeshed/stdlib/importlib/abc.pyi @@ -4,6 +4,7 @@ import types from _typeshed import ReadableBuffer, StrPath from abc import ABCMeta, abstractmethod from collections.abc import Iterator, Mapping, Sequence +from importlib import _bootstrap_external from importlib.machinery import ModuleSpec from io import BufferedReader from typing import IO, Any, Literal, Protocol, overload, runtime_checkable @@ -56,7 +57,7 @@ class ExecutionLoader(InspectLoader): @abstractmethod def get_filename(self, fullname: str) -> str: ... -class SourceLoader(ResourceLoader, ExecutionLoader, metaclass=ABCMeta): +class SourceLoader(_bootstrap_external.SourceLoader, ResourceLoader, ExecutionLoader, metaclass=ABCMeta): # type: ignore[misc] # incompatible definitions of source_to_code in the base classes def path_mtime(self, path: str) -> float: ... def set_data(self, path: str, data: bytes) -> None: ... def get_source(self, fullname: str) -> str | None: ... @@ -101,7 +102,7 @@ else: # Not defined on the actual class, but expected to exist. def find_spec(self, fullname: str, target: types.ModuleType | None = ...) -> ModuleSpec | None: ... -class FileLoader(ResourceLoader, ExecutionLoader, metaclass=ABCMeta): +class FileLoader(_bootstrap_external.FileLoader, ResourceLoader, ExecutionLoader, metaclass=ABCMeta): name: str path: str def __init__(self, fullname: str, path: str) -> None: ... diff --git a/mypy/typeshed/stdlib/importlib/machinery.pyi b/mypy/typeshed/stdlib/importlib/machinery.pyi index 586c2b80ab7b..bb1a6f93d0e0 100644 --- a/mypy/typeshed/stdlib/importlib/machinery.pyi +++ b/mypy/typeshed/stdlib/importlib/machinery.pyi @@ -1,179 +1,20 @@ -import importlib.abc import sys -import types -from _typeshed import ReadableBuffer -from collections.abc import Callable, Iterable, MutableSequence, Sequence -from importlib.metadata import DistributionFinder, PathDistribution -from typing import Any, Literal -from typing_extensions import deprecated - -class ModuleSpec: - def __init__( - self, - name: str, - loader: importlib.abc.Loader | None, - *, - origin: str | None = None, - loader_state: Any = None, - is_package: bool | None = None, - ) -> None: ... - name: str - loader: importlib.abc.Loader | None - origin: str | None - submodule_search_locations: list[str] | None - loader_state: Any - cached: str | None - @property - def parent(self) -> str | None: ... - has_location: bool - def __eq__(self, other: object) -> bool: ... - -class BuiltinImporter(importlib.abc.MetaPathFinder, importlib.abc.InspectLoader): - # MetaPathFinder - if sys.version_info < (3, 12): - @classmethod - def find_module(cls, fullname: str, path: Sequence[str] | None = None) -> importlib.abc.Loader | None: ... - - @classmethod - def find_spec( - cls, fullname: str, path: Sequence[str] | None = None, target: types.ModuleType | None = None - ) -> ModuleSpec | None: ... - # InspectLoader - @classmethod - def is_package(cls, fullname: str) -> bool: ... - @classmethod - def load_module(cls, fullname: str) -> types.ModuleType: ... - @classmethod - def get_code(cls, fullname: str) -> None: ... - @classmethod - def get_source(cls, fullname: str) -> None: ... - # Loader - if sys.version_info < (3, 12): - @staticmethod - def module_repr(module: types.ModuleType) -> str: ... - if sys.version_info >= (3, 10): - @staticmethod - def create_module(spec: ModuleSpec) -> types.ModuleType | None: ... - @staticmethod - def exec_module(module: types.ModuleType) -> None: ... - else: - @classmethod - def create_module(cls, spec: ModuleSpec) -> types.ModuleType | None: ... - @classmethod - def exec_module(cls, module: types.ModuleType) -> None: ... - -class FrozenImporter(importlib.abc.MetaPathFinder, importlib.abc.InspectLoader): - # MetaPathFinder - if sys.version_info < (3, 12): - @classmethod - def find_module(cls, fullname: str, path: Sequence[str] | None = None) -> importlib.abc.Loader | None: ... - - @classmethod - def find_spec( - cls, fullname: str, path: Sequence[str] | None = None, target: types.ModuleType | None = None - ) -> ModuleSpec | None: ... - # InspectLoader - @classmethod - def is_package(cls, fullname: str) -> bool: ... - @classmethod - def load_module(cls, fullname: str) -> types.ModuleType: ... - @classmethod - def get_code(cls, fullname: str) -> None: ... - @classmethod - def get_source(cls, fullname: str) -> None: ... - # Loader - if sys.version_info < (3, 12): - @staticmethod - def module_repr(m: types.ModuleType) -> str: ... - if sys.version_info >= (3, 10): - @staticmethod - def create_module(spec: ModuleSpec) -> types.ModuleType | None: ... - else: - @classmethod - def create_module(cls, spec: ModuleSpec) -> types.ModuleType | None: ... - - @staticmethod - def exec_module(module: types.ModuleType) -> None: ... - -class WindowsRegistryFinder(importlib.abc.MetaPathFinder): - if sys.version_info < (3, 12): - @classmethod - def find_module(cls, fullname: str, path: Sequence[str] | None = None) -> importlib.abc.Loader | None: ... - - @classmethod - def find_spec( - cls, fullname: str, path: Sequence[str] | None = None, target: types.ModuleType | None = None - ) -> ModuleSpec | None: ... - -class PathFinder: - if sys.version_info >= (3, 10): - @staticmethod - def invalidate_caches() -> None: ... - else: - @classmethod - def invalidate_caches(cls) -> None: ... - if sys.version_info >= (3, 10): - @staticmethod - def find_distributions(context: DistributionFinder.Context = ...) -> Iterable[PathDistribution]: ... - else: - @classmethod - def find_distributions(cls, context: DistributionFinder.Context = ...) -> Iterable[PathDistribution]: ... - - @classmethod - def find_spec( - cls, fullname: str, path: Sequence[str] | None = None, target: types.ModuleType | None = None - ) -> ModuleSpec | None: ... - if sys.version_info < (3, 12): - @classmethod - def find_module(cls, fullname: str, path: Sequence[str] | None = None) -> importlib.abc.Loader | None: ... - -SOURCE_SUFFIXES: list[str] -DEBUG_BYTECODE_SUFFIXES: list[str] -OPTIMIZED_BYTECODE_SUFFIXES: list[str] -BYTECODE_SUFFIXES: list[str] -EXTENSION_SUFFIXES: list[str] - -def all_suffixes() -> list[str]: ... - -class FileFinder(importlib.abc.PathEntryFinder): - path: str - def __init__(self, path: str, *loader_details: tuple[type[importlib.abc.Loader], list[str]]) -> None: ... - @classmethod - def path_hook( - cls, *loader_details: tuple[type[importlib.abc.Loader], list[str]] - ) -> Callable[[str], importlib.abc.PathEntryFinder]: ... - -class SourceFileLoader(importlib.abc.FileLoader, importlib.abc.SourceLoader): - def set_data(self, path: str, data: ReadableBuffer, *, _mode: int = 0o666) -> None: ... - -class SourcelessFileLoader(importlib.abc.FileLoader, importlib.abc.SourceLoader): ... - -class ExtensionFileLoader(importlib.abc.ExecutionLoader): - def __init__(self, name: str, path: str) -> None: ... - def get_filename(self, name: str | None = None) -> str: ... - def get_source(self, fullname: str) -> None: ... - def create_module(self, spec: ModuleSpec) -> types.ModuleType: ... - def exec_module(self, module: types.ModuleType) -> None: ... - def get_code(self, fullname: str) -> None: ... - def __eq__(self, other: object) -> bool: ... - def __hash__(self) -> int: ... +from importlib._bootstrap import BuiltinImporter as BuiltinImporter, FrozenImporter as FrozenImporter, ModuleSpec as ModuleSpec +from importlib._bootstrap_external import ( + BYTECODE_SUFFIXES as BYTECODE_SUFFIXES, + DEBUG_BYTECODE_SUFFIXES as DEBUG_BYTECODE_SUFFIXES, + EXTENSION_SUFFIXES as EXTENSION_SUFFIXES, + OPTIMIZED_BYTECODE_SUFFIXES as OPTIMIZED_BYTECODE_SUFFIXES, + SOURCE_SUFFIXES as SOURCE_SUFFIXES, + ExtensionFileLoader as ExtensionFileLoader, + FileFinder as FileFinder, + PathFinder as PathFinder, + SourceFileLoader as SourceFileLoader, + SourcelessFileLoader as SourcelessFileLoader, + WindowsRegistryFinder as WindowsRegistryFinder, +) if sys.version_info >= (3, 11): - import importlib.readers + from importlib._bootstrap_external import NamespaceLoader as NamespaceLoader - class NamespaceLoader(importlib.abc.InspectLoader): - def __init__( - self, name: str, path: MutableSequence[str], path_finder: Callable[[str, tuple[str, ...]], ModuleSpec] - ) -> None: ... - def is_package(self, fullname: str) -> Literal[True]: ... - def get_source(self, fullname: str) -> Literal[""]: ... - def get_code(self, fullname: str) -> types.CodeType: ... - def create_module(self, spec: ModuleSpec) -> None: ... - def exec_module(self, module: types.ModuleType) -> None: ... - @deprecated("load_module() is deprecated; use exec_module() instead") - def load_module(self, fullname: str) -> types.ModuleType: ... - def get_resource_reader(self, module: types.ModuleType) -> importlib.readers.NamespaceReader: ... - if sys.version_info < (3, 12): - @staticmethod - @deprecated("module_repr() is deprecated, and has been removed in Python 3.12") - def module_repr(module: types.ModuleType) -> str: ... +def all_suffixes() -> list[str]: ... diff --git a/mypy/typeshed/stdlib/importlib/resources/abc.pyi b/mypy/typeshed/stdlib/importlib/resources/abc.pyi index a36c952d01ac..ad80605f7c71 100644 --- a/mypy/typeshed/stdlib/importlib/resources/abc.pyi +++ b/mypy/typeshed/stdlib/importlib/resources/abc.pyi @@ -10,3 +10,5 @@ if sys.version_info >= (3, 11): Traversable as Traversable, TraversableResources as TraversableResources, ) + + __all__ = ["ResourceReader", "Traversable", "TraversableResources"] diff --git a/mypy/typeshed/stdlib/importlib/util.pyi b/mypy/typeshed/stdlib/importlib/util.pyi index 2492c76d5c6c..cc1c98ae4d0e 100644 --- a/mypy/typeshed/stdlib/importlib/util.pyi +++ b/mypy/typeshed/stdlib/importlib/util.pyi @@ -2,10 +2,16 @@ import importlib.abc import importlib.machinery import sys import types -from _typeshed import ReadableBuffer, StrOrBytesPath -from _typeshed.importlib import LoaderProtocol +from _typeshed import ReadableBuffer from collections.abc import Callable -from typing import Any +from importlib._bootstrap import module_from_spec as module_from_spec, spec_from_loader as spec_from_loader +from importlib._bootstrap_external import ( + MAGIC_NUMBER as MAGIC_NUMBER, + cache_from_source as cache_from_source, + decode_source as decode_source, + source_from_cache as source_from_cache, + spec_from_file_location as spec_from_file_location, +) from typing_extensions import ParamSpec _P = ParamSpec("_P") @@ -16,24 +22,7 @@ if sys.version_info < (3, 12): def set_package(fxn: Callable[_P, types.ModuleType]) -> Callable[_P, types.ModuleType]: ... def resolve_name(name: str, package: str | None) -> str: ... - -MAGIC_NUMBER: bytes - -def cache_from_source(path: str, debug_override: bool | None = None, *, optimization: Any | None = None) -> str: ... -def source_from_cache(path: str) -> str: ... -def decode_source(source_bytes: ReadableBuffer) -> str: ... def find_spec(name: str, package: str | None = None) -> importlib.machinery.ModuleSpec | None: ... -def spec_from_loader( - name: str, loader: LoaderProtocol | None, *, origin: str | None = None, is_package: bool | None = None -) -> importlib.machinery.ModuleSpec | None: ... -def spec_from_file_location( - name: str, - location: StrOrBytesPath | None = None, - *, - loader: LoaderProtocol | None = None, - submodule_search_locations: list[str] | None = ..., -) -> importlib.machinery.ModuleSpec | None: ... -def module_from_spec(spec: importlib.machinery.ModuleSpec) -> types.ModuleType: ... class LazyLoader(importlib.abc.Loader): def __init__(self, loader: importlib.abc.Loader) -> None: ... diff --git a/mypy/typeshed/stdlib/io.pyi b/mypy/typeshed/stdlib/io.pyi index 7607608696dd..5c26cb245a2f 100644 --- a/mypy/typeshed/stdlib/io.pyi +++ b/mypy/typeshed/stdlib/io.pyi @@ -1,13 +1,26 @@ import abc -import builtins -import codecs import sys -from _typeshed import FileDescriptorOrPath, ReadableBuffer, WriteableBuffer -from collections.abc import Callable, Iterable, Iterator -from os import _Opener -from types import TracebackType -from typing import IO, Any, BinaryIO, Final, Generic, Literal, Protocol, TextIO, TypeVar, overload, type_check_only -from typing_extensions import Self +from _io import ( + DEFAULT_BUFFER_SIZE as DEFAULT_BUFFER_SIZE, + BlockingIOError as BlockingIOError, + BufferedRandom as BufferedRandom, + BufferedReader as BufferedReader, + BufferedRWPair as BufferedRWPair, + BufferedWriter as BufferedWriter, + BytesIO as BytesIO, + FileIO as FileIO, + IncrementalNewlineDecoder as IncrementalNewlineDecoder, + StringIO as StringIO, + TextIOWrapper as TextIOWrapper, + _BufferedIOBase, + _IOBase, + _RawIOBase, + _TextIOBase, + _WrappedBuffer as _WrappedBuffer, # used elsewhere in typeshed + open as open, + open_code as open_code, +) +from typing import Final __all__ = [ "BlockingIOError", @@ -32,208 +45,16 @@ __all__ = [ ] if sys.version_info >= (3, 11): - __all__ += ["DEFAULT_BUFFER_SIZE", "IncrementalNewlineDecoder", "text_encoding"] - -_T = TypeVar("_T") + from _io import text_encoding as text_encoding -DEFAULT_BUFFER_SIZE: Final = 8192 + __all__ += ["DEFAULT_BUFFER_SIZE", "IncrementalNewlineDecoder", "text_encoding"] SEEK_SET: Final = 0 SEEK_CUR: Final = 1 SEEK_END: Final = 2 -open = builtins.open - -def open_code(path: str) -> IO[bytes]: ... - -BlockingIOError = builtins.BlockingIOError - class UnsupportedOperation(OSError, ValueError): ... - -class IOBase(metaclass=abc.ABCMeta): - def __iter__(self) -> Iterator[bytes]: ... - def __next__(self) -> bytes: ... - def __enter__(self) -> Self: ... - def __exit__( - self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None - ) -> None: ... - def close(self) -> None: ... - def fileno(self) -> int: ... - def flush(self) -> None: ... - def isatty(self) -> bool: ... - def readable(self) -> bool: ... - read: Callable[..., Any] - def readlines(self, hint: int = -1, /) -> list[bytes]: ... - def seek(self, offset: int, whence: int = ..., /) -> int: ... - def seekable(self) -> bool: ... - def tell(self) -> int: ... - def truncate(self, size: int | None = ..., /) -> int: ... - def writable(self) -> bool: ... - write: Callable[..., Any] - def writelines(self, lines: Iterable[ReadableBuffer], /) -> None: ... - def readline(self, size: int | None = -1, /) -> bytes: ... - def __del__(self) -> None: ... - @property - def closed(self) -> bool: ... - def _checkClosed(self) -> None: ... # undocumented - -class RawIOBase(IOBase): - def readall(self) -> bytes: ... - def readinto(self, buffer: WriteableBuffer, /) -> int | None: ... - def write(self, b: ReadableBuffer, /) -> int | None: ... - def read(self, size: int = -1, /) -> bytes | None: ... - -class BufferedIOBase(IOBase): - def detach(self) -> RawIOBase: ... - def readinto(self, buffer: WriteableBuffer, /) -> int: ... - def write(self, buffer: ReadableBuffer, /) -> int: ... - def readinto1(self, buffer: WriteableBuffer, /) -> int: ... - def read(self, size: int | None = ..., /) -> bytes: ... - def read1(self, size: int = ..., /) -> bytes: ... - -class FileIO(RawIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of writelines in the base classes - mode: str - # The type of "name" equals the argument passed in to the constructor, - # but that can make FileIO incompatible with other I/O types that assume - # "name" is a str. In the future, making FileIO generic might help. - name: Any - def __init__( - self, file: FileDescriptorOrPath, mode: str = ..., closefd: bool = ..., opener: _Opener | None = ... - ) -> None: ... - @property - def closefd(self) -> bool: ... - def write(self, b: ReadableBuffer, /) -> int: ... - def read(self, size: int = -1, /) -> bytes: ... - def __enter__(self) -> Self: ... - -class BytesIO(BufferedIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of methods in the base classes - def __init__(self, initial_bytes: ReadableBuffer = ...) -> None: ... - # BytesIO does not contain a "name" field. This workaround is necessary - # to allow BytesIO sub-classes to add this field, as it is defined - # as a read-only property on IO[]. - name: Any - def __enter__(self) -> Self: ... - def getvalue(self) -> bytes: ... - def getbuffer(self) -> memoryview: ... - def read1(self, size: int | None = -1, /) -> bytes: ... - -class BufferedReader(BufferedIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of methods in the base classes - raw: RawIOBase - def __enter__(self) -> Self: ... - def __init__(self, raw: RawIOBase, buffer_size: int = ...) -> None: ... - def peek(self, size: int = 0, /) -> bytes: ... - -class BufferedWriter(BufferedIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of writelines in the base classes - raw: RawIOBase - def __enter__(self) -> Self: ... - def __init__(self, raw: RawIOBase, buffer_size: int = ...) -> None: ... - def write(self, buffer: ReadableBuffer, /) -> int: ... - -class BufferedRandom(BufferedReader, BufferedWriter): # type: ignore[misc] # incompatible definitions of methods in the base classes - def __enter__(self) -> Self: ... - def seek(self, target: int, whence: int = 0, /) -> int: ... # stubtest needs this - -class BufferedRWPair(BufferedIOBase): - def __init__(self, reader: RawIOBase, writer: RawIOBase, buffer_size: int = ...) -> None: ... - def peek(self, size: int = ..., /) -> bytes: ... - -class TextIOBase(IOBase): - encoding: str - errors: str | None - newlines: str | tuple[str, ...] | None - def __iter__(self) -> Iterator[str]: ... # type: ignore[override] - def __next__(self) -> str: ... # type: ignore[override] - def detach(self) -> BinaryIO: ... - def write(self, s: str, /) -> int: ... - def writelines(self, lines: Iterable[str], /) -> None: ... # type: ignore[override] - def readline(self, size: int = ..., /) -> str: ... # type: ignore[override] - def readlines(self, hint: int = -1, /) -> list[str]: ... # type: ignore[override] - def read(self, size: int | None = ..., /) -> str: ... - -@type_check_only -class _WrappedBuffer(Protocol): - # "name" is wrapped by TextIOWrapper. Its type is inconsistent between - # the various I/O types, see the comments on TextIOWrapper.name and - # TextIO.name. - @property - def name(self) -> Any: ... - @property - def closed(self) -> bool: ... - def read(self, size: int = ..., /) -> ReadableBuffer: ... - # Optional: def read1(self, size: int, /) -> ReadableBuffer: ... - def write(self, b: bytes, /) -> object: ... - def flush(self) -> object: ... - def close(self) -> object: ... - def seekable(self) -> bool: ... - def readable(self) -> bool: ... - def writable(self) -> bool: ... - def truncate(self, size: int, /) -> int: ... - def fileno(self) -> int: ... - def isatty(self) -> bool: ... - # Optional: Only needs to be present if seekable() returns True. - # def seek(self, offset: Literal[0], whence: Literal[2]) -> int: ... - # def tell(self) -> int: ... - -_BufferT_co = TypeVar("_BufferT_co", bound=_WrappedBuffer, default=_WrappedBuffer, covariant=True) - -class TextIOWrapper(TextIOBase, TextIO, Generic[_BufferT_co]): # type: ignore[misc] # incompatible definitions of write in the base classes - def __init__( - self, - buffer: _BufferT_co, - encoding: str | None = None, - errors: str | None = None, - newline: str | None = None, - line_buffering: bool = False, - write_through: bool = False, - ) -> None: ... - # Equals the "buffer" argument passed in to the constructor. - @property - def buffer(self) -> _BufferT_co: ... # type: ignore[override] - @property - def closed(self) -> bool: ... - @property - def line_buffering(self) -> bool: ... - @property - def write_through(self) -> bool: ... - def reconfigure( - self, - *, - encoding: str | None = None, - errors: str | None = None, - newline: str | None = None, - line_buffering: bool | None = None, - write_through: bool | None = None, - ) -> None: ... - # These are inherited from TextIOBase, but must exist in the stub to satisfy mypy. - def __enter__(self) -> Self: ... - def __iter__(self) -> Iterator[str]: ... # type: ignore[override] - def __next__(self) -> str: ... # type: ignore[override] - def writelines(self, lines: Iterable[str], /) -> None: ... # type: ignore[override] - def readline(self, size: int = -1, /) -> str: ... # type: ignore[override] - def readlines(self, hint: int = -1, /) -> list[str]: ... # type: ignore[override] - # Equals the "buffer" argument passed in to the constructor. - def detach(self) -> _BufferT_co: ... # type: ignore[override] - # TextIOWrapper's version of seek only supports a limited subset of - # operations. - def seek(self, cookie: int, whence: int = 0, /) -> int: ... - -class StringIO(TextIOWrapper): - def __init__(self, initial_value: str | None = ..., newline: str | None = ...) -> None: ... - # StringIO does not contain a "name" field. This workaround is necessary - # to allow StringIO sub-classes to add this field, as it is defined - # as a read-only property on IO[]. - name: Any - def getvalue(self) -> str: ... - -class IncrementalNewlineDecoder(codecs.IncrementalDecoder): - def __init__(self, decoder: codecs.IncrementalDecoder | None, translate: bool, errors: str = ...) -> None: ... - def decode(self, input: ReadableBuffer | str, final: bool = False) -> str: ... - @property - def newlines(self) -> str | tuple[str, ...] | None: ... - def setstate(self, state: tuple[bytes, int], /) -> None: ... - -if sys.version_info >= (3, 10): - @overload - def text_encoding(encoding: None, stacklevel: int = 2, /) -> Literal["locale", "utf-8"]: ... - @overload - def text_encoding(encoding: _T, stacklevel: int = 2, /) -> _T: ... +class IOBase(_IOBase, metaclass=abc.ABCMeta): ... +class RawIOBase(_RawIOBase, IOBase): ... +class BufferedIOBase(_BufferedIOBase, IOBase): ... +class TextIOBase(_TextIOBase, IOBase): ... diff --git a/mypy/typeshed/stdlib/ipaddress.pyi b/mypy/typeshed/stdlib/ipaddress.pyi index f51ea87dcfcf..f5cee43d6b32 100644 --- a/mypy/typeshed/stdlib/ipaddress.pyi +++ b/mypy/typeshed/stdlib/ipaddress.pyi @@ -1,6 +1,6 @@ import sys from collections.abc import Iterable, Iterator -from typing import Any, Final, Generic, Literal, SupportsInt, TypeVar, overload +from typing import Any, Final, Generic, Literal, TypeVar, overload from typing_extensions import Self, TypeAlias # Undocumented length constants @@ -31,7 +31,7 @@ class _IPAddressBase: @property def version(self) -> int: ... -class _BaseAddress(_IPAddressBase, SupportsInt): +class _BaseAddress(_IPAddressBase): def __init__(self, address: object) -> None: ... def __add__(self, other: int) -> Self: ... def __hash__(self) -> int: ... @@ -51,25 +51,6 @@ class _BaseAddress(_IPAddressBase, SupportsInt): def __gt__(self, other: Self, NotImplemented: Any = ...) -> bool: ... def __le__(self, other: Self, NotImplemented: Any = ...) -> bool: ... - @property - def is_global(self) -> bool: ... - @property - def is_link_local(self) -> bool: ... - @property - def is_loopback(self) -> bool: ... - @property - def is_multicast(self) -> bool: ... - @property - def is_private(self) -> bool: ... - @property - def is_reserved(self) -> bool: ... - @property - def is_unspecified(self) -> bool: ... - @property - def max_prefixlen(self) -> int: ... - @property - def packed(self) -> bytes: ... - class _BaseNetwork(_IPAddressBase, Generic[_A]): network_address: _A netmask: _A @@ -109,8 +90,6 @@ class _BaseNetwork(_IPAddressBase, Generic[_A]): @property def is_unspecified(self) -> bool: ... @property - def max_prefixlen(self) -> int: ... - @property def num_addresses(self) -> int: ... def overlaps(self, other: _BaseNetwork[IPv4Address] | _BaseNetwork[IPv6Address]) -> bool: ... @property @@ -128,19 +107,6 @@ class _BaseNetwork(_IPAddressBase, Generic[_A]): @property def hostmask(self) -> _A: ... -class _BaseInterface(_BaseAddress, Generic[_A, _N]): - hostmask: _A - netmask: _A - network: _N - @property - def ip(self) -> _A: ... - @property - def with_hostmask(self) -> str: ... - @property - def with_netmask(self) -> str: ... - @property - def with_prefixlen(self) -> str: ... - class _BaseV4: @property def version(self) -> Literal[4]: ... @@ -148,15 +114,43 @@ class _BaseV4: def max_prefixlen(self) -> Literal[32]: ... class IPv4Address(_BaseV4, _BaseAddress): + @property + def is_global(self) -> bool: ... + @property + def is_link_local(self) -> bool: ... + @property + def is_loopback(self) -> bool: ... + @property + def is_multicast(self) -> bool: ... + @property + def is_private(self) -> bool: ... + @property + def is_reserved(self) -> bool: ... + @property + def is_unspecified(self) -> bool: ... + @property + def packed(self) -> bytes: ... if sys.version_info >= (3, 13): @property def ipv6_mapped(self) -> IPv6Address: ... class IPv4Network(_BaseV4, _BaseNetwork[IPv4Address]): ... -class IPv4Interface(IPv4Address, _BaseInterface[IPv4Address, IPv4Network]): +class IPv4Interface(IPv4Address): + netmask: IPv4Address + network: IPv4Network def __eq__(self, other: object) -> bool: ... def __hash__(self) -> int: ... + @property + def hostmask(self) -> IPv4Address: ... + @property + def ip(self) -> IPv4Address: ... + @property + def with_hostmask(self) -> str: ... + @property + def with_netmask(self) -> str: ... + @property + def with_prefixlen(self) -> str: ... class _BaseV6: @property @@ -165,6 +159,22 @@ class _BaseV6: def max_prefixlen(self) -> Literal[128]: ... class IPv6Address(_BaseV6, _BaseAddress): + @property + def is_global(self) -> bool: ... + @property + def is_link_local(self) -> bool: ... + @property + def is_loopback(self) -> bool: ... + @property + def is_multicast(self) -> bool: ... + @property + def is_private(self) -> bool: ... + @property + def is_reserved(self) -> bool: ... + @property + def is_unspecified(self) -> bool: ... + @property + def packed(self) -> bytes: ... @property def ipv4_mapped(self) -> IPv4Address | None: ... @property @@ -184,9 +194,21 @@ class IPv6Network(_BaseV6, _BaseNetwork[IPv6Address]): @property def is_site_local(self) -> bool: ... -class IPv6Interface(IPv6Address, _BaseInterface[IPv6Address, IPv6Network]): +class IPv6Interface(IPv6Address): + netmask: IPv6Address + network: IPv6Network def __eq__(self, other: object) -> bool: ... def __hash__(self) -> int: ... + @property + def hostmask(self) -> IPv6Address: ... + @property + def ip(self) -> IPv6Address: ... + @property + def with_hostmask(self) -> str: ... + @property + def with_netmask(self) -> str: ... + @property + def with_prefixlen(self) -> str: ... def v4_int_to_packed(address: int) -> bytes: ... def v6_int_to_packed(address: int) -> bytes: ... diff --git a/mypy/typeshed/stdlib/itertools.pyi b/mypy/typeshed/stdlib/itertools.pyi index 1635b6a0a072..013c3cba120f 100644 --- a/mypy/typeshed/stdlib/itertools.pyi +++ b/mypy/typeshed/stdlib/itertools.pyi @@ -1,4 +1,5 @@ import sys +from _typeshed import MaybeNone from collections.abc import Callable, Iterable, Iterator from typing import Any, Generic, Literal, SupportsComplex, SupportsFloat, SupportsIndex, SupportsInt, TypeVar, overload from typing_extensions import Self, TypeAlias @@ -28,7 +29,7 @@ _Predicate: TypeAlias = Callable[[_T], object] # Technically count can take anything that implements a number protocol and has an add method # but we can't enforce the add method -class count(Iterator[_N]): +class count(Generic[_N]): @overload def __new__(cls) -> count[int]: ... @overload @@ -38,12 +39,12 @@ class count(Iterator[_N]): def __next__(self) -> _N: ... def __iter__(self) -> Self: ... -class cycle(Iterator[_T]): +class cycle(Generic[_T]): def __init__(self, iterable: Iterable[_T], /) -> None: ... def __next__(self) -> _T: ... def __iter__(self) -> Self: ... -class repeat(Iterator[_T]): +class repeat(Generic[_T]): @overload def __init__(self, object: _T) -> None: ... @overload @@ -52,7 +53,7 @@ class repeat(Iterator[_T]): def __iter__(self) -> Self: ... def __length_hint__(self) -> int: ... -class accumulate(Iterator[_T]): +class accumulate(Generic[_T]): @overload def __init__(self, iterable: Iterable[_T], func: None = None, *, initial: _T | None = ...) -> None: ... @overload @@ -60,7 +61,7 @@ class accumulate(Iterator[_T]): def __iter__(self) -> Self: ... def __next__(self) -> _T: ... -class chain(Iterator[_T]): +class chain(Generic[_T]): def __init__(self, *iterables: Iterable[_T]) -> None: ... def __next__(self) -> _T: ... def __iter__(self) -> Self: ... @@ -70,22 +71,22 @@ class chain(Iterator[_T]): if sys.version_info >= (3, 9): def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... -class compress(Iterator[_T]): +class compress(Generic[_T]): def __init__(self, data: Iterable[_T], selectors: Iterable[Any]) -> None: ... def __iter__(self) -> Self: ... def __next__(self) -> _T: ... -class dropwhile(Iterator[_T]): +class dropwhile(Generic[_T]): def __init__(self, predicate: _Predicate[_T], iterable: Iterable[_T], /) -> None: ... def __iter__(self) -> Self: ... def __next__(self) -> _T: ... -class filterfalse(Iterator[_T]): +class filterfalse(Generic[_T]): def __init__(self, predicate: _Predicate[_T] | None, iterable: Iterable[_T], /) -> None: ... def __iter__(self) -> Self: ... def __next__(self) -> _T: ... -class groupby(Iterator[tuple[_T_co, Iterator[_S_co]]], Generic[_T_co, _S_co]): +class groupby(Generic[_T_co, _S_co]): @overload def __new__(cls, iterable: Iterable[_T1], key: None = None) -> groupby[_T1, _T1]: ... @overload @@ -93,7 +94,7 @@ class groupby(Iterator[tuple[_T_co, Iterator[_S_co]]], Generic[_T_co, _S_co]): def __iter__(self) -> Self: ... def __next__(self) -> tuple[_T_co, Iterator[_S_co]]: ... -class islice(Iterator[_T]): +class islice(Generic[_T]): @overload def __init__(self, iterable: Iterable[_T], stop: int | None, /) -> None: ... @overload @@ -101,19 +102,19 @@ class islice(Iterator[_T]): def __iter__(self) -> Self: ... def __next__(self) -> _T: ... -class starmap(Iterator[_T_co]): +class starmap(Generic[_T_co]): def __new__(cls, function: Callable[..., _T], iterable: Iterable[Iterable[Any]], /) -> starmap[_T]: ... def __iter__(self) -> Self: ... def __next__(self) -> _T_co: ... -class takewhile(Iterator[_T]): +class takewhile(Generic[_T]): def __init__(self, predicate: _Predicate[_T], iterable: Iterable[_T], /) -> None: ... def __iter__(self) -> Self: ... def __next__(self) -> _T: ... def tee(iterable: Iterable[_T], n: int = 2, /) -> tuple[Iterator[_T], ...]: ... -class zip_longest(Iterator[_T_co]): +class zip_longest(Generic[_T_co]): # one iterable (fillvalue doesn't matter) @overload def __new__(cls, iter1: Iterable[_T1], /, *, fillvalue: object = ...) -> zip_longest[tuple[_T1]]: ... @@ -122,7 +123,7 @@ class zip_longest(Iterator[_T_co]): # In the overloads without fillvalue, all of the tuple members could theoretically be None, # but we return Any instead to avoid false positives for code where we know one of the iterables # is longer. - def __new__(cls, iter1: Iterable[_T1], iter2: Iterable[_T2], /) -> zip_longest[tuple[_T1 | Any, _T2 | Any]]: ... + def __new__(cls, iter1: Iterable[_T1], iter2: Iterable[_T2], /) -> zip_longest[tuple[_T1 | MaybeNone, _T2 | MaybeNone]]: ... @overload def __new__( cls, iter1: Iterable[_T1], iter2: Iterable[_T2], /, *, fillvalue: _T @@ -131,7 +132,7 @@ class zip_longest(Iterator[_T_co]): @overload def __new__( cls, iter1: Iterable[_T1], iter2: Iterable[_T2], iter3: Iterable[_T3], / - ) -> zip_longest[tuple[_T1 | Any, _T2 | Any, _T3 | Any]]: ... + ) -> zip_longest[tuple[_T1 | MaybeNone, _T2 | MaybeNone, _T3 | MaybeNone]]: ... @overload def __new__( cls, iter1: Iterable[_T1], iter2: Iterable[_T2], iter3: Iterable[_T3], /, *, fillvalue: _T @@ -140,7 +141,7 @@ class zip_longest(Iterator[_T_co]): @overload def __new__( cls, iter1: Iterable[_T1], iter2: Iterable[_T2], iter3: Iterable[_T3], iter4: Iterable[_T4], / - ) -> zip_longest[tuple[_T1 | Any, _T2 | Any, _T3 | Any, _T4 | Any]]: ... + ) -> zip_longest[tuple[_T1 | MaybeNone, _T2 | MaybeNone, _T3 | MaybeNone, _T4 | MaybeNone]]: ... @overload def __new__( cls, iter1: Iterable[_T1], iter2: Iterable[_T2], iter3: Iterable[_T3], iter4: Iterable[_T4], /, *, fillvalue: _T @@ -149,7 +150,7 @@ class zip_longest(Iterator[_T_co]): @overload def __new__( cls, iter1: Iterable[_T1], iter2: Iterable[_T2], iter3: Iterable[_T3], iter4: Iterable[_T4], iter5: Iterable[_T5], / - ) -> zip_longest[tuple[_T1 | Any, _T2 | Any, _T3 | Any, _T4 | Any, _T5 | Any]]: ... + ) -> zip_longest[tuple[_T1 | MaybeNone, _T2 | MaybeNone, _T3 | MaybeNone, _T4 | MaybeNone, _T5 | MaybeNone]]: ... @overload def __new__( cls, @@ -174,7 +175,7 @@ class zip_longest(Iterator[_T_co]): iter6: Iterable[_T], /, *iterables: Iterable[_T], - ) -> zip_longest[tuple[_T | Any, ...]]: ... + ) -> zip_longest[tuple[_T | MaybeNone, ...]]: ... @overload def __new__( cls, @@ -191,7 +192,7 @@ class zip_longest(Iterator[_T_co]): def __iter__(self) -> Self: ... def __next__(self) -> _T_co: ... -class product(Iterator[_T_co]): +class product(Generic[_T_co]): @overload def __new__(cls, iter1: Iterable[_T1], /) -> product[tuple[_T1]]: ... @overload @@ -276,7 +277,7 @@ class product(Iterator[_T_co]): def __iter__(self) -> Self: ... def __next__(self) -> _T_co: ... -class permutations(Iterator[_T_co]): +class permutations(Generic[_T_co]): @overload def __new__(cls, iterable: Iterable[_T], r: Literal[2]) -> permutations[tuple[_T, _T]]: ... @overload @@ -290,7 +291,7 @@ class permutations(Iterator[_T_co]): def __iter__(self) -> Self: ... def __next__(self) -> _T_co: ... -class combinations(Iterator[_T_co]): +class combinations(Generic[_T_co]): @overload def __new__(cls, iterable: Iterable[_T], r: Literal[2]) -> combinations[tuple[_T, _T]]: ... @overload @@ -304,7 +305,7 @@ class combinations(Iterator[_T_co]): def __iter__(self) -> Self: ... def __next__(self) -> _T_co: ... -class combinations_with_replacement(Iterator[_T_co]): +class combinations_with_replacement(Generic[_T_co]): @overload def __new__(cls, iterable: Iterable[_T], r: Literal[2]) -> combinations_with_replacement[tuple[_T, _T]]: ... @overload @@ -319,13 +320,13 @@ class combinations_with_replacement(Iterator[_T_co]): def __next__(self) -> _T_co: ... if sys.version_info >= (3, 10): - class pairwise(Iterator[_T_co]): + class pairwise(Generic[_T_co]): def __new__(cls, iterable: Iterable[_T], /) -> pairwise[tuple[_T, _T]]: ... def __iter__(self) -> Self: ... def __next__(self) -> _T_co: ... if sys.version_info >= (3, 12): - class batched(Iterator[tuple[_T_co, ...]], Generic[_T_co]): + class batched(Generic[_T_co]): if sys.version_info >= (3, 13): def __new__(cls, iterable: Iterable[_T_co], n: int, *, strict: bool = False) -> Self: ... else: diff --git a/mypy/typeshed/stdlib/json/scanner.pyi b/mypy/typeshed/stdlib/json/scanner.pyi new file mode 100644 index 000000000000..f3b98996b752 --- /dev/null +++ b/mypy/typeshed/stdlib/json/scanner.pyi @@ -0,0 +1,3 @@ +from _json import make_scanner as make_scanner + +__all__ = ["make_scanner"] diff --git a/mypy/typeshed/stdlib/logging/config.pyi b/mypy/typeshed/stdlib/logging/config.pyi index 83fe7461cb5c..5c444e66c4c7 100644 --- a/mypy/typeshed/stdlib/logging/config.pyi +++ b/mypy/typeshed/stdlib/logging/config.pyi @@ -1,6 +1,6 @@ import sys from _typeshed import StrOrBytesPath -from collections.abc import Callable, Hashable, Iterable, Sequence +from collections.abc import Callable, Hashable, Iterable, Mapping, Sequence from configparser import RawConfigParser from re import Pattern from threading import Thread @@ -63,7 +63,7 @@ def dictConfig(config: _DictConfigArgs | dict[str, Any]) -> None: ... if sys.version_info >= (3, 10): def fileConfig( fname: StrOrBytesPath | IO[str] | RawConfigParser, - defaults: dict[str, str] | None = None, + defaults: Mapping[str, str] | None = None, disable_existing_loggers: bool = True, encoding: str | None = None, ) -> None: ... @@ -71,7 +71,7 @@ if sys.version_info >= (3, 10): else: def fileConfig( fname: StrOrBytesPath | IO[str] | RawConfigParser, - defaults: dict[str, str] | None = None, + defaults: Mapping[str, str] | None = None, disable_existing_loggers: bool = True, ) -> None: ... @@ -116,7 +116,7 @@ class BaseConfigurator: # undocumented def cfg_convert(self, value: str) -> Any: ... def convert(self, value: Any) -> Any: ... def configure_custom(self, config: dict[str, Any]) -> Any: ... - def as_tuple(self, value: list[Any] | tuple[Any]) -> tuple[Any]: ... + def as_tuple(self, value: list[Any] | tuple[Any, ...]) -> tuple[Any, ...]: ... class DictConfigurator(BaseConfigurator): def configure(self) -> None: ... # undocumented diff --git a/mypy/typeshed/stdlib/logging/handlers.pyi b/mypy/typeshed/stdlib/logging/handlers.pyi index 91f9fe57e46f..d594d6569a7e 100644 --- a/mypy/typeshed/stdlib/logging/handlers.pyi +++ b/mypy/typeshed/stdlib/logging/handlers.pyi @@ -260,6 +260,8 @@ class QueueHandler(Handler): def __init__(self, queue: _QueueLike[Any]) -> None: ... def prepare(self, record: LogRecord) -> Any: ... def enqueue(self, record: LogRecord) -> None: ... + if sys.version_info >= (3, 12): + listener: QueueListener | None class QueueListener: handlers: tuple[Handler, ...] # undocumented diff --git a/mypy/typeshed/stdlib/lzma.pyi b/mypy/typeshed/stdlib/lzma.pyi index 2df2b9a8bd6a..2f0279f5986b 100644 --- a/mypy/typeshed/stdlib/lzma.pyi +++ b/mypy/typeshed/stdlib/lzma.pyi @@ -1,7 +1,41 @@ from _compression import BaseStream +from _lzma import ( + CHECK_CRC32 as CHECK_CRC32, + CHECK_CRC64 as CHECK_CRC64, + CHECK_ID_MAX as CHECK_ID_MAX, + CHECK_NONE as CHECK_NONE, + CHECK_SHA256 as CHECK_SHA256, + CHECK_UNKNOWN as CHECK_UNKNOWN, + FILTER_ARM as FILTER_ARM, + FILTER_ARMTHUMB as FILTER_ARMTHUMB, + FILTER_DELTA as FILTER_DELTA, + FILTER_IA64 as FILTER_IA64, + FILTER_LZMA1 as FILTER_LZMA1, + FILTER_LZMA2 as FILTER_LZMA2, + FILTER_POWERPC as FILTER_POWERPC, + FILTER_SPARC as FILTER_SPARC, + FILTER_X86 as FILTER_X86, + FORMAT_ALONE as FORMAT_ALONE, + FORMAT_AUTO as FORMAT_AUTO, + FORMAT_RAW as FORMAT_RAW, + FORMAT_XZ as FORMAT_XZ, + MF_BT2 as MF_BT2, + MF_BT3 as MF_BT3, + MF_BT4 as MF_BT4, + MF_HC3 as MF_HC3, + MF_HC4 as MF_HC4, + MODE_FAST as MODE_FAST, + MODE_NORMAL as MODE_NORMAL, + PRESET_DEFAULT as PRESET_DEFAULT, + PRESET_EXTREME as PRESET_EXTREME, + LZMACompressor as LZMACompressor, + LZMADecompressor as LZMADecompressor, + LZMAError as LZMAError, + _FilterChain, + is_check_supported as is_check_supported, +) from _typeshed import ReadableBuffer, StrOrBytesPath -from collections.abc import Mapping, Sequence -from typing import IO, Any, Final, Literal, TextIO, final, overload +from typing import IO, Literal, TextIO, overload from typing_extensions import Self, TypeAlias __all__ = [ @@ -48,62 +82,6 @@ _OpenTextWritingMode: TypeAlias = Literal["wt", "xt", "at"] _PathOrFile: TypeAlias = StrOrBytesPath | IO[bytes] -_FilterChain: TypeAlias = Sequence[Mapping[str, Any]] - -FORMAT_AUTO: Final = 0 -FORMAT_XZ: Final = 1 -FORMAT_ALONE: Final = 2 -FORMAT_RAW: Final = 3 -CHECK_NONE: Final = 0 -CHECK_CRC32: Final = 1 -CHECK_CRC64: Final = 4 -CHECK_SHA256: Final = 10 -CHECK_ID_MAX: Final = 15 -CHECK_UNKNOWN: Final = 16 -FILTER_LZMA1: int # v big number -FILTER_LZMA2: Final = 33 -FILTER_DELTA: Final = 3 -FILTER_X86: Final = 4 -FILTER_IA64: Final = 6 -FILTER_ARM: Final = 7 -FILTER_ARMTHUMB: Final = 8 -FILTER_SPARC: Final = 9 -FILTER_POWERPC: Final = 5 -MF_HC3: Final = 3 -MF_HC4: Final = 4 -MF_BT2: Final = 18 -MF_BT3: Final = 19 -MF_BT4: Final = 20 -MODE_FAST: Final = 1 -MODE_NORMAL: Final = 2 -PRESET_DEFAULT: Final = 6 -PRESET_EXTREME: int # v big number - -# from _lzma.c -@final -class LZMADecompressor: - def __init__(self, format: int | None = ..., memlimit: int | None = ..., filters: _FilterChain | None = ...) -> None: ... - def decompress(self, data: ReadableBuffer, max_length: int = -1) -> bytes: ... - @property - def check(self) -> int: ... - @property - def eof(self) -> bool: ... - @property - def unused_data(self) -> bytes: ... - @property - def needs_input(self) -> bool: ... - -# from _lzma.c -@final -class LZMACompressor: - def __init__( - self, format: int | None = ..., check: int = ..., preset: int | None = ..., filters: _FilterChain | None = ... - ) -> None: ... - def compress(self, data: ReadableBuffer, /) -> bytes: ... - def flush(self) -> bytes: ... - -class LZMAError(Exception): ... - class LZMAFile(BaseStream, IO[bytes]): # type: ignore[misc] # incompatible definitions of writelines in the base classes def __init__( self, @@ -194,4 +172,3 @@ def compress( def decompress( data: ReadableBuffer, format: int = 0, memlimit: int | None = None, filters: _FilterChain | None = None ) -> bytes: ... -def is_check_supported(check_id: int, /) -> bool: ... diff --git a/mypy/typeshed/stdlib/mmap.pyi b/mypy/typeshed/stdlib/mmap.pyi index a0c150d6e7e8..f94e876237d1 100644 --- a/mypy/typeshed/stdlib/mmap.pyi +++ b/mypy/typeshed/stdlib/mmap.pyi @@ -1,6 +1,6 @@ import sys from _typeshed import ReadableBuffer, Unused -from collections.abc import Iterable, Iterator, Sized +from collections.abc import Iterator from typing import Final, Literal, NoReturn, overload from typing_extensions import Self @@ -30,13 +30,26 @@ if sys.platform != "win32": PAGESIZE: int -class mmap(Iterable[int], Sized): +class mmap: if sys.platform == "win32": def __init__(self, fileno: int, length: int, tagname: str | None = ..., access: int = ..., offset: int = ...) -> None: ... else: - def __init__( - self, fileno: int, length: int, flags: int = ..., prot: int = ..., access: int = ..., offset: int = ... - ) -> None: ... + if sys.version_info >= (3, 13): + def __init__( + self, + fileno: int, + length: int, + flags: int = ..., + prot: int = ..., + access: int = ..., + offset: int = ..., + *, + trackfd: bool = True, + ) -> None: ... + else: + def __init__( + self, fileno: int, length: int, flags: int = ..., prot: int = ..., access: int = ..., offset: int = ... + ) -> None: ... def close(self) -> None: ... def flush(self, offset: int = ..., size: int = ...) -> None: ... diff --git a/mypy/typeshed/stdlib/modulefinder.pyi b/mypy/typeshed/stdlib/modulefinder.pyi index 2cf948ba898a..6db665a18e69 100644 --- a/mypy/typeshed/stdlib/modulefinder.pyi +++ b/mypy/typeshed/stdlib/modulefinder.pyi @@ -64,3 +64,5 @@ class ModuleFinder: def any_missing(self) -> list[str]: ... # undocumented def any_missing_maybe(self) -> tuple[list[str], list[str]]: ... # undocumented def replace_paths_in_code(self, co: CodeType) -> CodeType: ... # undocumented + +def test() -> ModuleFinder | None: ... # undocumented diff --git a/mypy/typeshed/stdlib/multiprocessing/connection.pyi b/mypy/typeshed/stdlib/multiprocessing/connection.pyi index 7045a81b85be..9998239d3119 100644 --- a/mypy/typeshed/stdlib/multiprocessing/connection.pyi +++ b/mypy/typeshed/stdlib/multiprocessing/connection.pyi @@ -1,9 +1,9 @@ import socket import sys -import types -from _typeshed import ReadableBuffer +from _typeshed import Incomplete, ReadableBuffer from collections.abc import Iterable -from typing import Any, SupportsIndex +from types import TracebackType +from typing import Any, Generic, SupportsIndex, TypeVar from typing_extensions import Self, TypeAlias __all__ = ["Client", "Listener", "Pipe", "wait"] @@ -11,7 +11,11 @@ __all__ = ["Client", "Listener", "Pipe", "wait"] # https://docs.python.org/3/library/multiprocessing.html#address-formats _Address: TypeAlias = str | tuple[str, int] -class _ConnectionBase: +# Defaulting to Any to avoid forcing generics on a lot of pre-existing code +_SendT = TypeVar("_SendT", contravariant=True, default=Any) +_RecvT = TypeVar("_RecvT", covariant=True, default=Any) + +class _ConnectionBase(Generic[_SendT, _RecvT]): def __init__(self, handle: SupportsIndex, readable: bool = True, writable: bool = True) -> None: ... @property def closed(self) -> bool: ... # undocumented @@ -22,27 +26,27 @@ class _ConnectionBase: def fileno(self) -> int: ... def close(self) -> None: ... def send_bytes(self, buf: ReadableBuffer, offset: int = 0, size: int | None = None) -> None: ... - def send(self, obj: Any) -> None: ... + def send(self, obj: _SendT) -> None: ... def recv_bytes(self, maxlength: int | None = None) -> bytes: ... def recv_bytes_into(self, buf: Any, offset: int = 0) -> int: ... - def recv(self) -> Any: ... + def recv(self) -> _RecvT: ... def poll(self, timeout: float | None = 0.0) -> bool: ... def __enter__(self) -> Self: ... def __exit__( - self, exc_type: type[BaseException] | None, exc_value: BaseException | None, exc_tb: types.TracebackType | None + self, exc_type: type[BaseException] | None, exc_value: BaseException | None, exc_tb: TracebackType | None ) -> None: ... def __del__(self) -> None: ... -class Connection(_ConnectionBase): ... +class Connection(_ConnectionBase[_SendT, _RecvT]): ... if sys.platform == "win32": - class PipeConnection(_ConnectionBase): ... + class PipeConnection(_ConnectionBase[_SendT, _RecvT]): ... class Listener: def __init__( self, address: _Address | None = None, family: str | None = None, backlog: int = 1, authkey: bytes | None = None ) -> None: ... - def accept(self) -> Connection: ... + def accept(self) -> Connection[Incomplete, Incomplete]: ... def close(self) -> None: ... @property def address(self) -> _Address: ... @@ -50,26 +54,30 @@ class Listener: def last_accepted(self) -> _Address | None: ... def __enter__(self) -> Self: ... def __exit__( - self, exc_type: type[BaseException] | None, exc_value: BaseException | None, exc_tb: types.TracebackType | None + self, exc_type: type[BaseException] | None, exc_value: BaseException | None, exc_tb: TracebackType | None ) -> None: ... +# Any: send and recv methods unused if sys.version_info >= (3, 12): - def deliver_challenge(connection: Connection, authkey: bytes, digest_name: str = "sha256") -> None: ... + def deliver_challenge(connection: Connection[Any, Any], authkey: bytes, digest_name: str = "sha256") -> None: ... else: - def deliver_challenge(connection: Connection, authkey: bytes) -> None: ... + def deliver_challenge(connection: Connection[Any, Any], authkey: bytes) -> None: ... -def answer_challenge(connection: Connection, authkey: bytes) -> None: ... +def answer_challenge(connection: Connection[Any, Any], authkey: bytes) -> None: ... def wait( - object_list: Iterable[Connection | socket.socket | int], timeout: float | None = None -) -> list[Connection | socket.socket | int]: ... -def Client(address: _Address, family: str | None = None, authkey: bytes | None = None) -> Connection: ... + object_list: Iterable[Connection[_SendT, _RecvT] | socket.socket | int], timeout: float | None = None +) -> list[Connection[_SendT, _RecvT] | socket.socket | int]: ... +def Client(address: _Address, family: str | None = None, authkey: bytes | None = None) -> Connection[Any, Any]: ... # N.B. Keep this in sync with multiprocessing.context.BaseContext.Pipe. # _ConnectionBase is the common base class of Connection and PipeConnection # and can be used in cross-platform code. +# +# The two connections should have the same generic types but inverted (Connection[_T1, _T2], Connection[_T2, _T1]). +# However, TypeVars scoped entirely within a return annotation is unspecified in the spec. if sys.platform != "win32": - def Pipe(duplex: bool = True) -> tuple[Connection, Connection]: ... + def Pipe(duplex: bool = True) -> tuple[Connection[Any, Any], Connection[Any, Any]]: ... else: - def Pipe(duplex: bool = True) -> tuple[PipeConnection, PipeConnection]: ... + def Pipe(duplex: bool = True) -> tuple[PipeConnection[Any, Any], PipeConnection[Any, Any]]: ... diff --git a/mypy/typeshed/stdlib/multiprocessing/context.pyi b/mypy/typeshed/stdlib/multiprocessing/context.pyi index 605be4686c1f..03d1d2e5c220 100644 --- a/mypy/typeshed/stdlib/multiprocessing/context.pyi +++ b/mypy/typeshed/stdlib/multiprocessing/context.pyi @@ -1,7 +1,8 @@ import ctypes import sys +from _ctypes import _CData from collections.abc import Callable, Iterable, Sequence -from ctypes import _CData, _SimpleCData, c_char +from ctypes import _SimpleCData, c_char from logging import Logger, _Level as _LoggingLevel from multiprocessing import popen_fork, popen_forkserver, popen_spawn_posix, popen_spawn_win32, queues, synchronize from multiprocessing.managers import SyncManager @@ -47,10 +48,13 @@ class BaseContext: # N.B. Keep this in sync with multiprocessing.connection.Pipe. # _ConnectionBase is the common base class of Connection and PipeConnection # and can be used in cross-platform code. + # + # The two connections should have the same generic types but inverted (Connection[_T1, _T2], Connection[_T2, _T1]). + # However, TypeVars scoped entirely within a return annotation is unspecified in the spec. if sys.platform != "win32": - def Pipe(self, duplex: bool = True) -> tuple[Connection, Connection]: ... + def Pipe(self, duplex: bool = True) -> tuple[Connection[Any, Any], Connection[Any, Any]]: ... else: - def Pipe(self, duplex: bool = True) -> tuple[PipeConnection, PipeConnection]: ... + def Pipe(self, duplex: bool = True) -> tuple[PipeConnection[Any, Any], PipeConnection[Any, Any]]: ... def Barrier( self, parties: int, action: Callable[..., object] | None = None, timeout: float | None = None diff --git a/mypy/typeshed/stdlib/multiprocessing/managers.pyi b/mypy/typeshed/stdlib/multiprocessing/managers.pyi index 5d5b9cdcb913..1669c5f09f97 100644 --- a/mypy/typeshed/stdlib/multiprocessing/managers.pyi +++ b/mypy/typeshed/stdlib/multiprocessing/managers.pyi @@ -1,7 +1,7 @@ import queue import sys import threading -from _typeshed import SupportsKeysAndGetItem, SupportsRichComparison, SupportsRichComparisonT +from _typeshed import Incomplete, SupportsKeysAndGetItem, SupportsRichComparison, SupportsRichComparisonT from collections.abc import Callable, Iterable, Iterator, Mapping, MutableMapping, MutableSequence, Sequence from types import TracebackType from typing import Any, AnyStr, ClassVar, Generic, SupportsIndex, TypeVar, overload @@ -10,6 +10,7 @@ from typing_extensions import Self, TypeAlias from .connection import Connection from .context import BaseContext from .shared_memory import _SLT, ShareableList as _ShareableList, SharedMemory as _SharedMemory +from .util import Finalize as _Finalize __all__ = ["BaseManager", "SyncManager", "BaseProxy", "Token", "SharedMemoryManager"] @@ -60,31 +61,58 @@ class ValueProxy(BaseProxy, Generic[_T]): if sys.version_info >= (3, 9): def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... -class DictProxy(BaseProxy, MutableMapping[_KT, _VT]): - __builtins__: ClassVar[dict[str, Any]] - def __len__(self) -> int: ... - def __getitem__(self, key: _KT, /) -> _VT: ... - def __setitem__(self, key: _KT, value: _VT, /) -> None: ... - def __delitem__(self, key: _KT, /) -> None: ... - def __iter__(self) -> Iterator[_KT]: ... - def copy(self) -> dict[_KT, _VT]: ... - @overload # type: ignore[override] - def get(self, key: _KT, /) -> _VT | None: ... - @overload - def get(self, key: _KT, default: _VT, /) -> _VT: ... - @overload - def get(self, key: _KT, default: _T, /) -> _VT | _T: ... - @overload - def pop(self, key: _KT, /) -> _VT: ... - @overload - def pop(self, key: _KT, default: _VT, /) -> _VT: ... - @overload - def pop(self, key: _KT, default: _T, /) -> _VT | _T: ... - def keys(self) -> list[_KT]: ... # type: ignore[override] - def items(self) -> list[tuple[_KT, _VT]]: ... # type: ignore[override] - def values(self) -> list[_VT]: ... # type: ignore[override] - if sys.version_info >= (3, 13): - def __class_getitem__(cls, args: Any, /) -> Any: ... +if sys.version_info >= (3, 13): + class _BaseDictProxy(BaseProxy, MutableMapping[_KT, _VT]): + __builtins__: ClassVar[dict[str, Any]] + def __len__(self) -> int: ... + def __getitem__(self, key: _KT, /) -> _VT: ... + def __setitem__(self, key: _KT, value: _VT, /) -> None: ... + def __delitem__(self, key: _KT, /) -> None: ... + def __iter__(self) -> Iterator[_KT]: ... + def copy(self) -> dict[_KT, _VT]: ... + @overload # type: ignore[override] + def get(self, key: _KT, /) -> _VT | None: ... + @overload + def get(self, key: _KT, default: _VT, /) -> _VT: ... + @overload + def get(self, key: _KT, default: _T, /) -> _VT | _T: ... + @overload + def pop(self, key: _KT, /) -> _VT: ... + @overload + def pop(self, key: _KT, default: _VT, /) -> _VT: ... + @overload + def pop(self, key: _KT, default: _T, /) -> _VT | _T: ... + def keys(self) -> list[_KT]: ... # type: ignore[override] + def items(self) -> list[tuple[_KT, _VT]]: ... # type: ignore[override] + def values(self) -> list[_VT]: ... # type: ignore[override] + + class DictProxy(_BaseDictProxy[_KT, _VT]): + def __class_getitem__(cls, args: Any, /) -> GenericAlias: ... + +else: + class DictProxy(BaseProxy, MutableMapping[_KT, _VT]): + __builtins__: ClassVar[dict[str, Any]] + def __len__(self) -> int: ... + def __getitem__(self, key: _KT, /) -> _VT: ... + def __setitem__(self, key: _KT, value: _VT, /) -> None: ... + def __delitem__(self, key: _KT, /) -> None: ... + def __iter__(self) -> Iterator[_KT]: ... + def copy(self) -> dict[_KT, _VT]: ... + @overload # type: ignore[override] + def get(self, key: _KT, /) -> _VT | None: ... + @overload + def get(self, key: _KT, default: _VT, /) -> _VT: ... + @overload + def get(self, key: _KT, default: _T, /) -> _VT | _T: ... + @overload + def pop(self, key: _KT, /) -> _VT: ... + @overload + def pop(self, key: _KT, default: _VT, /) -> _VT: ... + @overload + def pop(self, key: _KT, default: _T, /) -> _VT | _T: ... + def keys(self) -> list[_KT]: ... # type: ignore[override] + def items(self) -> list[tuple[_KT, _VT]]: ... # type: ignore[override] + def values(self) -> list[_VT]: ... # type: ignore[override] class BaseListProxy(BaseProxy, MutableSequence[_T]): __builtins__: ClassVar[dict[str, Any]] @@ -129,7 +157,9 @@ class Server: self, registry: dict[str, tuple[Callable[..., Any], Any, Any, Any]], address: Any, authkey: bytes, serializer: str ) -> None: ... def serve_forever(self) -> None: ... - def accept_connection(self, c: Connection, name: str) -> None: ... + def accept_connection( + self, c: Connection[tuple[str, str | None], tuple[str, str, Iterable[Incomplete], Mapping[str, Incomplete]]], name: str + ) -> None: ... class BaseManager: if sys.version_info >= (3, 11): @@ -154,7 +184,7 @@ class BaseManager: def get_server(self) -> Server: ... def connect(self) -> None: ... def start(self, initializer: Callable[..., object] | None = None, initargs: Iterable[Any] = ()) -> None: ... - def shutdown(self) -> None: ... # only available after start() was called + shutdown: _Finalize # only available after start() was called def join(self, timeout: float | None = None) -> None: ... # undocumented @property def address(self) -> Any: ... diff --git a/mypy/typeshed/stdlib/multiprocessing/pool.pyi b/mypy/typeshed/stdlib/multiprocessing/pool.pyi index 950ed1d8c56b..61d6d0781213 100644 --- a/mypy/typeshed/stdlib/multiprocessing/pool.pyi +++ b/mypy/typeshed/stdlib/multiprocessing/pool.pyi @@ -1,5 +1,5 @@ import sys -from collections.abc import Callable, Iterable, Iterator, Mapping +from collections.abc import Callable, Iterable, Mapping from types import TracebackType from typing import Any, Final, Generic, TypeVar from typing_extensions import Self @@ -36,7 +36,7 @@ class MapResult(ApplyResult[list[_T]]): error_callback: Callable[[BaseException], object] | None, ) -> None: ... -class IMapIterator(Iterator[_T]): +class IMapIterator(Generic[_T]): def __init__(self, pool: Pool) -> None: ... def __iter__(self) -> Self: ... def next(self, timeout: float | None = None) -> _T: ... diff --git a/mypy/typeshed/stdlib/multiprocessing/reduction.pyi b/mypy/typeshed/stdlib/multiprocessing/reduction.pyi index a31987bcc3cb..473e90936d71 100644 --- a/mypy/typeshed/stdlib/multiprocessing/reduction.pyi +++ b/mypy/typeshed/stdlib/multiprocessing/reduction.pyi @@ -35,8 +35,8 @@ if sys.platform == "win32": handle: int, target_process: int | None = None, inheritable: bool = False, *, source_process: int | None = None ) -> int: ... def steal_handle(source_pid: int, handle: int) -> int: ... - def send_handle(conn: connection.PipeConnection, handle: int, destination_pid: int) -> None: ... - def recv_handle(conn: connection.PipeConnection) -> int: ... + def send_handle(conn: connection.PipeConnection[DupHandle, Any], handle: int, destination_pid: int) -> None: ... + def recv_handle(conn: connection.PipeConnection[Any, DupHandle]) -> int: ... class DupHandle: def __init__(self, handle: int, access: int, pid: int | None = None) -> None: ... diff --git a/mypy/typeshed/stdlib/multiprocessing/sharedctypes.pyi b/mypy/typeshed/stdlib/multiprocessing/sharedctypes.pyi index 2b0498abc2c6..5283445d8545 100644 --- a/mypy/typeshed/stdlib/multiprocessing/sharedctypes.pyi +++ b/mypy/typeshed/stdlib/multiprocessing/sharedctypes.pyi @@ -1,6 +1,7 @@ import ctypes +from _ctypes import _CData from collections.abc import Callable, Iterable, Sequence -from ctypes import _CData, _SimpleCData, c_char +from ctypes import _SimpleCData, c_char from multiprocessing.context import BaseContext from multiprocessing.synchronize import _LockLike from types import TracebackType diff --git a/mypy/typeshed/stdlib/multiprocessing/spawn.pyi b/mypy/typeshed/stdlib/multiprocessing/spawn.pyi index 43ce2f07d996..4a9753222897 100644 --- a/mypy/typeshed/stdlib/multiprocessing/spawn.pyi +++ b/mypy/typeshed/stdlib/multiprocessing/spawn.pyi @@ -23,7 +23,7 @@ def get_command_line(**kwds: Any) -> list[str]: ... def spawn_main(pipe_handle: int, parent_pid: int | None = None, tracker_fd: int | None = None) -> None: ... # undocumented -def _main(fd: int) -> Any: ... +def _main(fd: int, parent_sentinel: int) -> int: ... def get_preparation_data(name: str) -> dict[str, Any]: ... old_main_modules: list[ModuleType] diff --git a/mypy/typeshed/stdlib/multiprocessing/synchronize.pyi b/mypy/typeshed/stdlib/multiprocessing/synchronize.pyi index b417925fb17b..e3cbfbc0ec82 100644 --- a/mypy/typeshed/stdlib/multiprocessing/synchronize.pyi +++ b/mypy/typeshed/stdlib/multiprocessing/synchronize.pyi @@ -1,6 +1,5 @@ import threading from collections.abc import Callable -from contextlib import AbstractContextManager from multiprocessing.context import BaseContext from types import TracebackType from typing_extensions import TypeAlias @@ -11,20 +10,23 @@ _LockLike: TypeAlias = Lock | RLock class Barrier(threading.Barrier): def __init__( - self, parties: int, action: Callable[[], object] | None = None, timeout: float | None = None, *ctx: BaseContext + self, parties: int, action: Callable[[], object] | None = None, timeout: float | None = None, *, ctx: BaseContext ) -> None: ... -class Condition(AbstractContextManager[bool, None]): +class Condition: def __init__(self, lock: _LockLike | None = None, *, ctx: BaseContext) -> None: ... def notify(self, n: int = 1) -> None: ... def notify_all(self) -> None: ... def wait(self, timeout: float | None = None) -> bool: ... def wait_for(self, predicate: Callable[[], bool], timeout: float | None = None) -> bool: ... - def acquire(self, block: bool = ..., timeout: float | None = ...) -> bool: ... - def release(self) -> None: ... + def __enter__(self) -> bool: ... def __exit__( self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None, / ) -> None: ... + # These methods are copied from the lock passed to the constructor, or an + # instance of ctx.RLock() if lock was None. + def acquire(self, block: bool = True, timeout: float | None = None) -> bool: ... + def release(self) -> None: ... class Event: def __init__(self, *, ctx: BaseContext) -> None: ... @@ -34,12 +36,15 @@ class Event: def wait(self, timeout: float | None = None) -> bool: ... # Not part of public API -class SemLock(AbstractContextManager[bool, None]): - def acquire(self, block: bool = ..., timeout: float | None = ...) -> bool: ... - def release(self) -> None: ... +class SemLock: + def __init__(self, kind: int, value: int, maxvalue: int, *, ctx: BaseContext | None) -> None: ... + def __enter__(self) -> bool: ... def __exit__( self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None, / ) -> None: ... + # These methods are copied from the wrapped _multiprocessing.SemLock object + def acquire(self, block: bool = True, timeout: float | None = None) -> bool: ... + def release(self) -> None: ... class Lock(SemLock): def __init__(self, *, ctx: BaseContext) -> None: ... diff --git a/mypy/typeshed/stdlib/operator.pyi b/mypy/typeshed/stdlib/operator.pyi index 1a817f00f3c1..b73e037f3ed9 100644 --- a/mypy/typeshed/stdlib/operator.pyi +++ b/mypy/typeshed/stdlib/operator.pyi @@ -1,5 +1,66 @@ import sys -from _operator import * +from _operator import ( + abs as abs, + add as add, + and_ as and_, + concat as concat, + contains as contains, + countOf as countOf, + delitem as delitem, + eq as eq, + floordiv as floordiv, + ge as ge, + getitem as getitem, + gt as gt, + iadd as iadd, + iand as iand, + iconcat as iconcat, + ifloordiv as ifloordiv, + ilshift as ilshift, + imatmul as imatmul, + imod as imod, + imul as imul, + index as index, + indexOf as indexOf, + inv as inv, + invert as invert, + ior as ior, + ipow as ipow, + irshift as irshift, + is_ as is_, + is_not as is_not, + isub as isub, + itruediv as itruediv, + ixor as ixor, + le as le, + length_hint as length_hint, + lshift as lshift, + lt as lt, + matmul as matmul, + mod as mod, + mul as mul, + ne as ne, + neg as neg, + not_ as not_, + or_ as or_, + pos as pos, + pow as pow, + rshift as rshift, + setitem as setitem, + sub as sub, + truediv as truediv, + truth as truth, + xor as xor, +) +from _typeshed import SupportsGetItem +from typing import Any, Generic, TypeVar, final, overload +from typing_extensions import TypeVarTuple, Unpack + +_T = TypeVar("_T") +_T_co = TypeVar("_T_co", covariant=True) +_T1 = TypeVar("_T1") +_T2 = TypeVar("_T2") +_Ts = TypeVarTuple("_Ts") __all__ = [ "abs", @@ -59,9 +120,13 @@ __all__ = [ ] if sys.version_info >= (3, 11): + from _operator import call as call + __all__ += ["call"] if sys.version_info >= (3, 14): + from _operator import is_none as is_none, is_not_none as is_not_none + __all__ += ["is_none", "is_not_none"] __lt__ = lt @@ -111,3 +176,40 @@ __itruediv__ = itruediv __ixor__ = ixor if sys.version_info >= (3, 11): __call__ = call + +# At runtime, these classes are implemented in C as part of the _operator module +# However, they consider themselves to live in the operator module, so we'll put +# them here. +@final +class attrgetter(Generic[_T_co]): + @overload + def __new__(cls, attr: str, /) -> attrgetter[Any]: ... + @overload + def __new__(cls, attr: str, attr2: str, /) -> attrgetter[tuple[Any, Any]]: ... + @overload + def __new__(cls, attr: str, attr2: str, attr3: str, /) -> attrgetter[tuple[Any, Any, Any]]: ... + @overload + def __new__(cls, attr: str, attr2: str, attr3: str, attr4: str, /) -> attrgetter[tuple[Any, Any, Any, Any]]: ... + @overload + def __new__(cls, attr: str, /, *attrs: str) -> attrgetter[tuple[Any, ...]]: ... + def __call__(self, obj: Any, /) -> _T_co: ... + +@final +class itemgetter(Generic[_T_co]): + @overload + def __new__(cls, item: _T, /) -> itemgetter[_T]: ... + @overload + def __new__(cls, item1: _T1, item2: _T2, /, *items: Unpack[_Ts]) -> itemgetter[tuple[_T1, _T2, Unpack[_Ts]]]: ... + # __key: _KT_contra in SupportsGetItem seems to be causing variance issues, ie: + # TypeVar "_KT_contra@SupportsGetItem" is contravariant + # "tuple[int, int]" is incompatible with protocol "SupportsIndex" + # preventing [_T_co, ...] instead of [Any, ...] + # + # A suspected mypy issue prevents using [..., _T] instead of [..., Any] here. + # https://github.com/python/mypy/issues/14032 + def __call__(self, obj: SupportsGetItem[Any, Any]) -> Any: ... + +@final +class methodcaller: + def __init__(self, name: str, /, *args: Any, **kwargs: Any) -> None: ... + def __call__(self, obj: Any) -> Any: ... diff --git a/mypy/typeshed/stdlib/optparse.pyi b/mypy/typeshed/stdlib/optparse.pyi index b513bb647060..d6db7a06f291 100644 --- a/mypy/typeshed/stdlib/optparse.pyi +++ b/mypy/typeshed/stdlib/optparse.pyi @@ -1,4 +1,4 @@ -from _typeshed import Incomplete +from _typeshed import Incomplete, MaybeNone from abc import abstractmethod from collections.abc import Callable, Iterable, Mapping, Sequence from typing import IO, Any, AnyStr, Literal, NoReturn, overload @@ -56,7 +56,7 @@ class HelpFormatter: current_indent: int default_tag: str help_position: int - help_width: int | Any # initialized as None and computed later as int when storing option strings + help_width: int | MaybeNone # initialized as None and computed later as int when storing option strings indent_increment: int level: int max_help_position: int diff --git a/mypy/typeshed/stdlib/os/__init__.pyi b/mypy/typeshed/stdlib/os/__init__.pyi index d7bb4883a0f2..98260b14e7ed 100644 --- a/mypy/typeshed/stdlib/os/__init__.pyi +++ b/mypy/typeshed/stdlib/os/__init__.pyi @@ -19,12 +19,12 @@ from _typeshed import ( WriteableBuffer, structseq, ) -from abc import abstractmethod +from abc import ABC, abstractmethod from builtins import OSError from collections.abc import Callable, Iterable, Iterator, Mapping, MutableMapping, Sequence -from contextlib import AbstractContextManager -from io import BufferedRandom, BufferedReader, BufferedWriter, FileIO, TextIOWrapper as _TextIOWrapper +from io import BufferedRandom, BufferedReader, BufferedWriter, FileIO, TextIOWrapper from subprocess import Popen +from types import TracebackType from typing import ( IO, Any, @@ -47,6 +47,446 @@ from . import path as _path if sys.version_info >= (3, 9): from types import GenericAlias +__all__ = [ + "F_OK", + "O_APPEND", + "O_CREAT", + "O_EXCL", + "O_RDONLY", + "O_RDWR", + "O_TRUNC", + "O_WRONLY", + "P_NOWAIT", + "P_NOWAITO", + "P_WAIT", + "R_OK", + "SEEK_CUR", + "SEEK_END", + "SEEK_SET", + "TMP_MAX", + "W_OK", + "X_OK", + "DirEntry", + "_exit", + "abort", + "access", + "altsep", + "chdir", + "chmod", + "close", + "closerange", + "cpu_count", + "curdir", + "defpath", + "device_encoding", + "devnull", + "dup", + "dup2", + "environ", + "error", + "execl", + "execle", + "execlp", + "execlpe", + "execv", + "execve", + "execvp", + "execvpe", + "extsep", + "fdopen", + "fsdecode", + "fsencode", + "fspath", + "fstat", + "fsync", + "ftruncate", + "get_exec_path", + "get_inheritable", + "get_terminal_size", + "getcwd", + "getcwdb", + "getenv", + "getlogin", + "getpid", + "getppid", + "isatty", + "kill", + "linesep", + "link", + "listdir", + "lseek", + "lstat", + "makedirs", + "mkdir", + "name", + "open", + "pardir", + "path", + "pathsep", + "pipe", + "popen", + "putenv", + "read", + "readlink", + "remove", + "removedirs", + "rename", + "renames", + "replace", + "rmdir", + "scandir", + "sep", + "set_inheritable", + "spawnl", + "spawnle", + "spawnv", + "spawnve", + "stat", + "stat_result", + "statvfs_result", + "strerror", + "supports_bytes_environ", + "symlink", + "system", + "terminal_size", + "times", + "times_result", + "truncate", + "umask", + "uname_result", + "unlink", + "urandom", + "utime", + "waitpid", + "walk", + "write", +] +if sys.version_info >= (3, 9): + __all__ += ["waitstatus_to_exitcode"] +if sys.platform == "darwin" and sys.version_info >= (3, 12): + __all__ += ["PRIO_DARWIN_BG", "PRIO_DARWIN_NONUI", "PRIO_DARWIN_PROCESS", "PRIO_DARWIN_THREAD"] +if sys.platform == "darwin" and sys.version_info >= (3, 10): + __all__ += ["O_EVTONLY", "O_NOFOLLOW_ANY", "O_SYMLINK"] +if sys.platform == "linux": + __all__ += [ + "GRND_NONBLOCK", + "GRND_RANDOM", + "MFD_ALLOW_SEALING", + "MFD_CLOEXEC", + "MFD_HUGETLB", + "MFD_HUGE_16GB", + "MFD_HUGE_16MB", + "MFD_HUGE_1GB", + "MFD_HUGE_1MB", + "MFD_HUGE_256MB", + "MFD_HUGE_2GB", + "MFD_HUGE_2MB", + "MFD_HUGE_32MB", + "MFD_HUGE_512KB", + "MFD_HUGE_512MB", + "MFD_HUGE_64KB", + "MFD_HUGE_8MB", + "MFD_HUGE_MASK", + "MFD_HUGE_SHIFT", + "O_DIRECT", + "O_LARGEFILE", + "O_NOATIME", + "O_PATH", + "O_RSYNC", + "O_TMPFILE", + "RTLD_DEEPBIND", + "SCHED_BATCH", + "SCHED_IDLE", + "SCHED_RESET_ON_FORK", + "XATTR_CREATE", + "XATTR_REPLACE", + "XATTR_SIZE_MAX", + "copy_file_range", + "getrandom", + "getxattr", + "listxattr", + "memfd_create", + "removexattr", + "setxattr", + ] +if sys.platform == "linux" and sys.version_info >= (3, 13): + __all__ += [ + "POSIX_SPAWN_CLOSEFROM", + "TFD_CLOEXEC", + "TFD_NONBLOCK", + "TFD_TIMER_ABSTIME", + "TFD_TIMER_CANCEL_ON_SET", + "timerfd_create", + "timerfd_gettime", + "timerfd_gettime_ns", + "timerfd_settime", + "timerfd_settime_ns", + ] +if sys.platform == "linux" and sys.version_info >= (3, 12): + __all__ += [ + "CLONE_FILES", + "CLONE_FS", + "CLONE_NEWCGROUP", + "CLONE_NEWIPC", + "CLONE_NEWNET", + "CLONE_NEWNS", + "CLONE_NEWPID", + "CLONE_NEWUSER", + "CLONE_NEWUTS", + "CLONE_SIGHAND", + "CLONE_SYSVSEM", + "CLONE_THREAD", + "CLONE_VM", + "setns", + "unshare", + ] +if sys.platform == "linux" and sys.version_info >= (3, 10): + __all__ += [ + "EFD_CLOEXEC", + "EFD_NONBLOCK", + "EFD_SEMAPHORE", + "RWF_APPEND", + "SPLICE_F_MORE", + "SPLICE_F_MOVE", + "SPLICE_F_NONBLOCK", + "eventfd", + "eventfd_read", + "eventfd_write", + "splice", + ] +if sys.platform == "linux" and sys.version_info >= (3, 9): + __all__ += ["P_PIDFD", "pidfd_open"] +if sys.platform == "win32": + __all__ += [ + "O_BINARY", + "O_NOINHERIT", + "O_RANDOM", + "O_SEQUENTIAL", + "O_SHORT_LIVED", + "O_TEMPORARY", + "O_TEXT", + "P_DETACH", + "P_OVERLAY", + "get_handle_inheritable", + "set_handle_inheritable", + "startfile", + ] +if sys.platform == "win32" and sys.version_info >= (3, 12): + __all__ += ["listdrives", "listmounts", "listvolumes"] +if sys.platform != "win32": + __all__ += [ + "CLD_CONTINUED", + "CLD_DUMPED", + "CLD_EXITED", + "CLD_TRAPPED", + "EX_CANTCREAT", + "EX_CONFIG", + "EX_DATAERR", + "EX_IOERR", + "EX_NOHOST", + "EX_NOINPUT", + "EX_NOPERM", + "EX_NOUSER", + "EX_OSERR", + "EX_OSFILE", + "EX_PROTOCOL", + "EX_SOFTWARE", + "EX_TEMPFAIL", + "EX_UNAVAILABLE", + "EX_USAGE", + "F_LOCK", + "F_TEST", + "F_TLOCK", + "F_ULOCK", + "NGROUPS_MAX", + "O_ACCMODE", + "O_ASYNC", + "O_CLOEXEC", + "O_DIRECTORY", + "O_DSYNC", + "O_NDELAY", + "O_NOCTTY", + "O_NOFOLLOW", + "O_NONBLOCK", + "O_SYNC", + "POSIX_SPAWN_CLOSE", + "POSIX_SPAWN_DUP2", + "POSIX_SPAWN_OPEN", + "PRIO_PGRP", + "PRIO_PROCESS", + "PRIO_USER", + "P_ALL", + "P_PGID", + "P_PID", + "RTLD_GLOBAL", + "RTLD_LAZY", + "RTLD_LOCAL", + "RTLD_NODELETE", + "RTLD_NOLOAD", + "RTLD_NOW", + "SCHED_FIFO", + "SCHED_OTHER", + "SCHED_RR", + "SEEK_DATA", + "SEEK_HOLE", + "ST_NOSUID", + "ST_RDONLY", + "WCONTINUED", + "WCOREDUMP", + "WEXITED", + "WEXITSTATUS", + "WIFCONTINUED", + "WIFEXITED", + "WIFSIGNALED", + "WIFSTOPPED", + "WNOHANG", + "WNOWAIT", + "WSTOPPED", + "WSTOPSIG", + "WTERMSIG", + "WUNTRACED", + "chown", + "chroot", + "confstr", + "confstr_names", + "ctermid", + "environb", + "fchdir", + "fchown", + "fork", + "forkpty", + "fpathconf", + "fstatvfs", + "fwalk", + "getegid", + "getenvb", + "geteuid", + "getgid", + "getgrouplist", + "getgroups", + "getloadavg", + "getpgid", + "getpgrp", + "getpriority", + "getsid", + "getuid", + "initgroups", + "killpg", + "lchown", + "lockf", + "major", + "makedev", + "minor", + "mkfifo", + "mknod", + "nice", + "openpty", + "pathconf", + "pathconf_names", + "posix_spawn", + "posix_spawnp", + "pread", + "preadv", + "pwrite", + "pwritev", + "readv", + "register_at_fork", + "sched_get_priority_max", + "sched_get_priority_min", + "sched_yield", + "sendfile", + "setegid", + "seteuid", + "setgid", + "setgroups", + "setpgid", + "setpgrp", + "setpriority", + "setregid", + "setreuid", + "setsid", + "setuid", + "spawnlp", + "spawnlpe", + "spawnvp", + "spawnvpe", + "statvfs", + "sync", + "sysconf", + "sysconf_names", + "tcgetpgrp", + "tcsetpgrp", + "ttyname", + "uname", + "wait", + "wait3", + "wait4", + "writev", + ] +if sys.platform != "win32" and sys.version_info >= (3, 13): + __all__ += ["grantpt", "posix_openpt", "ptsname", "unlockpt"] +if sys.platform != "win32" and sys.version_info >= (3, 11): + __all__ += ["login_tty"] +if sys.platform != "win32" and sys.version_info >= (3, 10): + __all__ += ["O_FSYNC"] +if sys.platform != "win32" and sys.version_info >= (3, 9): + __all__ += ["CLD_KILLED", "CLD_STOPPED"] +if sys.platform != "darwin" and sys.platform != "win32": + __all__ += [ + "POSIX_FADV_DONTNEED", + "POSIX_FADV_NOREUSE", + "POSIX_FADV_NORMAL", + "POSIX_FADV_RANDOM", + "POSIX_FADV_SEQUENTIAL", + "POSIX_FADV_WILLNEED", + "RWF_DSYNC", + "RWF_HIPRI", + "RWF_NOWAIT", + "RWF_SYNC", + "ST_APPEND", + "ST_MANDLOCK", + "ST_NOATIME", + "ST_NODEV", + "ST_NODIRATIME", + "ST_NOEXEC", + "ST_RELATIME", + "ST_SYNCHRONOUS", + "ST_WRITE", + "fdatasync", + "getresgid", + "getresuid", + "pipe2", + "posix_fadvise", + "posix_fallocate", + "sched_getaffinity", + "sched_getparam", + "sched_getscheduler", + "sched_param", + "sched_rr_get_interval", + "sched_setaffinity", + "sched_setparam", + "sched_setscheduler", + "setresgid", + "setresuid", + ] +if sys.platform != "linux" and sys.platform != "win32": + __all__ += ["O_EXLOCK", "O_SHLOCK", "chflags", "lchflags"] +if sys.platform != "linux" and sys.platform != "win32" and sys.version_info >= (3, 13): + __all__ += ["O_EXEC", "O_SEARCH"] +if sys.platform != "darwin" or sys.version_info >= (3, 13): + if sys.platform != "win32": + __all__ += ["waitid", "waitid_result"] +if sys.platform != "win32" or sys.version_info >= (3, 13): + __all__ += ["fchmod"] + if sys.platform != "linux": + __all__ += ["lchmod"] +if sys.platform != "win32" or sys.version_info >= (3, 12): + __all__ += ["get_blocking", "set_blocking"] +if sys.platform != "win32" or sys.version_info >= (3, 11): + __all__ += ["EX_OK"] +if sys.platform != "win32" or sys.version_info >= (3, 9): + __all__ += ["unsetenv"] + # This unnecessary alias is to work around various errors path = _path @@ -124,15 +564,16 @@ if sys.platform != "win32": CLD_KILLED: int CLD_STOPPED: int - # TODO: SCHED_RESET_ON_FORK not available on darwin? - # TODO: SCHED_BATCH and SCHED_IDLE are linux only? - SCHED_OTHER: int # some flavors of Unix - SCHED_BATCH: int # some flavors of Unix - SCHED_IDLE: int # some flavors of Unix - SCHED_SPORADIC: int # some flavors of Unix - SCHED_FIFO: int # some flavors of Unix - SCHED_RR: int # some flavors of Unix - SCHED_RESET_ON_FORK: int # some flavors of Unix + SCHED_OTHER: int + SCHED_FIFO: int + SCHED_RR: int + if sys.platform != "darwin" and sys.platform != "linux": + SCHED_SPORADIC: int + +if sys.platform == "linux": + SCHED_BATCH: int + SCHED_IDLE: int + SCHED_RESET_ON_FORK: int if sys.platform != "win32": RTLD_LAZY: int @@ -157,8 +598,8 @@ SEEK_SET: int SEEK_CUR: int SEEK_END: int if sys.platform != "win32": - SEEK_DATA: int # some flavors of Unix - SEEK_HOLE: int # some flavors of Unix + SEEK_DATA: int + SEEK_HOLE: int O_RDONLY: int O_WRONLY: int @@ -167,34 +608,50 @@ O_APPEND: int O_CREAT: int O_EXCL: int O_TRUNC: int -# We don't use sys.platform for O_* flags to denote platform-dependent APIs because some codes, -# including tests for mypy, use a more finer way than sys.platform before using these APIs -# See https://github.com/python/typeshed/pull/2286 for discussions -O_DSYNC: int # Unix only -O_RSYNC: int # Unix only -O_SYNC: int # Unix only -O_NDELAY: int # Unix only -O_NONBLOCK: int # Unix only -O_NOCTTY: int # Unix only -O_CLOEXEC: int # Unix only -O_SHLOCK: int # Unix only -O_EXLOCK: int # Unix only -O_BINARY: int # Windows only -O_NOINHERIT: int # Windows only -O_SHORT_LIVED: int # Windows only -O_TEMPORARY: int # Windows only -O_RANDOM: int # Windows only -O_SEQUENTIAL: int # Windows only -O_TEXT: int # Windows only -O_ASYNC: int # Gnu extension if in C library -O_DIRECT: int # Gnu extension if in C library -O_DIRECTORY: int # Gnu extension if in C library -O_NOFOLLOW: int # Gnu extension if in C library -O_NOATIME: int # Gnu extension if in C library -O_PATH: int # Gnu extension if in C library -O_TMPFILE: int # Gnu extension if in C library -O_LARGEFILE: int # Gnu extension if in C library -O_ACCMODE: int # TODO: when does this exist? +if sys.platform == "win32": + O_BINARY: int + O_NOINHERIT: int + O_SHORT_LIVED: int + O_TEMPORARY: int + O_RANDOM: int + O_SEQUENTIAL: int + O_TEXT: int + +if sys.platform != "win32": + O_DSYNC: int + O_SYNC: int + O_NDELAY: int + O_NONBLOCK: int + O_NOCTTY: int + O_CLOEXEC: int + O_ASYNC: int # Gnu extension if in C library + O_DIRECTORY: int # Gnu extension if in C library + O_NOFOLLOW: int # Gnu extension if in C library + O_ACCMODE: int # TODO: when does this exist? + +if sys.platform == "linux": + O_RSYNC: int + O_DIRECT: int # Gnu extension if in C library + O_NOATIME: int # Gnu extension if in C library + O_PATH: int # Gnu extension if in C library + O_TMPFILE: int # Gnu extension if in C library + O_LARGEFILE: int # Gnu extension if in C library + +if sys.platform != "linux" and sys.platform != "win32": + O_SHLOCK: int + O_EXLOCK: int + +if sys.platform == "darwin" and sys.version_info >= (3, 10): + O_EVTONLY: int + O_NOFOLLOW_ANY: int + O_SYMLINK: int + +if sys.platform != "win32" and sys.version_info >= (3, 10): + O_FSYNC: int + +if sys.platform != "linux" and sys.platform != "win32" and sys.version_info >= (3, 13): + O_EXEC: int + O_SEARCH: int if sys.platform != "win32" and sys.platform != "darwin": # posix, but apparently missing on macos @@ -412,8 +869,11 @@ In the future, this property will contain the last metadata change time.""" # Attributes documented as sometimes appearing, but deliberately omitted from the stub: `st_creator`, `st_rsize`, `st_type`. # See https://github.com/python/typeshed/pull/6560#issuecomment-991253327 +# mypy and pyright object to this being both ABC and Protocol. +# At runtime it inherits from ABC and is not a Protocol, but it will be +# on the allowlist for use as a Protocol starting in 3.14. @runtime_checkable -class PathLike(Protocol[AnyStr_co]): +class PathLike(ABC, Protocol[AnyStr_co]): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] @abstractmethod def __fspath__(self) -> AnyStr_co: ... @@ -578,7 +1038,7 @@ def fdopen( newline: str | None = ..., closefd: bool = ..., opener: _Opener | None = ..., -) -> _TextIOWrapper: ... +) -> TextIOWrapper: ... @overload def fdopen( fd: int, @@ -793,9 +1253,12 @@ def replace( src: StrOrBytesPath, dst: StrOrBytesPath, *, src_dir_fd: int | None = None, dst_dir_fd: int | None = None ) -> None: ... def rmdir(path: StrOrBytesPath, *, dir_fd: int | None = None) -> None: ... - -class _ScandirIterator(Iterator[DirEntry[AnyStr]], AbstractContextManager[_ScandirIterator[AnyStr], None]): +@final +class _ScandirIterator(Generic[AnyStr]): + def __del__(self) -> None: ... + def __iter__(self) -> Self: ... def __next__(self) -> DirEntry[AnyStr]: ... + def __enter__(self) -> Self: ... def __exit__(self, *args: Unused) -> None: ... def close(self) -> None: ... @@ -917,9 +1380,25 @@ if sys.platform != "win32": if sys.platform != "darwin" and sys.platform != "linux": def plock(op: int, /) -> None: ... -class _wrap_close(_TextIOWrapper): - def __init__(self, stream: _TextIOWrapper, proc: Popen[str]) -> None: ... - def close(self) -> int | None: ... # type: ignore[override] +class _wrap_close: + def __init__(self, stream: TextIOWrapper, proc: Popen[str]) -> None: ... + def close(self) -> int | None: ... + def __enter__(self) -> Self: ... + def __exit__( + self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None + ) -> None: ... + def __iter__(self) -> Iterator[str]: ... + # Methods below here don't exist directly on the _wrap_close object, but + # are copied from the wrapped TextIOWrapper object via __getattr__. + # The full set of TextIOWrapper methods are technically available this way, + # but undocumented. Only a subset are currently included here. + def read(self, size: int | None = -1, /) -> str: ... + def readable(self) -> bool: ... + def readline(self, size: int = -1, /) -> str: ... + def readlines(self, hint: int = -1, /) -> list[str]: ... + def writable(self) -> bool: ... + def write(self, s: str, /) -> int: ... + def writelines(self, lines: Iterable[str], /) -> None: ... def popen(cmd: str, mode: str = "r", buffering: int = -1) -> _wrap_close: ... def spawnl(mode: int, file: StrOrBytesPath, arg0: StrOrBytesPath, *args: StrOrBytesPath) -> int: ... @@ -1059,6 +1538,14 @@ if sys.platform != "win32": def cpu_count() -> int | None: ... +if sys.version_info >= (3, 13): + # Documented to return `int | None`, but falls back to `len(sched_getaffinity(0))` when + # available. See https://github.com/python/cpython/blob/417c130/Lib/os.py#L1175-L1186. + if sys.platform != "win32" and sys.platform != "darwin": + def process_cpu_count() -> int: ... + else: + def process_cpu_count() -> int | None: ... + if sys.platform != "win32": # Unix only def confstr(name: str | int, /) -> str | None: ... diff --git a/mypy/typeshed/stdlib/pickle.pyi b/mypy/typeshed/stdlib/pickle.pyi index 98ec80b0f14e..9bea92ef1c9e 100644 --- a/mypy/typeshed/stdlib/pickle.pyi +++ b/mypy/typeshed/stdlib/pickle.pyi @@ -157,10 +157,10 @@ class Pickler: def __init__( self, file: SupportsWrite[bytes], - protocol: int | None = ..., + protocol: int | None = None, *, - fix_imports: bool = ..., - buffer_callback: _BufferCallback = ..., + fix_imports: bool = True, + buffer_callback: _BufferCallback = None, ) -> None: ... def reducer_override(self, obj: Any) -> Any: ... def dump(self, obj: Any, /) -> None: ... @@ -174,10 +174,10 @@ class Unpickler: self, file: _ReadableFileobj, *, - fix_imports: bool = ..., - encoding: str = ..., - errors: str = ..., - buffers: Iterable[Any] | None = ..., + fix_imports: bool = True, + encoding: str = "ASCII", + errors: str = "strict", + buffers: Iterable[Any] | None = (), ) -> None: ... def load(self) -> Any: ... def find_class(self, module_name: str, global_name: str, /) -> Any: ... diff --git a/mypy/typeshed/stdlib/platform.pyi b/mypy/typeshed/stdlib/platform.pyi index c47ecdc51df4..73393eada02c 100644 --- a/mypy/typeshed/stdlib/platform.pyi +++ b/mypy/typeshed/stdlib/platform.pyi @@ -1,5 +1,6 @@ import sys -from typing import NamedTuple +from typing import NamedTuple, type_check_only +from typing_extensions import Self def libc_ver(executable: str | None = None, lib: str = "", version: str = "", chunksize: int = 16384) -> tuple[str, str]: ... def win32_ver(release: str = "", version: str = "", csd: str = "", ptype: str = "") -> tuple[str, str, str, str]: ... @@ -14,13 +15,40 @@ def java_ver( def system_alias(system: str, release: str, version: str) -> tuple[str, str, str]: ... def architecture(executable: str = sys.executable, bits: str = "", linkage: str = "") -> tuple[str, str]: ... -class uname_result(NamedTuple): - system: str - node: str - release: str - version: str - machine: str - processor: str +if sys.version_info >= (3, 9): + # This class is not exposed. It calls itself platform.uname_result_base. + # At runtime it only has 5 fields. + @type_check_only + class _uname_result_base(NamedTuple): + system: str + node: str + release: str + version: str + machine: str + # This base class doesn't have this field at runtime, but claiming it + # does is the least bad way to handle the situation. Nobody really + # sees this class anyway. See #13068 + processor: str + + # uname_result emulates a 6-field named tuple, but the processor field + # is lazily evaluated rather than being passed in to the constructor. + class uname_result(_uname_result_base): + if sys.version_info >= (3, 10): + __match_args__ = ("system", "node", "release", "version", "machine") # pyright: ignore[reportAssignmentType] + + def __new__(_cls, system: str, node: str, release: str, version: str, machine: str) -> Self: ... + @property + def processor(self) -> str: ... + +else: + # On 3.8, uname_result is actually just a regular NamedTuple. + class uname_result(NamedTuple): + system: str + node: str + release: str + version: str + machine: str + processor: str def uname() -> uname_result: ... def system() -> str: ... diff --git a/mypy/typeshed/stdlib/posix.pyi b/mypy/typeshed/stdlib/posix.pyi index 1a4f22af82cf..7a4d6cb4bdbe 100644 --- a/mypy/typeshed/stdlib/posix.pyi +++ b/mypy/typeshed/stdlib/posix.pyi @@ -29,22 +29,20 @@ if sys.platform != "win32": F_TLOCK as F_TLOCK, F_ULOCK as F_ULOCK, NGROUPS_MAX as NGROUPS_MAX, + O_ACCMODE as O_ACCMODE, O_APPEND as O_APPEND, O_ASYNC as O_ASYNC, + O_CLOEXEC as O_CLOEXEC, O_CREAT as O_CREAT, - O_DIRECT as O_DIRECT, O_DIRECTORY as O_DIRECTORY, O_DSYNC as O_DSYNC, O_EXCL as O_EXCL, - O_LARGEFILE as O_LARGEFILE, O_NDELAY as O_NDELAY, - O_NOATIME as O_NOATIME, O_NOCTTY as O_NOCTTY, O_NOFOLLOW as O_NOFOLLOW, O_NONBLOCK as O_NONBLOCK, O_RDONLY as O_RDONLY, O_RDWR as O_RDWR, - O_RSYNC as O_RSYNC, O_SYNC as O_SYNC, O_TRUNC as O_TRUNC, O_WRONLY as O_WRONLY, @@ -64,13 +62,9 @@ if sys.platform != "win32": RTLD_NODELETE as RTLD_NODELETE, RTLD_NOLOAD as RTLD_NOLOAD, RTLD_NOW as RTLD_NOW, - SCHED_BATCH as SCHED_BATCH, SCHED_FIFO as SCHED_FIFO, - SCHED_IDLE as SCHED_IDLE, SCHED_OTHER as SCHED_OTHER, - SCHED_RESET_ON_FORK as SCHED_RESET_ON_FORK, SCHED_RR as SCHED_RR, - SCHED_SPORADIC as SCHED_SPORADIC, SEEK_DATA as SEEK_DATA, SEEK_HOLE as SEEK_HOLE, ST_NOSUID as ST_NOSUID, @@ -233,6 +227,9 @@ if sys.platform != "win32": if sys.version_info >= (3, 9): from os import CLD_KILLED as CLD_KILLED, CLD_STOPPED as CLD_STOPPED, waitstatus_to_exitcode as waitstatus_to_exitcode + if sys.version_info >= (3, 10): + from os import O_FSYNC as O_FSYNC + if sys.version_info >= (3, 11): from os import login_tty as login_tty @@ -254,10 +251,13 @@ if sys.platform != "win32": ) if sys.platform != "linux": - from os import chflags as chflags, lchflags as lchflags, lchmod as lchmod + from os import O_EXLOCK as O_EXLOCK, O_SHLOCK as O_SHLOCK, chflags as chflags, lchflags as lchflags, lchmod as lchmod if sys.platform != "linux" and sys.platform != "darwin": - from os import EX_NOTFOUND as EX_NOTFOUND + from os import EX_NOTFOUND as EX_NOTFOUND, SCHED_SPORADIC as SCHED_SPORADIC + + if sys.platform != "linux" and sys.version_info >= (3, 13): + from os import O_EXEC as O_EXEC, O_SEARCH as O_SEARCH if sys.platform != "darwin": from os import ( @@ -271,6 +271,15 @@ if sys.platform != "win32": RWF_HIPRI as RWF_HIPRI, RWF_NOWAIT as RWF_NOWAIT, RWF_SYNC as RWF_SYNC, + ST_APPEND as ST_APPEND, + ST_MANDLOCK as ST_MANDLOCK, + ST_NOATIME as ST_NOATIME, + ST_NODEV as ST_NODEV, + ST_NODIRATIME as ST_NODIRATIME, + ST_NOEXEC as ST_NOEXEC, + ST_RELATIME as ST_RELATIME, + ST_SYNCHRONOUS as ST_SYNCHRONOUS, + ST_WRITE as ST_WRITE, fdatasync as fdatasync, getresgid as getresgid, getresuid as getresuid, @@ -315,7 +324,16 @@ if sys.platform != "win32": MFD_HUGE_MASK as MFD_HUGE_MASK, MFD_HUGE_SHIFT as MFD_HUGE_SHIFT, MFD_HUGETLB as MFD_HUGETLB, + O_DIRECT as O_DIRECT, + O_LARGEFILE as O_LARGEFILE, + O_NOATIME as O_NOATIME, + O_PATH as O_PATH, + O_RSYNC as O_RSYNC, + O_TMPFILE as O_TMPFILE, RTLD_DEEPBIND as RTLD_DEEPBIND, + SCHED_BATCH as SCHED_BATCH, + SCHED_IDLE as SCHED_IDLE, + SCHED_RESET_ON_FORK as SCHED_RESET_ON_FORK, XATTR_CREATE as XATTR_CREATE, XATTR_REPLACE as XATTR_REPLACE, XATTR_SIZE_MAX as XATTR_SIZE_MAX, @@ -373,6 +391,8 @@ if sys.platform != "win32": PRIO_DARWIN_PROCESS as PRIO_DARWIN_PROCESS, PRIO_DARWIN_THREAD as PRIO_DARWIN_THREAD, ) + if sys.platform == "darwin" and sys.version_info >= (3, 10): + from os import O_EVTONLY as O_EVTONLY, O_NOFOLLOW_ANY as O_NOFOLLOW_ANY, O_SYMLINK as O_SYMLINK # Not same as os.environ or os.environb # Because of this variable, we can't do "from posix import *" in os/__init__.pyi diff --git a/mypy/typeshed/stdlib/posixpath.pyi b/mypy/typeshed/stdlib/posixpath.pyi index 31406f8df950..3313667f1781 100644 --- a/mypy/typeshed/stdlib/posixpath.pyi +++ b/mypy/typeshed/stdlib/posixpath.pyi @@ -77,7 +77,11 @@ pathsep: LiteralString defpath: LiteralString devnull: LiteralString -def abspath(path: PathLike[AnyStr] | AnyStr) -> AnyStr: ... +# Overloads are necessary to work around python/mypy#17952 & python/mypy#11880 +@overload +def abspath(path: PathLike[AnyStr]) -> AnyStr: ... +@overload +def abspath(path: AnyStr) -> AnyStr: ... @overload def basename(p: PathLike[AnyStr]) -> AnyStr: ... @overload @@ -86,8 +90,14 @@ def basename(p: AnyOrLiteralStr) -> AnyOrLiteralStr: ... def dirname(p: PathLike[AnyStr]) -> AnyStr: ... @overload def dirname(p: AnyOrLiteralStr) -> AnyOrLiteralStr: ... -def expanduser(path: PathLike[AnyStr] | AnyStr) -> AnyStr: ... -def expandvars(path: PathLike[AnyStr] | AnyStr) -> AnyStr: ... +@overload +def expanduser(path: PathLike[AnyStr]) -> AnyStr: ... +@overload +def expanduser(path: AnyStr) -> AnyStr: ... +@overload +def expandvars(path: PathLike[AnyStr]) -> AnyStr: ... +@overload +def expandvars(path: AnyStr) -> AnyStr: ... @overload def normcase(s: PathLike[AnyStr]) -> AnyStr: ... @overload diff --git a/mypy/typeshed/stdlib/pstats.pyi b/mypy/typeshed/stdlib/pstats.pyi index 83256b433035..d41fa202cf77 100644 --- a/mypy/typeshed/stdlib/pstats.pyi +++ b/mypy/typeshed/stdlib/pstats.pyi @@ -1,11 +1,16 @@ import sys -from _typeshed import StrEnum, StrOrBytesPath +from _typeshed import StrOrBytesPath from collections.abc import Iterable from cProfile import Profile as _cProfile from profile import Profile from typing import IO, Any, Literal, overload from typing_extensions import Self, TypeAlias +if sys.version_info >= (3, 11): + from enum import StrEnum +else: + from enum import Enum + if sys.version_info >= (3, 9): __all__ = ["Stats", "SortKey", "FunctionProfile", "StatsProfile"] else: @@ -13,16 +18,29 @@ else: _Selector: TypeAlias = str | float | int -class SortKey(StrEnum): - CALLS = "calls" - CUMULATIVE = "cumulative" - FILENAME = "filename" - LINE = "line" - NAME = "name" - NFL = "nfl" - PCALLS = "pcalls" - STDNAME = "stdname" - TIME = "time" +if sys.version_info >= (3, 11): + class SortKey(StrEnum): + CALLS = "calls" + CUMULATIVE = "cumulative" + FILENAME = "filename" + LINE = "line" + NAME = "name" + NFL = "nfl" + PCALLS = "pcalls" + STDNAME = "stdname" + TIME = "time" + +else: + class SortKey(str, Enum): + CALLS = "calls" + CUMULATIVE = "cumulative" + FILENAME = "filename" + LINE = "line" + NAME = "name" + NFL = "nfl" + PCALLS = "pcalls" + STDNAME = "stdname" + TIME = "time" if sys.version_info >= (3, 9): from dataclasses import dataclass diff --git a/mypy/typeshed/stdlib/pyexpat/__init__.pyi b/mypy/typeshed/stdlib/pyexpat/__init__.pyi index dc0156ef13bd..21e676052098 100644 --- a/mypy/typeshed/stdlib/pyexpat/__init__.pyi +++ b/mypy/typeshed/stdlib/pyexpat/__init__.pyi @@ -2,18 +2,14 @@ from _typeshed import ReadableBuffer, SupportsRead from collections.abc import Callable from pyexpat import errors as errors, model as model from typing import Any, Final, final -from typing_extensions import TypeAlias +from typing_extensions import CapsuleType, TypeAlias +from xml.parsers.expat import ExpatError as ExpatError EXPAT_VERSION: Final[str] # undocumented version_info: tuple[int, int, int] # undocumented native_encoding: str # undocumented features: list[tuple[str, int]] # undocumented -class ExpatError(Exception): - code: int - lineno: int - offset: int - error = ExpatError XML_PARAM_ENTITY_PARSING_NEVER: Final = 0 XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE: Final = 1 @@ -82,3 +78,5 @@ def ErrorString(code: int, /) -> str: ... def ParserCreate( encoding: str | None = None, namespace_separator: str | None = None, intern: dict[str, Any] | None = None ) -> XMLParserType: ... + +expat_CAPI: CapsuleType diff --git a/mypy/typeshed/stdlib/queue.pyi b/mypy/typeshed/stdlib/queue.pyi index 16643c99d08d..4fb49cb6102b 100644 --- a/mypy/typeshed/stdlib/queue.pyi +++ b/mypy/typeshed/stdlib/queue.pyi @@ -1,4 +1,5 @@ import sys +from _queue import Empty as Empty, SimpleQueue as SimpleQueue from threading import Condition, Lock from typing import Any, Generic, TypeVar @@ -11,7 +12,6 @@ if sys.version_info >= (3, 13): _T = TypeVar("_T") -class Empty(Exception): ... class Full(Exception): ... if sys.version_info >= (3, 13): @@ -55,14 +55,3 @@ class PriorityQueue(Queue[_T]): class LifoQueue(Queue[_T]): queue: list[_T] - -class SimpleQueue(Generic[_T]): - def __init__(self) -> None: ... - def empty(self) -> bool: ... - def get(self, block: bool = True, timeout: float | None = None) -> _T: ... - def get_nowait(self) -> _T: ... - def put(self, item: _T, block: bool = True, timeout: float | None = None) -> None: ... - def put_nowait(self, item: _T) -> None: ... - def qsize(self) -> int: ... - if sys.version_info >= (3, 9): - def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... diff --git a/mypy/typeshed/stdlib/re.pyi b/mypy/typeshed/stdlib/re.pyi index 76f98dd9f2a2..b8fe2e9e1a46 100644 --- a/mypy/typeshed/stdlib/re.pyi +++ b/mypy/typeshed/stdlib/re.pyi @@ -2,9 +2,8 @@ import enum import sre_compile import sre_constants import sys -from _typeshed import ReadableBuffer +from _typeshed import MaybeNone, ReadableBuffer from collections.abc import Callable, Iterator, Mapping -from sre_constants import error as error from typing import Any, AnyStr, Generic, Literal, TypeVar, final, overload from typing_extensions import TypeAlias @@ -54,6 +53,16 @@ if sys.version_info >= (3, 13): _T = TypeVar("_T") +# The implementation defines this in re._constants (version_info >= 3, 11) or +# sre_constants. Typeshed has it here because its __module__ attribute is set to "re". +class error(Exception): + msg: str + pattern: str | bytes | None + pos: int | None + lineno: int + colno: int + def __init__(self, msg: str, pattern: str | bytes | None = None, pos: int | None = None) -> None: ... + @final class Match(Generic[AnyStr]): @property @@ -81,19 +90,19 @@ class Match(Generic[AnyStr]): @overload def group(self, group: Literal[0] = 0, /) -> AnyStr: ... @overload - def group(self, group: str | int, /) -> AnyStr | Any: ... + def group(self, group: str | int, /) -> AnyStr | MaybeNone: ... @overload - def group(self, group1: str | int, group2: str | int, /, *groups: str | int) -> tuple[AnyStr | Any, ...]: ... + def group(self, group1: str | int, group2: str | int, /, *groups: str | int) -> tuple[AnyStr | MaybeNone, ...]: ... # Each item of groups()'s return tuple is either "AnyStr" or # "AnyStr | None", depending on the pattern. @overload - def groups(self) -> tuple[AnyStr | Any, ...]: ... + def groups(self) -> tuple[AnyStr | MaybeNone, ...]: ... @overload def groups(self, default: _T) -> tuple[AnyStr | _T, ...]: ... # Each value in groupdict()'s return dict is either "AnyStr" or # "AnyStr | None", depending on the pattern. @overload - def groupdict(self) -> dict[str, AnyStr | Any]: ... + def groupdict(self) -> dict[str, AnyStr | MaybeNone]: ... @overload def groupdict(self, default: _T) -> dict[str, AnyStr | _T]: ... def start(self, group: int | str = 0, /) -> int: ... @@ -105,7 +114,7 @@ class Match(Generic[AnyStr]): @overload def __getitem__(self, key: Literal[0], /) -> AnyStr: ... @overload - def __getitem__(self, key: int | str, /) -> AnyStr | Any: ... + def __getitem__(self, key: int | str, /) -> AnyStr | MaybeNone: ... def __copy__(self) -> Match[AnyStr]: ... def __deepcopy__(self, memo: Any, /) -> Match[AnyStr]: ... if sys.version_info >= (3, 9): @@ -142,11 +151,11 @@ class Pattern(Generic[AnyStr]): @overload def fullmatch(self, string: AnyStr, pos: int = 0, endpos: int = sys.maxsize) -> Match[AnyStr] | None: ... @overload - def split(self: Pattern[str], string: str, maxsplit: int = 0) -> list[str | Any]: ... + def split(self: Pattern[str], string: str, maxsplit: int = 0) -> list[str | MaybeNone]: ... @overload - def split(self: Pattern[bytes], string: ReadableBuffer, maxsplit: int = 0) -> list[bytes | Any]: ... + def split(self: Pattern[bytes], string: ReadableBuffer, maxsplit: int = 0) -> list[bytes | MaybeNone]: ... @overload - def split(self, string: AnyStr, maxsplit: int = 0) -> list[AnyStr | Any]: ... + def split(self, string: AnyStr, maxsplit: int = 0) -> list[AnyStr | MaybeNone]: ... # return type depends on the number of groups in the pattern @overload def findall(self: Pattern[str], string: str, pos: int = 0, endpos: int = sys.maxsize) -> list[Any]: ... @@ -261,11 +270,11 @@ def fullmatch(pattern: str | Pattern[str], string: str, flags: _FlagsType = 0) - @overload def fullmatch(pattern: bytes | Pattern[bytes], string: ReadableBuffer, flags: _FlagsType = 0) -> Match[bytes] | None: ... @overload -def split(pattern: str | Pattern[str], string: str, maxsplit: int = 0, flags: _FlagsType = 0) -> list[str | Any]: ... +def split(pattern: str | Pattern[str], string: str, maxsplit: int = 0, flags: _FlagsType = 0) -> list[str | MaybeNone]: ... @overload def split( pattern: bytes | Pattern[bytes], string: ReadableBuffer, maxsplit: int = 0, flags: _FlagsType = 0 -) -> list[bytes | Any]: ... +) -> list[bytes | MaybeNone]: ... @overload def findall(pattern: str | Pattern[str], string: str, flags: _FlagsType = 0) -> list[Any]: ... @overload diff --git a/mypy/typeshed/stdlib/sched.pyi b/mypy/typeshed/stdlib/sched.pyi index 75dd63d0414a..ace501430847 100644 --- a/mypy/typeshed/stdlib/sched.pyi +++ b/mypy/typeshed/stdlib/sched.pyi @@ -1,6 +1,6 @@ import sys from collections.abc import Callable -from typing import Any, NamedTuple +from typing import Any, NamedTuple, type_check_only from typing_extensions import TypeAlias __all__ = ["scheduler"] @@ -17,13 +17,16 @@ if sys.version_info >= (3, 10): kwargs: dict[str, Any] else: - class Event(NamedTuple): + @type_check_only + class _EventBase(NamedTuple): time: float priority: Any action: _ActionCallback argument: tuple[Any, ...] kwargs: dict[str, Any] + class Event(_EventBase): ... + class scheduler: timefunc: Callable[[], float] delayfunc: Callable[[float], object] diff --git a/mypy/typeshed/stdlib/shlex.pyi b/mypy/typeshed/stdlib/shlex.pyi index daa8df439b26..1c27483782fb 100644 --- a/mypy/typeshed/stdlib/shlex.pyi +++ b/mypy/typeshed/stdlib/shlex.pyi @@ -27,7 +27,7 @@ def join(split_command: Iterable[str]) -> str: ... def quote(s: str) -> str: ... # TODO: Make generic over infile once PEP 696 is implemented. -class shlex(Iterable[str]): +class shlex: commenters: str wordchars: str whitespace: str diff --git a/mypy/typeshed/stdlib/socket.pyi b/mypy/typeshed/stdlib/socket.pyi index b626409d2dde..e42bba757fc3 100644 --- a/mypy/typeshed/stdlib/socket.pyi +++ b/mypy/typeshed/stdlib/socket.pyi @@ -28,7 +28,6 @@ from _socket import ( IP_MULTICAST_LOOP as IP_MULTICAST_LOOP, IP_MULTICAST_TTL as IP_MULTICAST_TTL, IP_OPTIONS as IP_OPTIONS, - IP_RECVDSTADDR as IP_RECVDSTADDR, IP_TOS as IP_TOS, IP_TTL as IP_TTL, IPPORT_RESERVED as IPPORT_RESERVED, @@ -38,17 +37,13 @@ from _socket import ( IPPROTO_EGP as IPPROTO_EGP, IPPROTO_ESP as IPPROTO_ESP, IPPROTO_FRAGMENT as IPPROTO_FRAGMENT, - IPPROTO_GGP as IPPROTO_GGP, IPPROTO_HOPOPTS as IPPROTO_HOPOPTS, IPPROTO_ICMP as IPPROTO_ICMP, IPPROTO_ICMPV6 as IPPROTO_ICMPV6, IPPROTO_IDP as IPPROTO_IDP, IPPROTO_IGMP as IPPROTO_IGMP, IPPROTO_IP as IPPROTO_IP, - IPPROTO_IPV4 as IPPROTO_IPV4, IPPROTO_IPV6 as IPPROTO_IPV6, - IPPROTO_MAX as IPPROTO_MAX, - IPPROTO_ND as IPPROTO_ND, IPPROTO_NONE as IPPROTO_NONE, IPPROTO_PIM as IPPROTO_PIM, IPPROTO_PUP as IPPROTO_PUP, @@ -93,7 +88,6 @@ from _socket import ( SO_SNDLOWAT as SO_SNDLOWAT, SO_SNDTIMEO as SO_SNDTIMEO, SO_TYPE as SO_TYPE, - SO_USELOOPBACK as SO_USELOOPBACK, SOL_IP as SOL_IP, SOL_SOCKET as SOL_SOCKET, SOL_TCP as SOL_TCP, @@ -109,8 +103,6 @@ from _socket import ( _RetAddress as _RetAddress, close as close, dup as dup, - error as error, - gaierror as gaierror, getdefaulttimeout as getdefaulttimeout, gethostbyaddr as gethostbyaddr, gethostbyname as gethostbyname, @@ -121,7 +113,6 @@ from _socket import ( getservbyname as getservbyname, getservbyport as getservbyport, has_ipv6 as has_ipv6, - herror as herror, htonl as htonl, htons as htons, if_indextoname as if_indextoname, @@ -134,7 +125,6 @@ from _socket import ( ntohl as ntohl, ntohs as ntohs, setdefaulttimeout as setdefaulttimeout, - timeout as timeout, ) from _typeshed import ReadableBuffer, Unused, WriteableBuffer from collections.abc import Iterable @@ -143,8 +133,176 @@ from io import BufferedReader, BufferedRWPair, BufferedWriter, IOBase, RawIOBase from typing import Any, Literal, Protocol, SupportsIndex, overload from typing_extensions import Self +__all__ = [ + "fromfd", + "getfqdn", + "create_connection", + "create_server", + "has_dualstack_ipv6", + "AddressFamily", + "SocketKind", + "AF_APPLETALK", + "AF_DECnet", + "AF_INET", + "AF_INET6", + "AF_IPX", + "AF_SNA", + "AF_UNSPEC", + "AI_ADDRCONFIG", + "AI_ALL", + "AI_CANONNAME", + "AI_NUMERICHOST", + "AI_NUMERICSERV", + "AI_PASSIVE", + "AI_V4MAPPED", + "CAPI", + "EAI_AGAIN", + "EAI_BADFLAGS", + "EAI_FAIL", + "EAI_FAMILY", + "EAI_MEMORY", + "EAI_NODATA", + "EAI_NONAME", + "EAI_SERVICE", + "EAI_SOCKTYPE", + "INADDR_ALLHOSTS_GROUP", + "INADDR_ANY", + "INADDR_BROADCAST", + "INADDR_LOOPBACK", + "INADDR_MAX_LOCAL_GROUP", + "INADDR_NONE", + "INADDR_UNSPEC_GROUP", + "IPPORT_RESERVED", + "IPPORT_USERRESERVED", + "IPPROTO_AH", + "IPPROTO_DSTOPTS", + "IPPROTO_EGP", + "IPPROTO_ESP", + "IPPROTO_FRAGMENT", + "IPPROTO_HOPOPTS", + "IPPROTO_ICMP", + "IPPROTO_ICMPV6", + "IPPROTO_IDP", + "IPPROTO_IGMP", + "IPPROTO_IP", + "IPPROTO_IPV6", + "IPPROTO_NONE", + "IPPROTO_PIM", + "IPPROTO_PUP", + "IPPROTO_RAW", + "IPPROTO_ROUTING", + "IPPROTO_SCTP", + "IPPROTO_TCP", + "IPPROTO_UDP", + "IPV6_CHECKSUM", + "IPV6_JOIN_GROUP", + "IPV6_LEAVE_GROUP", + "IPV6_MULTICAST_HOPS", + "IPV6_MULTICAST_IF", + "IPV6_MULTICAST_LOOP", + "IPV6_RECVTCLASS", + "IPV6_TCLASS", + "IPV6_UNICAST_HOPS", + "IPV6_V6ONLY", + "IP_ADD_MEMBERSHIP", + "IP_DROP_MEMBERSHIP", + "IP_HDRINCL", + "IP_MULTICAST_IF", + "IP_MULTICAST_LOOP", + "IP_MULTICAST_TTL", + "IP_OPTIONS", + "IP_TOS", + "IP_TTL", + "MSG_CTRUNC", + "MSG_DONTROUTE", + "MSG_OOB", + "MSG_PEEK", + "MSG_TRUNC", + "MSG_WAITALL", + "NI_DGRAM", + "NI_MAXHOST", + "NI_MAXSERV", + "NI_NAMEREQD", + "NI_NOFQDN", + "NI_NUMERICHOST", + "NI_NUMERICSERV", + "SHUT_RD", + "SHUT_RDWR", + "SHUT_WR", + "SOCK_DGRAM", + "SOCK_RAW", + "SOCK_RDM", + "SOCK_SEQPACKET", + "SOCK_STREAM", + "SOL_IP", + "SOL_SOCKET", + "SOL_TCP", + "SOL_UDP", + "SOMAXCONN", + "SO_ACCEPTCONN", + "SO_BROADCAST", + "SO_DEBUG", + "SO_DONTROUTE", + "SO_ERROR", + "SO_KEEPALIVE", + "SO_LINGER", + "SO_OOBINLINE", + "SO_RCVBUF", + "SO_RCVLOWAT", + "SO_RCVTIMEO", + "SO_REUSEADDR", + "SO_SNDBUF", + "SO_SNDLOWAT", + "SO_SNDTIMEO", + "SO_TYPE", + "SocketType", + "TCP_FASTOPEN", + "TCP_KEEPCNT", + "TCP_KEEPINTVL", + "TCP_MAXSEG", + "TCP_NODELAY", + "close", + "dup", + "error", + "gaierror", + "getaddrinfo", + "getdefaulttimeout", + "gethostbyaddr", + "gethostbyname", + "gethostbyname_ex", + "gethostname", + "getnameinfo", + "getprotobyname", + "getservbyname", + "getservbyport", + "has_ipv6", + "herror", + "htonl", + "htons", + "if_indextoname", + "if_nameindex", + "if_nametoindex", + "inet_aton", + "inet_ntoa", + "inet_ntop", + "inet_pton", + "ntohl", + "ntohs", + "setdefaulttimeout", + "socket", + "socketpair", + "timeout", +] + if sys.platform == "win32": from _socket import ( + IPPROTO_CBT as IPPROTO_CBT, + IPPROTO_ICLFXBM as IPPROTO_ICLFXBM, + IPPROTO_IGP as IPPROTO_IGP, + IPPROTO_L2TP as IPPROTO_L2TP, + IPPROTO_PGM as IPPROTO_PGM, + IPPROTO_RDP as IPPROTO_RDP, + IPPROTO_ST as IPPROTO_ST, RCVALL_MAX as RCVALL_MAX, RCVALL_OFF as RCVALL_OFF, RCVALL_ON as RCVALL_ON, @@ -155,6 +313,28 @@ if sys.platform == "win32": SO_EXCLUSIVEADDRUSE as SO_EXCLUSIVEADDRUSE, ) + __all__ += [ + "IPPROTO_CBT", + "IPPROTO_ICLFXBM", + "IPPROTO_IGP", + "IPPROTO_L2TP", + "IPPROTO_PGM", + "IPPROTO_RDP", + "IPPROTO_ST", + "RCVALL_MAX", + "RCVALL_OFF", + "RCVALL_ON", + "RCVALL_SOCKETLEVELONLY", + "SIO_KEEPALIVE_VALS", + "SIO_LOOPBACK_FAST_PATH", + "SIO_RCVALL", + "SO_EXCLUSIVEADDRUSE", + "fromshare", + "errorTab", + "MSG_BCAST", + "MSG_MCAST", + ] + if sys.platform != "darwin" or sys.version_info >= (3, 9): from _socket import ( IPV6_DONTFRAG as IPV6_DONTFRAG, @@ -165,33 +345,26 @@ if sys.platform != "darwin" or sys.version_info >= (3, 9): IPV6_RTHDR as IPV6_RTHDR, ) + __all__ += ["IPV6_DONTFRAG", "IPV6_HOPLIMIT", "IPV6_HOPOPTS", "IPV6_PKTINFO", "IPV6_RECVRTHDR", "IPV6_RTHDR"] + if sys.platform == "darwin": from _socket import PF_SYSTEM as PF_SYSTEM, SYSPROTO_CONTROL as SYSPROTO_CONTROL + __all__ += ["PF_SYSTEM", "SYSPROTO_CONTROL", "AF_SYSTEM"] + if sys.platform != "darwin": - from _socket import ( - IPPROTO_CBT as IPPROTO_CBT, - IPPROTO_ICLFXBM as IPPROTO_ICLFXBM, - IPPROTO_IGP as IPPROTO_IGP, - IPPROTO_L2TP as IPPROTO_L2TP, - IPPROTO_PGM as IPPROTO_PGM, - IPPROTO_RDP as IPPROTO_RDP, - IPPROTO_ST as IPPROTO_ST, - TCP_KEEPIDLE as TCP_KEEPIDLE, - ) + from _socket import TCP_KEEPIDLE as TCP_KEEPIDLE + + __all__ += ["TCP_KEEPIDLE", "AF_IRDA", "MSG_ERRQUEUE"] if sys.version_info >= (3, 10): from _socket import IP_RECVTOS as IP_RECVTOS -elif sys.platform != "win32" and sys.platform != "darwin": - from _socket import IP_RECVTOS as IP_RECVTOS + + __all__ += ["IP_RECVTOS"] if sys.platform != "win32" and sys.platform != "darwin": from _socket import ( - IP_BIND_ADDRESS_NO_PORT as IP_BIND_ADDRESS_NO_PORT, IP_TRANSPARENT as IP_TRANSPARENT, - IPPROTO_BIP as IPPROTO_BIP, - IPPROTO_MOBILE as IPPROTO_MOBILE, - IPPROTO_VRRP as IPPROTO_VRRP, IPX_TYPE as IPX_TYPE, SCM_CREDENTIALS as SCM_CREDENTIALS, SO_BINDTODEVICE as SO_BINDTODEVICE, @@ -203,7 +376,6 @@ if sys.platform != "win32" and sys.platform != "darwin": SO_PEERSEC as SO_PEERSEC, SO_PRIORITY as SO_PRIORITY, SO_PROTOCOL as SO_PROTOCOL, - SO_SETFIB as SO_SETFIB, SOL_ATALK as SOL_ATALK, SOL_AX25 as SOL_AX25, SOL_HCI as SOL_HCI, @@ -221,15 +393,59 @@ if sys.platform != "win32" and sys.platform != "darwin": TCP_WINDOW_CLAMP as TCP_WINDOW_CLAMP, ) + __all__ += [ + "IP_TRANSPARENT", + "SCM_CREDENTIALS", + "SO_BINDTODEVICE", + "SO_DOMAIN", + "SO_MARK", + "SO_PASSCRED", + "SO_PASSSEC", + "SO_PEERCRED", + "SO_PEERSEC", + "SO_PRIORITY", + "SO_PROTOCOL", + "TCP_CONGESTION", + "TCP_CORK", + "TCP_DEFER_ACCEPT", + "TCP_INFO", + "TCP_LINGER2", + "TCP_QUICKACK", + "TCP_SYNCNT", + "TCP_USER_TIMEOUT", + "TCP_WINDOW_CLAMP", + "AF_ASH", + "AF_ATMPVC", + "AF_ATMSVC", + "AF_AX25", + "AF_BRIDGE", + "AF_ECONET", + "AF_KEY", + "AF_LLC", + "AF_NETBEUI", + "AF_NETROM", + "AF_PPPOX", + "AF_ROSE", + "AF_SECURITY", + "AF_WANPIPE", + "AF_X25", + "MSG_CMSG_CLOEXEC", + "MSG_CONFIRM", + "MSG_FASTOPEN", + "MSG_MORE", + ] + +if sys.platform != "win32" and sys.platform != "darwin" and sys.version_info >= (3, 11): + from _socket import IP_BIND_ADDRESS_NO_PORT as IP_BIND_ADDRESS_NO_PORT + + __all__ += ["IP_BIND_ADDRESS_NO_PORT"] + if sys.platform != "win32": from _socket import ( CMSG_LEN as CMSG_LEN, CMSG_SPACE as CMSG_SPACE, EAI_ADDRFAMILY as EAI_ADDRFAMILY, - EAI_BADHINTS as EAI_BADHINTS, - EAI_MAX as EAI_MAX, EAI_OVERFLOW as EAI_OVERFLOW, - EAI_PROTOCOL as EAI_PROTOCOL, EAI_SYSTEM as EAI_SYSTEM, IP_DEFAULT_MULTICAST_LOOP as IP_DEFAULT_MULTICAST_LOOP, IP_DEFAULT_MULTICAST_TTL as IP_DEFAULT_MULTICAST_TTL, @@ -237,23 +453,45 @@ if sys.platform != "win32": IP_RECVOPTS as IP_RECVOPTS, IP_RECVRETOPTS as IP_RECVRETOPTS, IP_RETOPTS as IP_RETOPTS, - IPPROTO_EON as IPPROTO_EON, IPPROTO_GRE as IPPROTO_GRE, - IPPROTO_HELLO as IPPROTO_HELLO, - IPPROTO_IPCOMP as IPPROTO_IPCOMP, IPPROTO_IPIP as IPPROTO_IPIP, IPPROTO_RSVP as IPPROTO_RSVP, IPPROTO_TP as IPPROTO_TP, - IPPROTO_XTP as IPPROTO_XTP, IPV6_RTHDR_TYPE_0 as IPV6_RTHDR_TYPE_0, - LOCAL_PEERCRED as LOCAL_PEERCRED, - SCM_CREDS as SCM_CREDS, SCM_RIGHTS as SCM_RIGHTS, SO_REUSEPORT as SO_REUSEPORT, TCP_NOTSENT_LOWAT as TCP_NOTSENT_LOWAT, sethostname as sethostname, ) + __all__ += [ + "CMSG_LEN", + "CMSG_SPACE", + "EAI_ADDRFAMILY", + "EAI_OVERFLOW", + "EAI_SYSTEM", + "IP_DEFAULT_MULTICAST_LOOP", + "IP_DEFAULT_MULTICAST_TTL", + "IP_MAX_MEMBERSHIPS", + "IP_RECVOPTS", + "IP_RECVRETOPTS", + "IP_RETOPTS", + "IPPROTO_GRE", + "IPPROTO_IPIP", + "IPPROTO_RSVP", + "IPPROTO_TP", + "IPV6_RTHDR_TYPE_0", + "SCM_RIGHTS", + "SO_REUSEPORT", + "TCP_NOTSENT_LOWAT", + "sethostname", + "AF_ROUTE", + "AF_UNIX", + "MSG_DONTWAIT", + "MSG_EOR", + "MSG_NOSIGNAL", + ] + if sys.platform != "darwin" or sys.version_info >= (3, 9): from _socket import ( IPV6_DSTOPTS as IPV6_DSTOPTS, @@ -265,19 +503,36 @@ if sys.platform != "win32": IPV6_RECVPATHMTU as IPV6_RECVPATHMTU, IPV6_RECVPKTINFO as IPV6_RECVPKTINFO, IPV6_RTHDRDSTOPTS as IPV6_RTHDRDSTOPTS, - IPV6_USE_MIN_MTU as IPV6_USE_MIN_MTU, ) -if sys.platform != "darwin": + __all__ += [ + "IPV6_DSTOPTS", + "IPV6_NEXTHOP", + "IPV6_PATHMTU", + "IPV6_RECVDSTOPTS", + "IPV6_RECVHOPLIMIT", + "IPV6_RECVHOPOPTS", + "IPV6_RECVPATHMTU", + "IPV6_RECVPKTINFO", + "IPV6_RTHDRDSTOPTS", + ] + +if sys.platform != "darwin" and sys.platform != "linux": if sys.platform != "win32" or sys.version_info >= (3, 9): from _socket import BDADDR_ANY as BDADDR_ANY, BDADDR_LOCAL as BDADDR_LOCAL, BTPROTO_RFCOMM as BTPROTO_RFCOMM + __all__ += ["BDADDR_ANY", "BDADDR_LOCAL", "BTPROTO_RFCOMM"] + if sys.platform == "darwin" and sys.version_info >= (3, 10): from _socket import TCP_KEEPALIVE as TCP_KEEPALIVE + __all__ += ["TCP_KEEPALIVE"] + if sys.platform == "darwin" and sys.version_info >= (3, 11): from _socket import TCP_CONNECTION_INFO as TCP_CONNECTION_INFO + __all__ += ["TCP_CONNECTION_INFO"] + if sys.platform == "linux": from _socket import ( ALG_OP_DECRYPT as ALG_OP_DECRYPT, @@ -321,7 +576,6 @@ if sys.platform == "linux": CAN_ERR_MASK as CAN_ERR_MASK, CAN_ISOTP as CAN_ISOTP, CAN_RAW as CAN_RAW, - CAN_RAW_ERR_FILTER as CAN_RAW_ERR_FILTER, CAN_RAW_FD_FRAMES as CAN_RAW_FD_FRAMES, CAN_RAW_FILTER as CAN_RAW_FILTER, CAN_RAW_LOOPBACK as CAN_RAW_LOOPBACK, @@ -329,19 +583,13 @@ if sys.platform == "linux": CAN_RTR_FLAG as CAN_RTR_FLAG, CAN_SFF_MASK as CAN_SFF_MASK, IOCTL_VM_SOCKETS_GET_LOCAL_CID as IOCTL_VM_SOCKETS_GET_LOCAL_CID, - NETLINK_ARPD as NETLINK_ARPD, NETLINK_CRYPTO as NETLINK_CRYPTO, NETLINK_DNRTMSG as NETLINK_DNRTMSG, NETLINK_FIREWALL as NETLINK_FIREWALL, NETLINK_IP6_FW as NETLINK_IP6_FW, NETLINK_NFLOG as NETLINK_NFLOG, NETLINK_ROUTE as NETLINK_ROUTE, - NETLINK_ROUTE6 as NETLINK_ROUTE6, - NETLINK_SKIP as NETLINK_SKIP, - NETLINK_TAPBASE as NETLINK_TAPBASE, - NETLINK_TCPDIAG as NETLINK_TCPDIAG, NETLINK_USERSOCK as NETLINK_USERSOCK, - NETLINK_W1 as NETLINK_W1, NETLINK_XFRM as NETLINK_XFRM, PACKET_BROADCAST as PACKET_BROADCAST, PACKET_FASTROUTE as PACKET_FASTROUTE, @@ -358,7 +606,6 @@ if sys.platform == "linux": RDS_CMSG_RDMA_DEST as RDS_CMSG_RDMA_DEST, RDS_CMSG_RDMA_MAP as RDS_CMSG_RDMA_MAP, RDS_CMSG_RDMA_STATUS as RDS_CMSG_RDMA_STATUS, - RDS_CMSG_RDMA_UPDATE as RDS_CMSG_RDMA_UPDATE, RDS_CONG_MONITOR as RDS_CONG_MONITOR, RDS_FREE_MR as RDS_FREE_MR, RDS_GET_MR as RDS_GET_MR, @@ -408,10 +655,130 @@ if sys.platform == "linux": VMADDR_PORT_ANY as VMADDR_PORT_ANY, ) + __all__ += [ + "ALG_OP_DECRYPT", + "ALG_OP_ENCRYPT", + "ALG_OP_SIGN", + "ALG_OP_VERIFY", + "ALG_SET_AEAD_ASSOCLEN", + "ALG_SET_AEAD_AUTHSIZE", + "ALG_SET_IV", + "ALG_SET_KEY", + "ALG_SET_OP", + "ALG_SET_PUBKEY", + "CAN_BCM", + "CAN_BCM_CAN_FD_FRAME", + "CAN_BCM_RX_ANNOUNCE_RESUME", + "CAN_BCM_RX_CHANGED", + "CAN_BCM_RX_CHECK_DLC", + "CAN_BCM_RX_DELETE", + "CAN_BCM_RX_FILTER_ID", + "CAN_BCM_RX_NO_AUTOTIMER", + "CAN_BCM_RX_READ", + "CAN_BCM_RX_RTR_FRAME", + "CAN_BCM_RX_SETUP", + "CAN_BCM_RX_STATUS", + "CAN_BCM_RX_TIMEOUT", + "CAN_BCM_SETTIMER", + "CAN_BCM_STARTTIMER", + "CAN_BCM_TX_ANNOUNCE", + "CAN_BCM_TX_COUNTEVT", + "CAN_BCM_TX_CP_CAN_ID", + "CAN_BCM_TX_DELETE", + "CAN_BCM_TX_EXPIRED", + "CAN_BCM_TX_READ", + "CAN_BCM_TX_RESET_MULTI_IDX", + "CAN_BCM_TX_SEND", + "CAN_BCM_TX_SETUP", + "CAN_BCM_TX_STATUS", + "CAN_EFF_FLAG", + "CAN_EFF_MASK", + "CAN_ERR_FLAG", + "CAN_ERR_MASK", + "CAN_ISOTP", + "CAN_RAW", + "CAN_RAW_FD_FRAMES", + "CAN_RAW_FILTER", + "CAN_RAW_LOOPBACK", + "CAN_RAW_RECV_OWN_MSGS", + "CAN_RTR_FLAG", + "CAN_SFF_MASK", + "IOCTL_VM_SOCKETS_GET_LOCAL_CID", + "NETLINK_CRYPTO", + "NETLINK_DNRTMSG", + "NETLINK_FIREWALL", + "NETLINK_IP6_FW", + "NETLINK_NFLOG", + "NETLINK_ROUTE", + "NETLINK_USERSOCK", + "NETLINK_XFRM", + "PACKET_BROADCAST", + "PACKET_FASTROUTE", + "PACKET_HOST", + "PACKET_LOOPBACK", + "PACKET_MULTICAST", + "PACKET_OTHERHOST", + "PACKET_OUTGOING", + "PF_CAN", + "PF_PACKET", + "PF_RDS", + "SO_VM_SOCKETS_BUFFER_MAX_SIZE", + "SO_VM_SOCKETS_BUFFER_MIN_SIZE", + "SO_VM_SOCKETS_BUFFER_SIZE", + "SOL_ALG", + "SOL_CAN_BASE", + "SOL_CAN_RAW", + "SOL_RDS", + "SOL_TIPC", + "TIPC_ADDR_ID", + "TIPC_ADDR_NAME", + "TIPC_ADDR_NAMESEQ", + "TIPC_CFG_SRV", + "TIPC_CLUSTER_SCOPE", + "TIPC_CONN_TIMEOUT", + "TIPC_CRITICAL_IMPORTANCE", + "TIPC_DEST_DROPPABLE", + "TIPC_HIGH_IMPORTANCE", + "TIPC_IMPORTANCE", + "TIPC_LOW_IMPORTANCE", + "TIPC_MEDIUM_IMPORTANCE", + "TIPC_NODE_SCOPE", + "TIPC_PUBLISHED", + "TIPC_SRC_DROPPABLE", + "TIPC_SUB_CANCEL", + "TIPC_SUB_PORTS", + "TIPC_SUB_SERVICE", + "TIPC_SUBSCR_TIMEOUT", + "TIPC_TOP_SRV", + "TIPC_WAIT_FOREVER", + "TIPC_WITHDRAWN", + "TIPC_ZONE_SCOPE", + "VM_SOCKETS_INVALID_VERSION", + "VMADDR_CID_ANY", + "VMADDR_CID_HOST", + "VMADDR_PORT_ANY", + "AF_CAN", + "AF_PACKET", + "AF_RDS", + "AF_TIPC", + "AF_ALG", + "AF_NETLINK", + "AF_VSOCK", + "AF_QIPCRTR", + "SOCK_CLOEXEC", + "SOCK_NONBLOCK", + ] + + if sys.version_info < (3, 11): + from _socket import CAN_RAW_ERR_FILTER as CAN_RAW_ERR_FILTER + + __all__ += ["CAN_RAW_ERR_FILTER"] + if sys.platform == "linux" and sys.version_info >= (3, 9): from _socket import ( CAN_J1939 as CAN_J1939, CAN_RAW_JOIN_FILTERS as CAN_RAW_JOIN_FILTERS, + IPPROTO_UDPLITE as IPPROTO_UDPLITE, J1939_EE_INFO_NONE as J1939_EE_INFO_NONE, J1939_EE_INFO_TX_ABORT as J1939_EE_INFO_TX_ABORT, J1939_FILTER_MAX as J1939_FILTER_MAX, @@ -438,11 +805,97 @@ if sys.platform == "linux" and sys.version_info >= (3, 9): UDPLITE_RECV_CSCOV as UDPLITE_RECV_CSCOV, UDPLITE_SEND_CSCOV as UDPLITE_SEND_CSCOV, ) + + __all__ += [ + "CAN_J1939", + "CAN_RAW_JOIN_FILTERS", + "IPPROTO_UDPLITE", + "J1939_EE_INFO_NONE", + "J1939_EE_INFO_TX_ABORT", + "J1939_FILTER_MAX", + "J1939_IDLE_ADDR", + "J1939_MAX_UNICAST_ADDR", + "J1939_NLA_BYTES_ACKED", + "J1939_NLA_PAD", + "J1939_NO_ADDR", + "J1939_NO_NAME", + "J1939_NO_PGN", + "J1939_PGN_ADDRESS_CLAIMED", + "J1939_PGN_ADDRESS_COMMANDED", + "J1939_PGN_MAX", + "J1939_PGN_PDU1_MAX", + "J1939_PGN_REQUEST", + "SCM_J1939_DEST_ADDR", + "SCM_J1939_DEST_NAME", + "SCM_J1939_ERRQUEUE", + "SCM_J1939_PRIO", + "SO_J1939_ERRQUEUE", + "SO_J1939_FILTER", + "SO_J1939_PROMISC", + "SO_J1939_SEND_PRIO", + "UDPLITE_RECV_CSCOV", + "UDPLITE_SEND_CSCOV", + ] if sys.platform == "linux" and sys.version_info >= (3, 10): from _socket import IPPROTO_MPTCP as IPPROTO_MPTCP + + __all__ += ["IPPROTO_MPTCP"] if sys.platform == "linux" and sys.version_info >= (3, 11): from _socket import SO_INCOMING_CPU as SO_INCOMING_CPU + __all__ += ["SO_INCOMING_CPU"] +if sys.platform == "linux" and sys.version_info >= (3, 12): + from _socket import ( + TCP_CC_INFO as TCP_CC_INFO, + TCP_FASTOPEN_CONNECT as TCP_FASTOPEN_CONNECT, + TCP_FASTOPEN_KEY as TCP_FASTOPEN_KEY, + TCP_FASTOPEN_NO_COOKIE as TCP_FASTOPEN_NO_COOKIE, + TCP_INQ as TCP_INQ, + TCP_MD5SIG as TCP_MD5SIG, + TCP_MD5SIG_EXT as TCP_MD5SIG_EXT, + TCP_QUEUE_SEQ as TCP_QUEUE_SEQ, + TCP_REPAIR as TCP_REPAIR, + TCP_REPAIR_OPTIONS as TCP_REPAIR_OPTIONS, + TCP_REPAIR_QUEUE as TCP_REPAIR_QUEUE, + TCP_REPAIR_WINDOW as TCP_REPAIR_WINDOW, + TCP_SAVE_SYN as TCP_SAVE_SYN, + TCP_SAVED_SYN as TCP_SAVED_SYN, + TCP_THIN_DUPACK as TCP_THIN_DUPACK, + TCP_THIN_LINEAR_TIMEOUTS as TCP_THIN_LINEAR_TIMEOUTS, + TCP_TIMESTAMP as TCP_TIMESTAMP, + TCP_TX_DELAY as TCP_TX_DELAY, + TCP_ULP as TCP_ULP, + TCP_ZEROCOPY_RECEIVE as TCP_ZEROCOPY_RECEIVE, + ) + + __all__ += [ + "TCP_CC_INFO", + "TCP_FASTOPEN_CONNECT", + "TCP_FASTOPEN_KEY", + "TCP_FASTOPEN_NO_COOKIE", + "TCP_INQ", + "TCP_MD5SIG", + "TCP_MD5SIG_EXT", + "TCP_QUEUE_SEQ", + "TCP_REPAIR", + "TCP_REPAIR_OPTIONS", + "TCP_REPAIR_QUEUE", + "TCP_REPAIR_WINDOW", + "TCP_SAVED_SYN", + "TCP_SAVE_SYN", + "TCP_THIN_DUPACK", + "TCP_THIN_LINEAR_TIMEOUTS", + "TCP_TIMESTAMP", + "TCP_TX_DELAY", + "TCP_ULP", + "TCP_ZEROCOPY_RECEIVE", + ] + +if sys.platform == "linux" and sys.version_info >= (3, 13): + from _socket import NI_IDN as NI_IDN, SO_BINDTOIFINDEX as SO_BINDTOIFINDEX + + __all__ += ["NI_IDN", "SO_BINDTOIFINDEX"] + if sys.version_info >= (3, 12): from _socket import ( IP_ADD_SOURCE_MEMBERSHIP as IP_ADD_SOURCE_MEMBERSHIP, @@ -452,6 +905,8 @@ if sys.version_info >= (3, 12): IP_UNBLOCK_SOURCE as IP_UNBLOCK_SOURCE, ) + __all__ += ["IP_ADD_SOURCE_MEMBERSHIP", "IP_BLOCK_SOURCE", "IP_DROP_SOURCE_MEMBERSHIP", "IP_PKTINFO", "IP_UNBLOCK_SOURCE"] + if sys.platform == "win32": from _socket import ( HV_GUID_BROADCAST as HV_GUID_BROADCAST, @@ -466,6 +921,20 @@ if sys.version_info >= (3, 12): HVSOCKET_CONNECT_TIMEOUT_MAX as HVSOCKET_CONNECT_TIMEOUT_MAX, HVSOCKET_CONNECTED_SUSPEND as HVSOCKET_CONNECTED_SUSPEND, ) + + __all__ += [ + "HV_GUID_BROADCAST", + "HV_GUID_CHILDREN", + "HV_GUID_LOOPBACK", + "HV_GUID_PARENT", + "HV_GUID_WILDCARD", + "HV_GUID_ZERO", + "HV_PROTOCOL_RAW", + "HVSOCKET_ADDRESS_FLAG_PASSTHRU", + "HVSOCKET_CONNECT_TIMEOUT", + "HVSOCKET_CONNECT_TIMEOUT_MAX", + "HVSOCKET_CONNECTED_SUSPEND", + ] else: from _socket import ( ETHERTYPE_ARP as ETHERTYPE_ARP, @@ -474,18 +943,105 @@ if sys.version_info >= (3, 12): ETHERTYPE_VLAN as ETHERTYPE_VLAN, ) + __all__ += ["ETHERTYPE_ARP", "ETHERTYPE_IP", "ETHERTYPE_IPV6", "ETHERTYPE_VLAN"] + if sys.platform == "linux": from _socket import ETH_P_ALL as ETH_P_ALL + __all__ += ["ETH_P_ALL"] + if sys.platform != "linux" and sys.platform != "win32" and sys.platform != "darwin": # FreeBSD >= 14.0 from _socket import PF_DIVERT as PF_DIVERT + __all__ += ["PF_DIVERT", "AF_DIVERT"] + +if sys.platform != "win32" and sys.version_info >= (3, 9): + __all__ += ["send_fds", "recv_fds"] + +if sys.platform != "win32" or sys.version_info >= (3, 9): + if sys.platform != "linux": + __all__ += ["AF_LINK"] + if sys.platform != "darwin" and sys.platform != "linux": + __all__ += ["AF_BLUETOOTH"] + +if sys.platform == "win32" and sys.version_info >= (3, 12): + __all__ += ["AF_HYPERV"] + +if sys.platform != "win32" and sys.platform != "linux": + from _socket import ( + EAI_BADHINTS as EAI_BADHINTS, + EAI_MAX as EAI_MAX, + EAI_PROTOCOL as EAI_PROTOCOL, + IPPROTO_EON as IPPROTO_EON, + IPPROTO_HELLO as IPPROTO_HELLO, + IPPROTO_IPCOMP as IPPROTO_IPCOMP, + IPPROTO_XTP as IPPROTO_XTP, + LOCAL_PEERCRED as LOCAL_PEERCRED, + SCM_CREDS as SCM_CREDS, + ) + + __all__ += [ + "EAI_BADHINTS", + "EAI_MAX", + "EAI_PROTOCOL", + "IPPROTO_EON", + "IPPROTO_HELLO", + "IPPROTO_IPCOMP", + "IPPROTO_XTP", + "LOCAL_PEERCRED", + "SCM_CREDS", + "AI_DEFAULT", + "AI_MASK", + "AI_V4MAPPED_CFG", + "MSG_EOF", + ] + if sys.platform != "darwin" or sys.version_info >= (3, 9): + from _socket import IPV6_USE_MIN_MTU as IPV6_USE_MIN_MTU + + __all__ += ["IPV6_USE_MIN_MTU"] + +if sys.platform != "win32" and sys.platform != "darwin" and sys.platform != "linux": + from _socket import ( + IPPROTO_BIP as IPPROTO_BIP, + IPPROTO_MOBILE as IPPROTO_MOBILE, + IPPROTO_VRRP as IPPROTO_VRRP, + MSG_BTAG as MSG_BTAG, + MSG_ETAG as MSG_ETAG, + SO_SETFIB as SO_SETFIB, + ) + + __all__ += ["SO_SETFIB", "MSG_BTAG", "MSG_ETAG", "IPPROTO_BIP", "IPPROTO_MOBILE", "IPPROTO_VRRP", "MSG_NOTIFICATION"] + +if sys.platform != "linux": + from _socket import ( + IP_RECVDSTADDR as IP_RECVDSTADDR, + IPPROTO_GGP as IPPROTO_GGP, + IPPROTO_IPV4 as IPPROTO_IPV4, + IPPROTO_MAX as IPPROTO_MAX, + IPPROTO_ND as IPPROTO_ND, + SO_USELOOPBACK as SO_USELOOPBACK, + ) + + __all__ += ["IPPROTO_GGP", "IPPROTO_IPV4", "IPPROTO_MAX", "IPPROTO_ND", "IP_RECVDSTADDR", "SO_USELOOPBACK"] + # Re-exported from errno EBADF: int EAGAIN: int EWOULDBLOCK: int +# These errors are implemented in _socket at runtime +# but they consider themselves to live in socket so we'll put them here. +error = OSError + +class herror(error): ... +class gaierror(error): ... + +if sys.version_info >= (3, 10): + timeout = TimeoutError +else: + class timeout(error): ... + class AddressFamily(IntEnum): AF_INET = 2 AF_INET6 = 10 @@ -498,10 +1054,10 @@ class AddressFamily(IntEnum): AF_IRDA = 23 if sys.platform != "win32": AF_ROUTE = 16 - AF_SYSTEM = 32 AF_UNIX = 1 + if sys.platform == "darwin": + AF_SYSTEM = 32 if sys.platform != "win32" and sys.platform != "darwin": - AF_AAL5 = ... AF_ASH = 18 AF_ATMPVC = 8 AF_ATMSVC = 20 @@ -527,8 +1083,9 @@ class AddressFamily(IntEnum): AF_VSOCK = 40 AF_QIPCRTR = 42 if sys.platform != "win32" or sys.version_info >= (3, 9): - AF_LINK = 33 - if sys.platform != "darwin": + if sys.platform != "linux": + AF_LINK = 33 + if sys.platform != "darwin" and sys.platform != "linux": AF_BLUETOOTH = 32 if sys.platform == "win32" and sys.version_info >= (3, 12): AF_HYPERV = 34 @@ -549,11 +1106,12 @@ if sys.platform != "darwin": if sys.platform != "win32": AF_ROUTE = AddressFamily.AF_ROUTE - AF_SYSTEM = AddressFamily.AF_SYSTEM AF_UNIX = AddressFamily.AF_UNIX +if sys.platform == "darwin": + AF_SYSTEM = AddressFamily.AF_SYSTEM + if sys.platform != "win32" and sys.platform != "darwin": - AF_AAL5 = AddressFamily.AF_AAL5 AF_ASH = AddressFamily.AF_ASH AF_ATMPVC = AddressFamily.AF_ATMPVC AF_ATMSVC = AddressFamily.AF_ATMSVC @@ -581,8 +1139,9 @@ if sys.platform == "linux": AF_QIPCRTR = AddressFamily.AF_QIPCRTR if sys.platform != "win32" or sys.version_info >= (3, 9): - AF_LINK = AddressFamily.AF_LINK - if sys.platform != "darwin": + if sys.platform != "linux": + AF_LINK = AddressFamily.AF_LINK + if sys.platform != "darwin" and sys.platform != "linux": AF_BLUETOOTH = AddressFamily.AF_BLUETOOTH if sys.platform == "win32" and sys.version_info >= (3, 12): @@ -617,26 +1176,28 @@ class MsgFlag(IntFlag): MSG_PEEK = 2 MSG_TRUNC = 32 MSG_WAITALL = 256 - - if sys.platform != "darwin": + if sys.platform == "win32": MSG_BCAST = 1024 MSG_MCAST = 2048 + + if sys.platform != "darwin": MSG_ERRQUEUE = 8192 if sys.platform != "win32" and sys.platform != "darwin": - MSG_BTAG = ... MSG_CMSG_CLOEXEC = 1073741821 MSG_CONFIRM = 2048 - MSG_ETAG = ... MSG_FASTOPEN = 536870912 MSG_MORE = 32768 - MSG_NOTIFICATION = ... + + if sys.platform != "win32" and sys.platform != "darwin" and sys.platform != "linux": + MSG_NOTIFICATION = 8192 if sys.platform != "win32": MSG_DONTWAIT = 64 - MSG_EOF = 256 MSG_EOR = 128 MSG_NOSIGNAL = 16384 # sometimes this exists on darwin, sometimes not + if sys.platform != "win32" and sys.platform != "linux": + MSG_EOF = 256 MSG_CTRUNC = MsgFlag.MSG_CTRUNC MSG_DONTROUTE = MsgFlag.MSG_DONTROUTE @@ -645,26 +1206,30 @@ MSG_PEEK = MsgFlag.MSG_PEEK MSG_TRUNC = MsgFlag.MSG_TRUNC MSG_WAITALL = MsgFlag.MSG_WAITALL -if sys.platform != "darwin": +if sys.platform == "win32": MSG_BCAST = MsgFlag.MSG_BCAST MSG_MCAST = MsgFlag.MSG_MCAST + +if sys.platform != "darwin": MSG_ERRQUEUE = MsgFlag.MSG_ERRQUEUE if sys.platform != "win32": MSG_DONTWAIT = MsgFlag.MSG_DONTWAIT - MSG_EOF = MsgFlag.MSG_EOF MSG_EOR = MsgFlag.MSG_EOR MSG_NOSIGNAL = MsgFlag.MSG_NOSIGNAL # Sometimes this exists on darwin, sometimes not if sys.platform != "win32" and sys.platform != "darwin": - MSG_BTAG = MsgFlag.MSG_BTAG MSG_CMSG_CLOEXEC = MsgFlag.MSG_CMSG_CLOEXEC MSG_CONFIRM = MsgFlag.MSG_CONFIRM - MSG_ETAG = MsgFlag.MSG_ETAG MSG_FASTOPEN = MsgFlag.MSG_FASTOPEN MSG_MORE = MsgFlag.MSG_MORE + +if sys.platform != "win32" and sys.platform != "darwin" and sys.platform != "linux": MSG_NOTIFICATION = MsgFlag.MSG_NOTIFICATION +if sys.platform != "win32" and sys.platform != "linux": + MSG_EOF = MsgFlag.MSG_EOF + class AddressInfo(IntFlag): AI_ADDRCONFIG = 32 AI_ALL = 16 @@ -673,7 +1238,7 @@ class AddressInfo(IntFlag): AI_NUMERICSERV = 1024 AI_PASSIVE = 1 AI_V4MAPPED = 8 - if sys.platform != "win32": + if sys.platform != "win32" and sys.platform != "linux": AI_DEFAULT = 1536 AI_MASK = 5127 AI_V4MAPPED_CFG = 512 @@ -686,7 +1251,7 @@ AI_NUMERICSERV = AddressInfo.AI_NUMERICSERV AI_PASSIVE = AddressInfo.AI_PASSIVE AI_V4MAPPED = AddressInfo.AI_V4MAPPED -if sys.platform != "win32": +if sys.platform != "win32" and sys.platform != "linux": AI_DEFAULT = AddressInfo.AI_DEFAULT AI_MASK = AddressInfo.AI_MASK AI_V4MAPPED_CFG = AddressInfo.AI_V4MAPPED_CFG @@ -710,7 +1275,7 @@ class socket(_socket.socket): ) -> None: ... def __enter__(self) -> Self: ... def __exit__(self, *args: Unused) -> None: ... - def dup(self) -> Self: ... # noqa: F811 + def dup(self) -> Self: ... def accept(self) -> tuple[socket, _RetAddress]: ... # Note that the makefile's documented windows-specific behavior is not represented # mode strings with duplicates are intentionally excluded diff --git a/mypy/typeshed/stdlib/sqlite3/__init__.pyi b/mypy/typeshed/stdlib/sqlite3/__init__.pyi index d747be90fd0a..bc0ff6469d5e 100644 --- a/mypy/typeshed/stdlib/sqlite3/__init__.pyi +++ b/mypy/typeshed/stdlib/sqlite3/__init__.pyi @@ -1 +1,467 @@ -from sqlite3.dbapi2 import * +import sys +from _typeshed import MaybeNone, ReadableBuffer, StrOrBytesPath, SupportsLenAndGetItem, Unused +from collections.abc import Callable, Generator, Iterable, Iterator, Mapping, Sequence +from sqlite3.dbapi2 import ( + PARSE_COLNAMES as PARSE_COLNAMES, + PARSE_DECLTYPES as PARSE_DECLTYPES, + SQLITE_ALTER_TABLE as SQLITE_ALTER_TABLE, + SQLITE_ANALYZE as SQLITE_ANALYZE, + SQLITE_ATTACH as SQLITE_ATTACH, + SQLITE_CREATE_INDEX as SQLITE_CREATE_INDEX, + SQLITE_CREATE_TABLE as SQLITE_CREATE_TABLE, + SQLITE_CREATE_TEMP_INDEX as SQLITE_CREATE_TEMP_INDEX, + SQLITE_CREATE_TEMP_TABLE as SQLITE_CREATE_TEMP_TABLE, + SQLITE_CREATE_TEMP_TRIGGER as SQLITE_CREATE_TEMP_TRIGGER, + SQLITE_CREATE_TEMP_VIEW as SQLITE_CREATE_TEMP_VIEW, + SQLITE_CREATE_TRIGGER as SQLITE_CREATE_TRIGGER, + SQLITE_CREATE_VIEW as SQLITE_CREATE_VIEW, + SQLITE_CREATE_VTABLE as SQLITE_CREATE_VTABLE, + SQLITE_DELETE as SQLITE_DELETE, + SQLITE_DENY as SQLITE_DENY, + SQLITE_DETACH as SQLITE_DETACH, + SQLITE_DONE as SQLITE_DONE, + SQLITE_DROP_INDEX as SQLITE_DROP_INDEX, + SQLITE_DROP_TABLE as SQLITE_DROP_TABLE, + SQLITE_DROP_TEMP_INDEX as SQLITE_DROP_TEMP_INDEX, + SQLITE_DROP_TEMP_TABLE as SQLITE_DROP_TEMP_TABLE, + SQLITE_DROP_TEMP_TRIGGER as SQLITE_DROP_TEMP_TRIGGER, + SQLITE_DROP_TEMP_VIEW as SQLITE_DROP_TEMP_VIEW, + SQLITE_DROP_TRIGGER as SQLITE_DROP_TRIGGER, + SQLITE_DROP_VIEW as SQLITE_DROP_VIEW, + SQLITE_DROP_VTABLE as SQLITE_DROP_VTABLE, + SQLITE_FUNCTION as SQLITE_FUNCTION, + SQLITE_IGNORE as SQLITE_IGNORE, + SQLITE_INSERT as SQLITE_INSERT, + SQLITE_OK as SQLITE_OK, + SQLITE_PRAGMA as SQLITE_PRAGMA, + SQLITE_READ as SQLITE_READ, + SQLITE_RECURSIVE as SQLITE_RECURSIVE, + SQLITE_REINDEX as SQLITE_REINDEX, + SQLITE_SAVEPOINT as SQLITE_SAVEPOINT, + SQLITE_SELECT as SQLITE_SELECT, + SQLITE_TRANSACTION as SQLITE_TRANSACTION, + SQLITE_UPDATE as SQLITE_UPDATE, + Binary as Binary, + Date as Date, + DateFromTicks as DateFromTicks, + Time as Time, + TimeFromTicks as TimeFromTicks, + TimestampFromTicks as TimestampFromTicks, + adapt as adapt, + adapters as adapters, + apilevel as apilevel, + complete_statement as complete_statement, + connect as connect, + converters as converters, + enable_callback_tracebacks as enable_callback_tracebacks, + paramstyle as paramstyle, + register_adapter as register_adapter, + register_converter as register_converter, + sqlite_version as sqlite_version, + sqlite_version_info as sqlite_version_info, + threadsafety as threadsafety, + version_info as version_info, +) +from types import TracebackType +from typing import Any, Literal, Protocol, SupportsIndex, TypeVar, final, overload, type_check_only +from typing_extensions import Self, TypeAlias + +if sys.version_info >= (3, 12): + from sqlite3.dbapi2 import ( + LEGACY_TRANSACTION_CONTROL as LEGACY_TRANSACTION_CONTROL, + SQLITE_DBCONFIG_DEFENSIVE as SQLITE_DBCONFIG_DEFENSIVE, + SQLITE_DBCONFIG_DQS_DDL as SQLITE_DBCONFIG_DQS_DDL, + SQLITE_DBCONFIG_DQS_DML as SQLITE_DBCONFIG_DQS_DML, + SQLITE_DBCONFIG_ENABLE_FKEY as SQLITE_DBCONFIG_ENABLE_FKEY, + SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER as SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, + SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION as SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, + SQLITE_DBCONFIG_ENABLE_QPSG as SQLITE_DBCONFIG_ENABLE_QPSG, + SQLITE_DBCONFIG_ENABLE_TRIGGER as SQLITE_DBCONFIG_ENABLE_TRIGGER, + SQLITE_DBCONFIG_ENABLE_VIEW as SQLITE_DBCONFIG_ENABLE_VIEW, + SQLITE_DBCONFIG_LEGACY_ALTER_TABLE as SQLITE_DBCONFIG_LEGACY_ALTER_TABLE, + SQLITE_DBCONFIG_LEGACY_FILE_FORMAT as SQLITE_DBCONFIG_LEGACY_FILE_FORMAT, + SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE as SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, + SQLITE_DBCONFIG_RESET_DATABASE as SQLITE_DBCONFIG_RESET_DATABASE, + SQLITE_DBCONFIG_TRIGGER_EQP as SQLITE_DBCONFIG_TRIGGER_EQP, + SQLITE_DBCONFIG_TRUSTED_SCHEMA as SQLITE_DBCONFIG_TRUSTED_SCHEMA, + SQLITE_DBCONFIG_WRITABLE_SCHEMA as SQLITE_DBCONFIG_WRITABLE_SCHEMA, + ) + +if sys.version_info >= (3, 11): + from sqlite3.dbapi2 import ( + SQLITE_ABORT as SQLITE_ABORT, + SQLITE_ABORT_ROLLBACK as SQLITE_ABORT_ROLLBACK, + SQLITE_AUTH as SQLITE_AUTH, + SQLITE_AUTH_USER as SQLITE_AUTH_USER, + SQLITE_BUSY as SQLITE_BUSY, + SQLITE_BUSY_RECOVERY as SQLITE_BUSY_RECOVERY, + SQLITE_BUSY_SNAPSHOT as SQLITE_BUSY_SNAPSHOT, + SQLITE_BUSY_TIMEOUT as SQLITE_BUSY_TIMEOUT, + SQLITE_CANTOPEN as SQLITE_CANTOPEN, + SQLITE_CANTOPEN_CONVPATH as SQLITE_CANTOPEN_CONVPATH, + SQLITE_CANTOPEN_DIRTYWAL as SQLITE_CANTOPEN_DIRTYWAL, + SQLITE_CANTOPEN_FULLPATH as SQLITE_CANTOPEN_FULLPATH, + SQLITE_CANTOPEN_ISDIR as SQLITE_CANTOPEN_ISDIR, + SQLITE_CANTOPEN_NOTEMPDIR as SQLITE_CANTOPEN_NOTEMPDIR, + SQLITE_CANTOPEN_SYMLINK as SQLITE_CANTOPEN_SYMLINK, + SQLITE_CONSTRAINT as SQLITE_CONSTRAINT, + SQLITE_CONSTRAINT_CHECK as SQLITE_CONSTRAINT_CHECK, + SQLITE_CONSTRAINT_COMMITHOOK as SQLITE_CONSTRAINT_COMMITHOOK, + SQLITE_CONSTRAINT_FOREIGNKEY as SQLITE_CONSTRAINT_FOREIGNKEY, + SQLITE_CONSTRAINT_FUNCTION as SQLITE_CONSTRAINT_FUNCTION, + SQLITE_CONSTRAINT_NOTNULL as SQLITE_CONSTRAINT_NOTNULL, + SQLITE_CONSTRAINT_PINNED as SQLITE_CONSTRAINT_PINNED, + SQLITE_CONSTRAINT_PRIMARYKEY as SQLITE_CONSTRAINT_PRIMARYKEY, + SQLITE_CONSTRAINT_ROWID as SQLITE_CONSTRAINT_ROWID, + SQLITE_CONSTRAINT_TRIGGER as SQLITE_CONSTRAINT_TRIGGER, + SQLITE_CONSTRAINT_UNIQUE as SQLITE_CONSTRAINT_UNIQUE, + SQLITE_CONSTRAINT_VTAB as SQLITE_CONSTRAINT_VTAB, + SQLITE_CORRUPT as SQLITE_CORRUPT, + SQLITE_CORRUPT_INDEX as SQLITE_CORRUPT_INDEX, + SQLITE_CORRUPT_SEQUENCE as SQLITE_CORRUPT_SEQUENCE, + SQLITE_CORRUPT_VTAB as SQLITE_CORRUPT_VTAB, + SQLITE_EMPTY as SQLITE_EMPTY, + SQLITE_ERROR as SQLITE_ERROR, + SQLITE_ERROR_MISSING_COLLSEQ as SQLITE_ERROR_MISSING_COLLSEQ, + SQLITE_ERROR_RETRY as SQLITE_ERROR_RETRY, + SQLITE_ERROR_SNAPSHOT as SQLITE_ERROR_SNAPSHOT, + SQLITE_FORMAT as SQLITE_FORMAT, + SQLITE_FULL as SQLITE_FULL, + SQLITE_INTERNAL as SQLITE_INTERNAL, + SQLITE_INTERRUPT as SQLITE_INTERRUPT, + SQLITE_IOERR as SQLITE_IOERR, + SQLITE_IOERR_ACCESS as SQLITE_IOERR_ACCESS, + SQLITE_IOERR_AUTH as SQLITE_IOERR_AUTH, + SQLITE_IOERR_BEGIN_ATOMIC as SQLITE_IOERR_BEGIN_ATOMIC, + SQLITE_IOERR_BLOCKED as SQLITE_IOERR_BLOCKED, + SQLITE_IOERR_CHECKRESERVEDLOCK as SQLITE_IOERR_CHECKRESERVEDLOCK, + SQLITE_IOERR_CLOSE as SQLITE_IOERR_CLOSE, + SQLITE_IOERR_COMMIT_ATOMIC as SQLITE_IOERR_COMMIT_ATOMIC, + SQLITE_IOERR_CONVPATH as SQLITE_IOERR_CONVPATH, + SQLITE_IOERR_CORRUPTFS as SQLITE_IOERR_CORRUPTFS, + SQLITE_IOERR_DATA as SQLITE_IOERR_DATA, + SQLITE_IOERR_DELETE as SQLITE_IOERR_DELETE, + SQLITE_IOERR_DELETE_NOENT as SQLITE_IOERR_DELETE_NOENT, + SQLITE_IOERR_DIR_CLOSE as SQLITE_IOERR_DIR_CLOSE, + SQLITE_IOERR_DIR_FSYNC as SQLITE_IOERR_DIR_FSYNC, + SQLITE_IOERR_FSTAT as SQLITE_IOERR_FSTAT, + SQLITE_IOERR_FSYNC as SQLITE_IOERR_FSYNC, + SQLITE_IOERR_GETTEMPPATH as SQLITE_IOERR_GETTEMPPATH, + SQLITE_IOERR_LOCK as SQLITE_IOERR_LOCK, + SQLITE_IOERR_MMAP as SQLITE_IOERR_MMAP, + SQLITE_IOERR_NOMEM as SQLITE_IOERR_NOMEM, + SQLITE_IOERR_RDLOCK as SQLITE_IOERR_RDLOCK, + SQLITE_IOERR_READ as SQLITE_IOERR_READ, + SQLITE_IOERR_ROLLBACK_ATOMIC as SQLITE_IOERR_ROLLBACK_ATOMIC, + SQLITE_IOERR_SEEK as SQLITE_IOERR_SEEK, + SQLITE_IOERR_SHMLOCK as SQLITE_IOERR_SHMLOCK, + SQLITE_IOERR_SHMMAP as SQLITE_IOERR_SHMMAP, + SQLITE_IOERR_SHMOPEN as SQLITE_IOERR_SHMOPEN, + SQLITE_IOERR_SHMSIZE as SQLITE_IOERR_SHMSIZE, + SQLITE_IOERR_SHORT_READ as SQLITE_IOERR_SHORT_READ, + SQLITE_IOERR_TRUNCATE as SQLITE_IOERR_TRUNCATE, + SQLITE_IOERR_UNLOCK as SQLITE_IOERR_UNLOCK, + SQLITE_IOERR_VNODE as SQLITE_IOERR_VNODE, + SQLITE_IOERR_WRITE as SQLITE_IOERR_WRITE, + SQLITE_LIMIT_ATTACHED as SQLITE_LIMIT_ATTACHED, + SQLITE_LIMIT_COLUMN as SQLITE_LIMIT_COLUMN, + SQLITE_LIMIT_COMPOUND_SELECT as SQLITE_LIMIT_COMPOUND_SELECT, + SQLITE_LIMIT_EXPR_DEPTH as SQLITE_LIMIT_EXPR_DEPTH, + SQLITE_LIMIT_FUNCTION_ARG as SQLITE_LIMIT_FUNCTION_ARG, + SQLITE_LIMIT_LENGTH as SQLITE_LIMIT_LENGTH, + SQLITE_LIMIT_LIKE_PATTERN_LENGTH as SQLITE_LIMIT_LIKE_PATTERN_LENGTH, + SQLITE_LIMIT_SQL_LENGTH as SQLITE_LIMIT_SQL_LENGTH, + SQLITE_LIMIT_TRIGGER_DEPTH as SQLITE_LIMIT_TRIGGER_DEPTH, + SQLITE_LIMIT_VARIABLE_NUMBER as SQLITE_LIMIT_VARIABLE_NUMBER, + SQLITE_LIMIT_VDBE_OP as SQLITE_LIMIT_VDBE_OP, + SQLITE_LIMIT_WORKER_THREADS as SQLITE_LIMIT_WORKER_THREADS, + SQLITE_LOCKED as SQLITE_LOCKED, + SQLITE_LOCKED_SHAREDCACHE as SQLITE_LOCKED_SHAREDCACHE, + SQLITE_LOCKED_VTAB as SQLITE_LOCKED_VTAB, + SQLITE_MISMATCH as SQLITE_MISMATCH, + SQLITE_MISUSE as SQLITE_MISUSE, + SQLITE_NOLFS as SQLITE_NOLFS, + SQLITE_NOMEM as SQLITE_NOMEM, + SQLITE_NOTADB as SQLITE_NOTADB, + SQLITE_NOTFOUND as SQLITE_NOTFOUND, + SQLITE_NOTICE as SQLITE_NOTICE, + SQLITE_NOTICE_RECOVER_ROLLBACK as SQLITE_NOTICE_RECOVER_ROLLBACK, + SQLITE_NOTICE_RECOVER_WAL as SQLITE_NOTICE_RECOVER_WAL, + SQLITE_OK_LOAD_PERMANENTLY as SQLITE_OK_LOAD_PERMANENTLY, + SQLITE_OK_SYMLINK as SQLITE_OK_SYMLINK, + SQLITE_PERM as SQLITE_PERM, + SQLITE_PROTOCOL as SQLITE_PROTOCOL, + SQLITE_RANGE as SQLITE_RANGE, + SQLITE_READONLY as SQLITE_READONLY, + SQLITE_READONLY_CANTINIT as SQLITE_READONLY_CANTINIT, + SQLITE_READONLY_CANTLOCK as SQLITE_READONLY_CANTLOCK, + SQLITE_READONLY_DBMOVED as SQLITE_READONLY_DBMOVED, + SQLITE_READONLY_DIRECTORY as SQLITE_READONLY_DIRECTORY, + SQLITE_READONLY_RECOVERY as SQLITE_READONLY_RECOVERY, + SQLITE_READONLY_ROLLBACK as SQLITE_READONLY_ROLLBACK, + SQLITE_ROW as SQLITE_ROW, + SQLITE_SCHEMA as SQLITE_SCHEMA, + SQLITE_TOOBIG as SQLITE_TOOBIG, + SQLITE_WARNING as SQLITE_WARNING, + SQLITE_WARNING_AUTOINDEX as SQLITE_WARNING_AUTOINDEX, + ) + +if sys.version_info < (3, 12): + from sqlite3.dbapi2 import enable_shared_cache as enable_shared_cache, version as version + +if sys.version_info < (3, 10): + from sqlite3.dbapi2 import OptimizedUnicode as OptimizedUnicode + +_CursorT = TypeVar("_CursorT", bound=Cursor) +_SqliteData: TypeAlias = str | ReadableBuffer | int | float | None +# Data that is passed through adapters can be of any type accepted by an adapter. +_AdaptedInputData: TypeAlias = _SqliteData | Any +# The Mapping must really be a dict, but making it invariant is too annoying. +_Parameters: TypeAlias = SupportsLenAndGetItem[_AdaptedInputData] | Mapping[str, _AdaptedInputData] + +class _AnyParamWindowAggregateClass(Protocol): + def step(self, *args: Any) -> object: ... + def inverse(self, *args: Any) -> object: ... + def value(self) -> _SqliteData: ... + def finalize(self) -> _SqliteData: ... + +class _WindowAggregateClass(Protocol): + step: Callable[..., object] + inverse: Callable[..., object] + def value(self) -> _SqliteData: ... + def finalize(self) -> _SqliteData: ... + +class _AggregateProtocol(Protocol): + def step(self, value: int, /) -> object: ... + def finalize(self) -> int: ... + +class _SingleParamWindowAggregateClass(Protocol): + def step(self, param: Any, /) -> object: ... + def inverse(self, param: Any, /) -> object: ... + def value(self) -> _SqliteData: ... + def finalize(self) -> _SqliteData: ... + +# These classes are implemented in the C module _sqlite3. At runtime, they're imported +# from there into sqlite3.dbapi2 and from that module to here. However, they +# consider themselves to live in the sqlite3.* namespace, so we'll define them here. + +class Error(Exception): + if sys.version_info >= (3, 11): + sqlite_errorcode: int + sqlite_errorname: str + +class DatabaseError(Error): ... +class DataError(DatabaseError): ... +class IntegrityError(DatabaseError): ... +class InterfaceError(Error): ... +class InternalError(DatabaseError): ... +class NotSupportedError(DatabaseError): ... +class OperationalError(DatabaseError): ... +class ProgrammingError(DatabaseError): ... +class Warning(Exception): ... + +class Connection: + @property + def DataError(self) -> type[DataError]: ... + @property + def DatabaseError(self) -> type[DatabaseError]: ... + @property + def Error(self) -> type[Error]: ... + @property + def IntegrityError(self) -> type[IntegrityError]: ... + @property + def InterfaceError(self) -> type[InterfaceError]: ... + @property + def InternalError(self) -> type[InternalError]: ... + @property + def NotSupportedError(self) -> type[NotSupportedError]: ... + @property + def OperationalError(self) -> type[OperationalError]: ... + @property + def ProgrammingError(self) -> type[ProgrammingError]: ... + @property + def Warning(self) -> type[Warning]: ... + @property + def in_transaction(self) -> bool: ... + isolation_level: str | None # one of '', 'DEFERRED', 'IMMEDIATE' or 'EXCLUSIVE' + @property + def total_changes(self) -> int: ... + if sys.version_info >= (3, 12): + @property + def autocommit(self) -> int: ... + @autocommit.setter + def autocommit(self, val: int) -> None: ... + row_factory: Any + text_factory: Any + if sys.version_info >= (3, 12): + def __init__( + self, + database: StrOrBytesPath, + timeout: float = ..., + detect_types: int = ..., + isolation_level: str | None = ..., + check_same_thread: bool = ..., + factory: type[Connection] | None = ..., + cached_statements: int = ..., + uri: bool = ..., + autocommit: bool = ..., + ) -> None: ... + else: + def __init__( + self, + database: StrOrBytesPath, + timeout: float = ..., + detect_types: int = ..., + isolation_level: str | None = ..., + check_same_thread: bool = ..., + factory: type[Connection] | None = ..., + cached_statements: int = ..., + uri: bool = ..., + ) -> None: ... + + def close(self) -> None: ... + if sys.version_info >= (3, 11): + def blobopen(self, table: str, column: str, row: int, /, *, readonly: bool = False, name: str = "main") -> Blob: ... + + def commit(self) -> None: ... + def create_aggregate(self, name: str, n_arg: int, aggregate_class: Callable[[], _AggregateProtocol]) -> None: ... + if sys.version_info >= (3, 11): + # num_params determines how many params will be passed to the aggregate class. We provide an overload + # for the case where num_params = 1, which is expected to be the common case. + @overload + def create_window_function( + self, name: str, num_params: Literal[1], aggregate_class: Callable[[], _SingleParamWindowAggregateClass] | None, / + ) -> None: ... + # And for num_params = -1, which means the aggregate must accept any number of parameters. + @overload + def create_window_function( + self, name: str, num_params: Literal[-1], aggregate_class: Callable[[], _AnyParamWindowAggregateClass] | None, / + ) -> None: ... + @overload + def create_window_function( + self, name: str, num_params: int, aggregate_class: Callable[[], _WindowAggregateClass] | None, / + ) -> None: ... + + def create_collation(self, name: str, callback: Callable[[str, str], int | SupportsIndex] | None, /) -> None: ... + def create_function( + self, name: str, narg: int, func: Callable[..., _SqliteData] | None, *, deterministic: bool = False + ) -> None: ... + @overload + def cursor(self, factory: None = None) -> Cursor: ... + @overload + def cursor(self, factory: Callable[[Connection], _CursorT]) -> _CursorT: ... + def execute(self, sql: str, parameters: _Parameters = ..., /) -> Cursor: ... + def executemany(self, sql: str, parameters: Iterable[_Parameters], /) -> Cursor: ... + def executescript(self, sql_script: str, /) -> Cursor: ... + def interrupt(self) -> None: ... + if sys.version_info >= (3, 13): + def iterdump(self, *, filter: str | None = None) -> Generator[str, None, None]: ... + else: + def iterdump(self) -> Generator[str, None, None]: ... + + def rollback(self) -> None: ... + def set_authorizer( + self, authorizer_callback: Callable[[int, str | None, str | None, str | None, str | None], int] | None + ) -> None: ... + def set_progress_handler(self, progress_handler: Callable[[], int | None] | None, n: int) -> None: ... + def set_trace_callback(self, trace_callback: Callable[[str], object] | None) -> None: ... + # enable_load_extension and load_extension is not available on python distributions compiled + # without sqlite3 loadable extension support. see footnotes https://docs.python.org/3/library/sqlite3.html#f1 + def enable_load_extension(self, enable: bool, /) -> None: ... + if sys.version_info >= (3, 12): + def load_extension(self, name: str, /, *, entrypoint: str | None = None) -> None: ... + else: + def load_extension(self, name: str, /) -> None: ... + + def backup( + self, + target: Connection, + *, + pages: int = -1, + progress: Callable[[int, int, int], object] | None = None, + name: str = "main", + sleep: float = 0.25, + ) -> None: ... + if sys.version_info >= (3, 11): + def setlimit(self, category: int, limit: int, /) -> int: ... + def getlimit(self, category: int, /) -> int: ... + def serialize(self, *, name: str = "main") -> bytes: ... + def deserialize(self, data: ReadableBuffer, /, *, name: str = "main") -> None: ... + if sys.version_info >= (3, 12): + def getconfig(self, op: int, /) -> bool: ... + def setconfig(self, op: int, enable: bool = True, /) -> bool: ... + + def __call__(self, sql: str, /) -> _Statement: ... + def __enter__(self) -> Self: ... + def __exit__( + self, type: type[BaseException] | None, value: BaseException | None, traceback: TracebackType | None, / + ) -> Literal[False]: ... + +class Cursor: + arraysize: int + @property + def connection(self) -> Connection: ... + # May be None, but using `| MaybeNone` (`| Any`) instead to avoid slightly annoying false positives. + @property + def description(self) -> tuple[tuple[str, None, None, None, None, None, None], ...] | MaybeNone: ... + @property + def lastrowid(self) -> int | None: ... + row_factory: Callable[[Cursor, Row], object] | None + @property + def rowcount(self) -> int: ... + def __init__(self, cursor: Connection, /) -> None: ... + def close(self) -> None: ... + def execute(self, sql: str, parameters: _Parameters = (), /) -> Self: ... + def executemany(self, sql: str, seq_of_parameters: Iterable[_Parameters], /) -> Self: ... + def executescript(self, sql_script: str, /) -> Cursor: ... + def fetchall(self) -> list[Any]: ... + def fetchmany(self, size: int | None = 1) -> list[Any]: ... + # Returns either a row (as created by the row_factory) or None, but + # putting None in the return annotation causes annoying false positives. + def fetchone(self) -> Any: ... + def setinputsizes(self, sizes: Unused, /) -> None: ... # does nothing + def setoutputsize(self, size: Unused, column: Unused = None, /) -> None: ... # does nothing + def __iter__(self) -> Self: ... + def __next__(self) -> Any: ... + +@final +class PrepareProtocol: + def __init__(self, *args: object, **kwargs: object) -> None: ... + +class Row(Sequence[Any]): + def __init__(self, cursor: Cursor, data: tuple[Any, ...], /) -> None: ... + def keys(self) -> list[str]: ... + @overload + def __getitem__(self, key: int | str, /) -> Any: ... + @overload + def __getitem__(self, key: slice, /) -> tuple[Any, ...]: ... + def __hash__(self) -> int: ... + def __iter__(self) -> Iterator[Any]: ... + def __len__(self) -> int: ... + # These return NotImplemented for anything that is not a Row. + def __eq__(self, value: object, /) -> bool: ... + def __ge__(self, value: object, /) -> bool: ... + def __gt__(self, value: object, /) -> bool: ... + def __le__(self, value: object, /) -> bool: ... + def __lt__(self, value: object, /) -> bool: ... + def __ne__(self, value: object, /) -> bool: ... + +# This class is not exposed. It calls itself sqlite3.Statement. +@final +@type_check_only +class _Statement: ... + +if sys.version_info >= (3, 11): + @final + class Blob: + def close(self) -> None: ... + def read(self, length: int = -1, /) -> bytes: ... + def write(self, data: ReadableBuffer, /) -> None: ... + def tell(self) -> int: ... + # whence must be one of os.SEEK_SET, os.SEEK_CUR, os.SEEK_END + def seek(self, offset: int, origin: int = 0, /) -> None: ... + def __len__(self) -> int: ... + def __enter__(self) -> Self: ... + def __exit__(self, type: object, val: object, tb: object, /) -> Literal[False]: ... + def __getitem__(self, key: SupportsIndex | slice, /) -> int: ... + def __setitem__(self, key: SupportsIndex | slice, value: int, /) -> None: ... diff --git a/mypy/typeshed/stdlib/sqlite3/dbapi2.pyi b/mypy/typeshed/stdlib/sqlite3/dbapi2.pyi index 0ee511df4e37..d3ea3ef0e896 100644 --- a/mypy/typeshed/stdlib/sqlite3/dbapi2.pyi +++ b/mypy/typeshed/stdlib/sqlite3/dbapi2.pyi @@ -1,22 +1,226 @@ -import sqlite3 import sys -from _typeshed import ReadableBuffer, StrOrBytesPath, SupportsLenAndGetItem, Unused -from collections.abc import Callable, Generator, Iterable, Iterator, Mapping +from _sqlite3 import ( + PARSE_COLNAMES as PARSE_COLNAMES, + PARSE_DECLTYPES as PARSE_DECLTYPES, + SQLITE_ALTER_TABLE as SQLITE_ALTER_TABLE, + SQLITE_ANALYZE as SQLITE_ANALYZE, + SQLITE_ATTACH as SQLITE_ATTACH, + SQLITE_CREATE_INDEX as SQLITE_CREATE_INDEX, + SQLITE_CREATE_TABLE as SQLITE_CREATE_TABLE, + SQLITE_CREATE_TEMP_INDEX as SQLITE_CREATE_TEMP_INDEX, + SQLITE_CREATE_TEMP_TABLE as SQLITE_CREATE_TEMP_TABLE, + SQLITE_CREATE_TEMP_TRIGGER as SQLITE_CREATE_TEMP_TRIGGER, + SQLITE_CREATE_TEMP_VIEW as SQLITE_CREATE_TEMP_VIEW, + SQLITE_CREATE_TRIGGER as SQLITE_CREATE_TRIGGER, + SQLITE_CREATE_VIEW as SQLITE_CREATE_VIEW, + SQLITE_CREATE_VTABLE as SQLITE_CREATE_VTABLE, + SQLITE_DELETE as SQLITE_DELETE, + SQLITE_DENY as SQLITE_DENY, + SQLITE_DETACH as SQLITE_DETACH, + SQLITE_DONE as SQLITE_DONE, + SQLITE_DROP_INDEX as SQLITE_DROP_INDEX, + SQLITE_DROP_TABLE as SQLITE_DROP_TABLE, + SQLITE_DROP_TEMP_INDEX as SQLITE_DROP_TEMP_INDEX, + SQLITE_DROP_TEMP_TABLE as SQLITE_DROP_TEMP_TABLE, + SQLITE_DROP_TEMP_TRIGGER as SQLITE_DROP_TEMP_TRIGGER, + SQLITE_DROP_TEMP_VIEW as SQLITE_DROP_TEMP_VIEW, + SQLITE_DROP_TRIGGER as SQLITE_DROP_TRIGGER, + SQLITE_DROP_VIEW as SQLITE_DROP_VIEW, + SQLITE_DROP_VTABLE as SQLITE_DROP_VTABLE, + SQLITE_FUNCTION as SQLITE_FUNCTION, + SQLITE_IGNORE as SQLITE_IGNORE, + SQLITE_INSERT as SQLITE_INSERT, + SQLITE_OK as SQLITE_OK, + SQLITE_PRAGMA as SQLITE_PRAGMA, + SQLITE_READ as SQLITE_READ, + SQLITE_RECURSIVE as SQLITE_RECURSIVE, + SQLITE_REINDEX as SQLITE_REINDEX, + SQLITE_SAVEPOINT as SQLITE_SAVEPOINT, + SQLITE_SELECT as SQLITE_SELECT, + SQLITE_TRANSACTION as SQLITE_TRANSACTION, + SQLITE_UPDATE as SQLITE_UPDATE, + adapt as adapt, + adapters as adapters, + complete_statement as complete_statement, + connect as connect, + converters as converters, + enable_callback_tracebacks as enable_callback_tracebacks, + register_adapter as register_adapter, + register_converter as register_converter, + sqlite_version as sqlite_version, +) from datetime import date, datetime, time -from types import TracebackType -from typing import Any, Final, Literal, Protocol, SupportsIndex, TypeVar, final, overload -from typing_extensions import Self, TypeAlias +from sqlite3 import ( + Connection as Connection, + Cursor as Cursor, + DatabaseError as DatabaseError, + DataError as DataError, + Error as Error, + IntegrityError as IntegrityError, + InterfaceError as InterfaceError, + InternalError as InternalError, + NotSupportedError as NotSupportedError, + OperationalError as OperationalError, + PrepareProtocol as PrepareProtocol, + ProgrammingError as ProgrammingError, + Row as Row, + Warning as Warning, +) -_T = TypeVar("_T") -_ConnectionT = TypeVar("_ConnectionT", bound=Connection) -_CursorT = TypeVar("_CursorT", bound=Cursor) -_SqliteData: TypeAlias = str | ReadableBuffer | int | float | None -# Data that is passed through adapters can be of any type accepted by an adapter. -_AdaptedInputData: TypeAlias = _SqliteData | Any -# The Mapping must really be a dict, but making it invariant is too annoying. -_Parameters: TypeAlias = SupportsLenAndGetItem[_AdaptedInputData] | Mapping[str, _AdaptedInputData] -_Adapter: TypeAlias = Callable[[_T], _SqliteData] -_Converter: TypeAlias = Callable[[bytes], Any] +if sys.version_info >= (3, 12): + from _sqlite3 import ( + LEGACY_TRANSACTION_CONTROL as LEGACY_TRANSACTION_CONTROL, + SQLITE_DBCONFIG_DEFENSIVE as SQLITE_DBCONFIG_DEFENSIVE, + SQLITE_DBCONFIG_DQS_DDL as SQLITE_DBCONFIG_DQS_DDL, + SQLITE_DBCONFIG_DQS_DML as SQLITE_DBCONFIG_DQS_DML, + SQLITE_DBCONFIG_ENABLE_FKEY as SQLITE_DBCONFIG_ENABLE_FKEY, + SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER as SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, + SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION as SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, + SQLITE_DBCONFIG_ENABLE_QPSG as SQLITE_DBCONFIG_ENABLE_QPSG, + SQLITE_DBCONFIG_ENABLE_TRIGGER as SQLITE_DBCONFIG_ENABLE_TRIGGER, + SQLITE_DBCONFIG_ENABLE_VIEW as SQLITE_DBCONFIG_ENABLE_VIEW, + SQLITE_DBCONFIG_LEGACY_ALTER_TABLE as SQLITE_DBCONFIG_LEGACY_ALTER_TABLE, + SQLITE_DBCONFIG_LEGACY_FILE_FORMAT as SQLITE_DBCONFIG_LEGACY_FILE_FORMAT, + SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE as SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, + SQLITE_DBCONFIG_RESET_DATABASE as SQLITE_DBCONFIG_RESET_DATABASE, + SQLITE_DBCONFIG_TRIGGER_EQP as SQLITE_DBCONFIG_TRIGGER_EQP, + SQLITE_DBCONFIG_TRUSTED_SCHEMA as SQLITE_DBCONFIG_TRUSTED_SCHEMA, + SQLITE_DBCONFIG_WRITABLE_SCHEMA as SQLITE_DBCONFIG_WRITABLE_SCHEMA, + ) + +if sys.version_info >= (3, 11): + from _sqlite3 import ( + SQLITE_ABORT as SQLITE_ABORT, + SQLITE_ABORT_ROLLBACK as SQLITE_ABORT_ROLLBACK, + SQLITE_AUTH as SQLITE_AUTH, + SQLITE_AUTH_USER as SQLITE_AUTH_USER, + SQLITE_BUSY as SQLITE_BUSY, + SQLITE_BUSY_RECOVERY as SQLITE_BUSY_RECOVERY, + SQLITE_BUSY_SNAPSHOT as SQLITE_BUSY_SNAPSHOT, + SQLITE_BUSY_TIMEOUT as SQLITE_BUSY_TIMEOUT, + SQLITE_CANTOPEN as SQLITE_CANTOPEN, + SQLITE_CANTOPEN_CONVPATH as SQLITE_CANTOPEN_CONVPATH, + SQLITE_CANTOPEN_DIRTYWAL as SQLITE_CANTOPEN_DIRTYWAL, + SQLITE_CANTOPEN_FULLPATH as SQLITE_CANTOPEN_FULLPATH, + SQLITE_CANTOPEN_ISDIR as SQLITE_CANTOPEN_ISDIR, + SQLITE_CANTOPEN_NOTEMPDIR as SQLITE_CANTOPEN_NOTEMPDIR, + SQLITE_CANTOPEN_SYMLINK as SQLITE_CANTOPEN_SYMLINK, + SQLITE_CONSTRAINT as SQLITE_CONSTRAINT, + SQLITE_CONSTRAINT_CHECK as SQLITE_CONSTRAINT_CHECK, + SQLITE_CONSTRAINT_COMMITHOOK as SQLITE_CONSTRAINT_COMMITHOOK, + SQLITE_CONSTRAINT_FOREIGNKEY as SQLITE_CONSTRAINT_FOREIGNKEY, + SQLITE_CONSTRAINT_FUNCTION as SQLITE_CONSTRAINT_FUNCTION, + SQLITE_CONSTRAINT_NOTNULL as SQLITE_CONSTRAINT_NOTNULL, + SQLITE_CONSTRAINT_PINNED as SQLITE_CONSTRAINT_PINNED, + SQLITE_CONSTRAINT_PRIMARYKEY as SQLITE_CONSTRAINT_PRIMARYKEY, + SQLITE_CONSTRAINT_ROWID as SQLITE_CONSTRAINT_ROWID, + SQLITE_CONSTRAINT_TRIGGER as SQLITE_CONSTRAINT_TRIGGER, + SQLITE_CONSTRAINT_UNIQUE as SQLITE_CONSTRAINT_UNIQUE, + SQLITE_CONSTRAINT_VTAB as SQLITE_CONSTRAINT_VTAB, + SQLITE_CORRUPT as SQLITE_CORRUPT, + SQLITE_CORRUPT_INDEX as SQLITE_CORRUPT_INDEX, + SQLITE_CORRUPT_SEQUENCE as SQLITE_CORRUPT_SEQUENCE, + SQLITE_CORRUPT_VTAB as SQLITE_CORRUPT_VTAB, + SQLITE_EMPTY as SQLITE_EMPTY, + SQLITE_ERROR as SQLITE_ERROR, + SQLITE_ERROR_MISSING_COLLSEQ as SQLITE_ERROR_MISSING_COLLSEQ, + SQLITE_ERROR_RETRY as SQLITE_ERROR_RETRY, + SQLITE_ERROR_SNAPSHOT as SQLITE_ERROR_SNAPSHOT, + SQLITE_FORMAT as SQLITE_FORMAT, + SQLITE_FULL as SQLITE_FULL, + SQLITE_INTERNAL as SQLITE_INTERNAL, + SQLITE_INTERRUPT as SQLITE_INTERRUPT, + SQLITE_IOERR as SQLITE_IOERR, + SQLITE_IOERR_ACCESS as SQLITE_IOERR_ACCESS, + SQLITE_IOERR_AUTH as SQLITE_IOERR_AUTH, + SQLITE_IOERR_BEGIN_ATOMIC as SQLITE_IOERR_BEGIN_ATOMIC, + SQLITE_IOERR_BLOCKED as SQLITE_IOERR_BLOCKED, + SQLITE_IOERR_CHECKRESERVEDLOCK as SQLITE_IOERR_CHECKRESERVEDLOCK, + SQLITE_IOERR_CLOSE as SQLITE_IOERR_CLOSE, + SQLITE_IOERR_COMMIT_ATOMIC as SQLITE_IOERR_COMMIT_ATOMIC, + SQLITE_IOERR_CONVPATH as SQLITE_IOERR_CONVPATH, + SQLITE_IOERR_CORRUPTFS as SQLITE_IOERR_CORRUPTFS, + SQLITE_IOERR_DATA as SQLITE_IOERR_DATA, + SQLITE_IOERR_DELETE as SQLITE_IOERR_DELETE, + SQLITE_IOERR_DELETE_NOENT as SQLITE_IOERR_DELETE_NOENT, + SQLITE_IOERR_DIR_CLOSE as SQLITE_IOERR_DIR_CLOSE, + SQLITE_IOERR_DIR_FSYNC as SQLITE_IOERR_DIR_FSYNC, + SQLITE_IOERR_FSTAT as SQLITE_IOERR_FSTAT, + SQLITE_IOERR_FSYNC as SQLITE_IOERR_FSYNC, + SQLITE_IOERR_GETTEMPPATH as SQLITE_IOERR_GETTEMPPATH, + SQLITE_IOERR_LOCK as SQLITE_IOERR_LOCK, + SQLITE_IOERR_MMAP as SQLITE_IOERR_MMAP, + SQLITE_IOERR_NOMEM as SQLITE_IOERR_NOMEM, + SQLITE_IOERR_RDLOCK as SQLITE_IOERR_RDLOCK, + SQLITE_IOERR_READ as SQLITE_IOERR_READ, + SQLITE_IOERR_ROLLBACK_ATOMIC as SQLITE_IOERR_ROLLBACK_ATOMIC, + SQLITE_IOERR_SEEK as SQLITE_IOERR_SEEK, + SQLITE_IOERR_SHMLOCK as SQLITE_IOERR_SHMLOCK, + SQLITE_IOERR_SHMMAP as SQLITE_IOERR_SHMMAP, + SQLITE_IOERR_SHMOPEN as SQLITE_IOERR_SHMOPEN, + SQLITE_IOERR_SHMSIZE as SQLITE_IOERR_SHMSIZE, + SQLITE_IOERR_SHORT_READ as SQLITE_IOERR_SHORT_READ, + SQLITE_IOERR_TRUNCATE as SQLITE_IOERR_TRUNCATE, + SQLITE_IOERR_UNLOCK as SQLITE_IOERR_UNLOCK, + SQLITE_IOERR_VNODE as SQLITE_IOERR_VNODE, + SQLITE_IOERR_WRITE as SQLITE_IOERR_WRITE, + SQLITE_LIMIT_ATTACHED as SQLITE_LIMIT_ATTACHED, + SQLITE_LIMIT_COLUMN as SQLITE_LIMIT_COLUMN, + SQLITE_LIMIT_COMPOUND_SELECT as SQLITE_LIMIT_COMPOUND_SELECT, + SQLITE_LIMIT_EXPR_DEPTH as SQLITE_LIMIT_EXPR_DEPTH, + SQLITE_LIMIT_FUNCTION_ARG as SQLITE_LIMIT_FUNCTION_ARG, + SQLITE_LIMIT_LENGTH as SQLITE_LIMIT_LENGTH, + SQLITE_LIMIT_LIKE_PATTERN_LENGTH as SQLITE_LIMIT_LIKE_PATTERN_LENGTH, + SQLITE_LIMIT_SQL_LENGTH as SQLITE_LIMIT_SQL_LENGTH, + SQLITE_LIMIT_TRIGGER_DEPTH as SQLITE_LIMIT_TRIGGER_DEPTH, + SQLITE_LIMIT_VARIABLE_NUMBER as SQLITE_LIMIT_VARIABLE_NUMBER, + SQLITE_LIMIT_VDBE_OP as SQLITE_LIMIT_VDBE_OP, + SQLITE_LIMIT_WORKER_THREADS as SQLITE_LIMIT_WORKER_THREADS, + SQLITE_LOCKED as SQLITE_LOCKED, + SQLITE_LOCKED_SHAREDCACHE as SQLITE_LOCKED_SHAREDCACHE, + SQLITE_LOCKED_VTAB as SQLITE_LOCKED_VTAB, + SQLITE_MISMATCH as SQLITE_MISMATCH, + SQLITE_MISUSE as SQLITE_MISUSE, + SQLITE_NOLFS as SQLITE_NOLFS, + SQLITE_NOMEM as SQLITE_NOMEM, + SQLITE_NOTADB as SQLITE_NOTADB, + SQLITE_NOTFOUND as SQLITE_NOTFOUND, + SQLITE_NOTICE as SQLITE_NOTICE, + SQLITE_NOTICE_RECOVER_ROLLBACK as SQLITE_NOTICE_RECOVER_ROLLBACK, + SQLITE_NOTICE_RECOVER_WAL as SQLITE_NOTICE_RECOVER_WAL, + SQLITE_OK_LOAD_PERMANENTLY as SQLITE_OK_LOAD_PERMANENTLY, + SQLITE_OK_SYMLINK as SQLITE_OK_SYMLINK, + SQLITE_PERM as SQLITE_PERM, + SQLITE_PROTOCOL as SQLITE_PROTOCOL, + SQLITE_RANGE as SQLITE_RANGE, + SQLITE_READONLY as SQLITE_READONLY, + SQLITE_READONLY_CANTINIT as SQLITE_READONLY_CANTINIT, + SQLITE_READONLY_CANTLOCK as SQLITE_READONLY_CANTLOCK, + SQLITE_READONLY_DBMOVED as SQLITE_READONLY_DBMOVED, + SQLITE_READONLY_DIRECTORY as SQLITE_READONLY_DIRECTORY, + SQLITE_READONLY_RECOVERY as SQLITE_READONLY_RECOVERY, + SQLITE_READONLY_ROLLBACK as SQLITE_READONLY_ROLLBACK, + SQLITE_ROW as SQLITE_ROW, + SQLITE_SCHEMA as SQLITE_SCHEMA, + SQLITE_TOOBIG as SQLITE_TOOBIG, + SQLITE_WARNING as SQLITE_WARNING, + SQLITE_WARNING_AUTOINDEX as SQLITE_WARNING_AUTOINDEX, + ) + from sqlite3 import Blob as Blob + +if sys.version_info < (3, 14): + # Deprecated and removed from _sqlite3 in 3.12, but removed from here in 3.14. + version: str + +if sys.version_info < (3, 12): + if sys.version_info >= (3, 10): + # deprecation wrapper that has a different name for the argument... + def enable_shared_cache(enable: int) -> None: ... + else: + from _sqlite3 import enable_shared_cache as enable_shared_cache + +if sys.version_info < (3, 10): + from _sqlite3 import OptimizedUnicode as OptimizedUnicode paramstyle: str threadsafety: int @@ -35,527 +239,3 @@ if sys.version_info < (3, 14): sqlite_version_info: tuple[int, int, int] Binary = memoryview - -# The remaining definitions are imported from _sqlite3. - -PARSE_COLNAMES: Final[int] -PARSE_DECLTYPES: Final[int] -SQLITE_ALTER_TABLE: Final[int] -SQLITE_ANALYZE: Final[int] -SQLITE_ATTACH: Final[int] -SQLITE_CREATE_INDEX: Final[int] -SQLITE_CREATE_TABLE: Final[int] -SQLITE_CREATE_TEMP_INDEX: Final[int] -SQLITE_CREATE_TEMP_TABLE: Final[int] -SQLITE_CREATE_TEMP_TRIGGER: Final[int] -SQLITE_CREATE_TEMP_VIEW: Final[int] -SQLITE_CREATE_TRIGGER: Final[int] -SQLITE_CREATE_VIEW: Final[int] -SQLITE_CREATE_VTABLE: Final[int] -SQLITE_DELETE: Final[int] -SQLITE_DENY: Final[int] -SQLITE_DETACH: Final[int] -SQLITE_DONE: Final[int] -SQLITE_DROP_INDEX: Final[int] -SQLITE_DROP_TABLE: Final[int] -SQLITE_DROP_TEMP_INDEX: Final[int] -SQLITE_DROP_TEMP_TABLE: Final[int] -SQLITE_DROP_TEMP_TRIGGER: Final[int] -SQLITE_DROP_TEMP_VIEW: Final[int] -SQLITE_DROP_TRIGGER: Final[int] -SQLITE_DROP_VIEW: Final[int] -SQLITE_DROP_VTABLE: Final[int] -SQLITE_FUNCTION: Final[int] -SQLITE_IGNORE: Final[int] -SQLITE_INSERT: Final[int] -SQLITE_OK: Final[int] -if sys.version_info >= (3, 11): - SQLITE_LIMIT_LENGTH: Final[int] - SQLITE_LIMIT_SQL_LENGTH: Final[int] - SQLITE_LIMIT_COLUMN: Final[int] - SQLITE_LIMIT_EXPR_DEPTH: Final[int] - SQLITE_LIMIT_COMPOUND_SELECT: Final[int] - SQLITE_LIMIT_VDBE_OP: Final[int] - SQLITE_LIMIT_FUNCTION_ARG: Final[int] - SQLITE_LIMIT_ATTACHED: Final[int] - SQLITE_LIMIT_LIKE_PATTERN_LENGTH: Final[int] - SQLITE_LIMIT_VARIABLE_NUMBER: Final[int] - SQLITE_LIMIT_TRIGGER_DEPTH: Final[int] - SQLITE_LIMIT_WORKER_THREADS: Final[int] -SQLITE_PRAGMA: Final[int] -SQLITE_READ: Final[int] -SQLITE_REINDEX: Final[int] -SQLITE_RECURSIVE: Final[int] -SQLITE_SAVEPOINT: Final[int] -SQLITE_SELECT: Final[int] -SQLITE_TRANSACTION: Final[int] -SQLITE_UPDATE: Final[int] -adapters: dict[tuple[type[Any], type[Any]], _Adapter[Any]] -converters: dict[str, _Converter] -sqlite_version: str - -if sys.version_info < (3, 14): - # Deprecated in 3.12, removed in 3.14. - version: str - -if sys.version_info >= (3, 11): - SQLITE_ABORT: Final[int] - SQLITE_ABORT_ROLLBACK: Final[int] - SQLITE_AUTH: Final[int] - SQLITE_AUTH_USER: Final[int] - SQLITE_BUSY: Final[int] - SQLITE_BUSY_RECOVERY: Final[int] - SQLITE_BUSY_SNAPSHOT: Final[int] - SQLITE_BUSY_TIMEOUT: Final[int] - SQLITE_CANTOPEN: Final[int] - SQLITE_CANTOPEN_CONVPATH: Final[int] - SQLITE_CANTOPEN_DIRTYWAL: Final[int] - SQLITE_CANTOPEN_FULLPATH: Final[int] - SQLITE_CANTOPEN_ISDIR: Final[int] - SQLITE_CANTOPEN_NOTEMPDIR: Final[int] - SQLITE_CANTOPEN_SYMLINK: Final[int] - SQLITE_CONSTRAINT: Final[int] - SQLITE_CONSTRAINT_CHECK: Final[int] - SQLITE_CONSTRAINT_COMMITHOOK: Final[int] - SQLITE_CONSTRAINT_FOREIGNKEY: Final[int] - SQLITE_CONSTRAINT_FUNCTION: Final[int] - SQLITE_CONSTRAINT_NOTNULL: Final[int] - SQLITE_CONSTRAINT_PINNED: Final[int] - SQLITE_CONSTRAINT_PRIMARYKEY: Final[int] - SQLITE_CONSTRAINT_ROWID: Final[int] - SQLITE_CONSTRAINT_TRIGGER: Final[int] - SQLITE_CONSTRAINT_UNIQUE: Final[int] - SQLITE_CONSTRAINT_VTAB: Final[int] - SQLITE_CORRUPT: Final[int] - SQLITE_CORRUPT_INDEX: Final[int] - SQLITE_CORRUPT_SEQUENCE: Final[int] - SQLITE_CORRUPT_VTAB: Final[int] - SQLITE_EMPTY: Final[int] - SQLITE_ERROR: Final[int] - SQLITE_ERROR_MISSING_COLLSEQ: Final[int] - SQLITE_ERROR_RETRY: Final[int] - SQLITE_ERROR_SNAPSHOT: Final[int] - SQLITE_FORMAT: Final[int] - SQLITE_FULL: Final[int] - SQLITE_INTERNAL: Final[int] - SQLITE_INTERRUPT: Final[int] - SQLITE_IOERR: Final[int] - SQLITE_IOERR_ACCESS: Final[int] - SQLITE_IOERR_AUTH: Final[int] - SQLITE_IOERR_BEGIN_ATOMIC: Final[int] - SQLITE_IOERR_BLOCKED: Final[int] - SQLITE_IOERR_CHECKRESERVEDLOCK: Final[int] - SQLITE_IOERR_CLOSE: Final[int] - SQLITE_IOERR_COMMIT_ATOMIC: Final[int] - SQLITE_IOERR_CONVPATH: Final[int] - SQLITE_IOERR_CORRUPTFS: Final[int] - SQLITE_IOERR_DATA: Final[int] - SQLITE_IOERR_DELETE: Final[int] - SQLITE_IOERR_DELETE_NOENT: Final[int] - SQLITE_IOERR_DIR_CLOSE: Final[int] - SQLITE_IOERR_DIR_FSYNC: Final[int] - SQLITE_IOERR_FSTAT: Final[int] - SQLITE_IOERR_FSYNC: Final[int] - SQLITE_IOERR_GETTEMPPATH: Final[int] - SQLITE_IOERR_LOCK: Final[int] - SQLITE_IOERR_MMAP: Final[int] - SQLITE_IOERR_NOMEM: Final[int] - SQLITE_IOERR_RDLOCK: Final[int] - SQLITE_IOERR_READ: Final[int] - SQLITE_IOERR_ROLLBACK_ATOMIC: Final[int] - SQLITE_IOERR_SEEK: Final[int] - SQLITE_IOERR_SHMLOCK: Final[int] - SQLITE_IOERR_SHMMAP: Final[int] - SQLITE_IOERR_SHMOPEN: Final[int] - SQLITE_IOERR_SHMSIZE: Final[int] - SQLITE_IOERR_SHORT_READ: Final[int] - SQLITE_IOERR_TRUNCATE: Final[int] - SQLITE_IOERR_UNLOCK: Final[int] - SQLITE_IOERR_VNODE: Final[int] - SQLITE_IOERR_WRITE: Final[int] - SQLITE_LOCKED: Final[int] - SQLITE_LOCKED_SHAREDCACHE: Final[int] - SQLITE_LOCKED_VTAB: Final[int] - SQLITE_MISMATCH: Final[int] - SQLITE_MISUSE: Final[int] - SQLITE_NOLFS: Final[int] - SQLITE_NOMEM: Final[int] - SQLITE_NOTADB: Final[int] - SQLITE_NOTFOUND: Final[int] - SQLITE_NOTICE: Final[int] - SQLITE_NOTICE_RECOVER_ROLLBACK: Final[int] - SQLITE_NOTICE_RECOVER_WAL: Final[int] - SQLITE_OK_LOAD_PERMANENTLY: Final[int] - SQLITE_OK_SYMLINK: Final[int] - SQLITE_PERM: Final[int] - SQLITE_PROTOCOL: Final[int] - SQLITE_RANGE: Final[int] - SQLITE_READONLY: Final[int] - SQLITE_READONLY_CANTINIT: Final[int] - SQLITE_READONLY_CANTLOCK: Final[int] - SQLITE_READONLY_DBMOVED: Final[int] - SQLITE_READONLY_DIRECTORY: Final[int] - SQLITE_READONLY_RECOVERY: Final[int] - SQLITE_READONLY_ROLLBACK: Final[int] - SQLITE_ROW: Final[int] - SQLITE_SCHEMA: Final[int] - SQLITE_TOOBIG: Final[int] - SQLITE_WARNING: Final[int] - SQLITE_WARNING_AUTOINDEX: Final[int] - -if sys.version_info >= (3, 12): - LEGACY_TRANSACTION_CONTROL: Final[int] - SQLITE_DBCONFIG_DEFENSIVE: Final[int] - SQLITE_DBCONFIG_DQS_DDL: Final[int] - SQLITE_DBCONFIG_DQS_DML: Final[int] - SQLITE_DBCONFIG_ENABLE_FKEY: Final[int] - SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER: Final[int] - SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION: Final[int] - SQLITE_DBCONFIG_ENABLE_QPSG: Final[int] - SQLITE_DBCONFIG_ENABLE_TRIGGER: Final[int] - SQLITE_DBCONFIG_ENABLE_VIEW: Final[int] - SQLITE_DBCONFIG_LEGACY_ALTER_TABLE: Final[int] - SQLITE_DBCONFIG_LEGACY_FILE_FORMAT: Final[int] - SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE: Final[int] - SQLITE_DBCONFIG_RESET_DATABASE: Final[int] - SQLITE_DBCONFIG_TRIGGER_EQP: Final[int] - SQLITE_DBCONFIG_TRUSTED_SCHEMA: Final[int] - SQLITE_DBCONFIG_WRITABLE_SCHEMA: Final[int] - -# Can take or return anything depending on what's in the registry. -@overload -def adapt(obj: Any, proto: Any, /) -> Any: ... -@overload -def adapt(obj: Any, proto: Any, alt: _T, /) -> Any | _T: ... -def complete_statement(statement: str) -> bool: ... - -if sys.version_info >= (3, 12): - @overload - def connect( - database: StrOrBytesPath, - timeout: float = 5.0, - detect_types: int = 0, - isolation_level: Literal["DEFERRED", "EXCLUSIVE", "IMMEDIATE"] | None = "DEFERRED", - check_same_thread: bool = True, - cached_statements: int = 128, - uri: bool = False, - *, - autocommit: bool = ..., - ) -> Connection: ... - @overload - def connect( - database: StrOrBytesPath, - timeout: float, - detect_types: int, - isolation_level: Literal["DEFERRED", "EXCLUSIVE", "IMMEDIATE"] | None, - check_same_thread: bool, - factory: type[_ConnectionT], - cached_statements: int = 128, - uri: bool = False, - *, - autocommit: bool = ..., - ) -> _ConnectionT: ... - @overload - def connect( - database: StrOrBytesPath, - timeout: float = 5.0, - detect_types: int = 0, - isolation_level: Literal["DEFERRED", "EXCLUSIVE", "IMMEDIATE"] | None = "DEFERRED", - check_same_thread: bool = True, - *, - factory: type[_ConnectionT], - cached_statements: int = 128, - uri: bool = False, - autocommit: bool = ..., - ) -> _ConnectionT: ... - -else: - @overload - def connect( - database: StrOrBytesPath, - timeout: float = 5.0, - detect_types: int = 0, - isolation_level: Literal["DEFERRED", "EXCLUSIVE", "IMMEDIATE"] | None = "DEFERRED", - check_same_thread: bool = True, - cached_statements: int = 128, - uri: bool = False, - ) -> Connection: ... - @overload - def connect( - database: StrOrBytesPath, - timeout: float, - detect_types: int, - isolation_level: Literal["DEFERRED", "EXCLUSIVE", "IMMEDIATE"] | None, - check_same_thread: bool, - factory: type[_ConnectionT], - cached_statements: int = 128, - uri: bool = False, - ) -> _ConnectionT: ... - @overload - def connect( - database: StrOrBytesPath, - timeout: float = 5.0, - detect_types: int = 0, - isolation_level: Literal["DEFERRED", "EXCLUSIVE", "IMMEDIATE"] | None = "DEFERRED", - check_same_thread: bool = True, - *, - factory: type[_ConnectionT], - cached_statements: int = 128, - uri: bool = False, - ) -> _ConnectionT: ... - -def enable_callback_tracebacks(enable: bool, /) -> None: ... - -if sys.version_info < (3, 12): - # takes a pos-or-keyword argument because there is a C wrapper - def enable_shared_cache(enable: int) -> None: ... - -if sys.version_info >= (3, 10): - def register_adapter(type: type[_T], adapter: _Adapter[_T], /) -> None: ... - def register_converter(typename: str, converter: _Converter, /) -> None: ... - -else: - def register_adapter(type: type[_T], caster: _Adapter[_T], /) -> None: ... - def register_converter(name: str, converter: _Converter, /) -> None: ... - -class _AggregateProtocol(Protocol): - def step(self, value: int, /) -> object: ... - def finalize(self) -> int: ... - -class _SingleParamWindowAggregateClass(Protocol): - def step(self, param: Any, /) -> object: ... - def inverse(self, param: Any, /) -> object: ... - def value(self) -> _SqliteData: ... - def finalize(self) -> _SqliteData: ... - -class _AnyParamWindowAggregateClass(Protocol): - def step(self, *args: Any) -> object: ... - def inverse(self, *args: Any) -> object: ... - def value(self) -> _SqliteData: ... - def finalize(self) -> _SqliteData: ... - -class _WindowAggregateClass(Protocol): - step: Callable[..., object] - inverse: Callable[..., object] - def value(self) -> _SqliteData: ... - def finalize(self) -> _SqliteData: ... - -class Connection: - @property - def DataError(self) -> type[sqlite3.DataError]: ... - @property - def DatabaseError(self) -> type[sqlite3.DatabaseError]: ... - @property - def Error(self) -> type[sqlite3.Error]: ... - @property - def IntegrityError(self) -> type[sqlite3.IntegrityError]: ... - @property - def InterfaceError(self) -> type[sqlite3.InterfaceError]: ... - @property - def InternalError(self) -> type[sqlite3.InternalError]: ... - @property - def NotSupportedError(self) -> type[sqlite3.NotSupportedError]: ... - @property - def OperationalError(self) -> type[sqlite3.OperationalError]: ... - @property - def ProgrammingError(self) -> type[sqlite3.ProgrammingError]: ... - @property - def Warning(self) -> type[sqlite3.Warning]: ... - @property - def in_transaction(self) -> bool: ... - isolation_level: str | None # one of '', 'DEFERRED', 'IMMEDIATE' or 'EXCLUSIVE' - @property - def total_changes(self) -> int: ... - if sys.version_info >= (3, 12): - @property - def autocommit(self) -> int: ... - @autocommit.setter - def autocommit(self, val: int) -> None: ... - row_factory: Any - text_factory: Any - if sys.version_info >= (3, 12): - def __init__( - self, - database: StrOrBytesPath, - timeout: float = ..., - detect_types: int = ..., - isolation_level: str | None = ..., - check_same_thread: bool = ..., - factory: type[Connection] | None = ..., - cached_statements: int = ..., - uri: bool = ..., - autocommit: bool = ..., - ) -> None: ... - else: - def __init__( - self, - database: StrOrBytesPath, - timeout: float = ..., - detect_types: int = ..., - isolation_level: str | None = ..., - check_same_thread: bool = ..., - factory: type[Connection] | None = ..., - cached_statements: int = ..., - uri: bool = ..., - ) -> None: ... - - def close(self) -> None: ... - if sys.version_info >= (3, 11): - def blobopen(self, table: str, column: str, row: int, /, *, readonly: bool = False, name: str = "main") -> Blob: ... - - def commit(self) -> None: ... - def create_aggregate(self, name: str, n_arg: int, aggregate_class: Callable[[], _AggregateProtocol]) -> None: ... - if sys.version_info >= (3, 11): - # num_params determines how many params will be passed to the aggregate class. We provide an overload - # for the case where num_params = 1, which is expected to be the common case. - @overload - def create_window_function( - self, name: str, num_params: Literal[1], aggregate_class: Callable[[], _SingleParamWindowAggregateClass] | None, / - ) -> None: ... - # And for num_params = -1, which means the aggregate must accept any number of parameters. - @overload - def create_window_function( - self, name: str, num_params: Literal[-1], aggregate_class: Callable[[], _AnyParamWindowAggregateClass] | None, / - ) -> None: ... - @overload - def create_window_function( - self, name: str, num_params: int, aggregate_class: Callable[[], _WindowAggregateClass] | None, / - ) -> None: ... - - def create_collation(self, name: str, callback: Callable[[str, str], int | SupportsIndex] | None, /) -> None: ... - def create_function( - self, name: str, narg: int, func: Callable[..., _SqliteData] | None, *, deterministic: bool = False - ) -> None: ... - @overload - def cursor(self, factory: None = None) -> Cursor: ... - @overload - def cursor(self, factory: Callable[[Connection], _CursorT]) -> _CursorT: ... - def execute(self, sql: str, parameters: _Parameters = ..., /) -> Cursor: ... - def executemany(self, sql: str, parameters: Iterable[_Parameters], /) -> Cursor: ... - def executescript(self, sql_script: str, /) -> Cursor: ... - def interrupt(self) -> None: ... - if sys.version_info >= (3, 13): - def iterdump(self, *, filter: str | None = None) -> Generator[str, None, None]: ... - else: - def iterdump(self) -> Generator[str, None, None]: ... - - def rollback(self) -> None: ... - def set_authorizer( - self, authorizer_callback: Callable[[int, str | None, str | None, str | None, str | None], int] | None - ) -> None: ... - def set_progress_handler(self, progress_handler: Callable[[], int | None] | None, n: int) -> None: ... - def set_trace_callback(self, trace_callback: Callable[[str], object] | None) -> None: ... - # enable_load_extension and load_extension is not available on python distributions compiled - # without sqlite3 loadable extension support. see footnotes https://docs.python.org/3/library/sqlite3.html#f1 - def enable_load_extension(self, enable: bool, /) -> None: ... - def load_extension(self, name: str, /) -> None: ... - def backup( - self, - target: Connection, - *, - pages: int = -1, - progress: Callable[[int, int, int], object] | None = None, - name: str = "main", - sleep: float = 0.25, - ) -> None: ... - if sys.version_info >= (3, 11): - def setlimit(self, category: int, limit: int, /) -> int: ... - def getlimit(self, category: int, /) -> int: ... - def serialize(self, *, name: str = "main") -> bytes: ... - def deserialize(self, data: ReadableBuffer, /, *, name: str = "main") -> None: ... - if sys.version_info >= (3, 12): - def getconfig(self, op: int, /) -> bool: ... - def setconfig(self, op: int, enable: bool = True, /) -> bool: ... - - def __call__(self, sql: str, /) -> _Statement: ... - def __enter__(self) -> Self: ... - def __exit__( - self, type: type[BaseException] | None, value: BaseException | None, traceback: TracebackType | None, / - ) -> Literal[False]: ... - -class Cursor(Iterator[Any]): - arraysize: int - @property - def connection(self) -> Connection: ... - # May be None, but using | Any instead to avoid slightly annoying false positives. - @property - def description(self) -> tuple[tuple[str, None, None, None, None, None, None], ...] | Any: ... - @property - def lastrowid(self) -> int | None: ... - row_factory: Callable[[Cursor, Row], object] | None - @property - def rowcount(self) -> int: ... - def __init__(self, cursor: Connection, /) -> None: ... - def close(self) -> None: ... - def execute(self, sql: str, parameters: _Parameters = (), /) -> Self: ... - def executemany(self, sql: str, seq_of_parameters: Iterable[_Parameters], /) -> Self: ... - def executescript(self, sql_script: str, /) -> Cursor: ... - def fetchall(self) -> list[Any]: ... - def fetchmany(self, size: int | None = 1) -> list[Any]: ... - # Returns either a row (as created by the row_factory) or None, but - # putting None in the return annotation causes annoying false positives. - def fetchone(self) -> Any: ... - def setinputsizes(self, sizes: Unused, /) -> None: ... # does nothing - def setoutputsize(self, size: Unused, column: Unused = None, /) -> None: ... # does nothing - def __iter__(self) -> Self: ... - def __next__(self) -> Any: ... - -class Error(Exception): - if sys.version_info >= (3, 11): - sqlite_errorcode: int - sqlite_errorname: str - -class DatabaseError(Error): ... -class DataError(DatabaseError): ... -class IntegrityError(DatabaseError): ... -class InterfaceError(Error): ... -class InternalError(DatabaseError): ... -class NotSupportedError(DatabaseError): ... -class OperationalError(DatabaseError): ... - -if sys.version_info < (3, 10): - OptimizedUnicode = str - -@final -class PrepareProtocol: - def __init__(self, *args: object, **kwargs: object) -> None: ... - -class ProgrammingError(DatabaseError): ... - -class Row: - def __init__(self, cursor: Cursor, data: tuple[Any, ...], /) -> None: ... - def keys(self) -> list[str]: ... - @overload - def __getitem__(self, key: int | str, /) -> Any: ... - @overload - def __getitem__(self, key: slice, /) -> tuple[Any, ...]: ... - def __hash__(self) -> int: ... - def __iter__(self) -> Iterator[Any]: ... - def __len__(self) -> int: ... - # These return NotImplemented for anything that is not a Row. - def __eq__(self, value: object, /) -> bool: ... - def __ge__(self, value: object, /) -> bool: ... - def __gt__(self, value: object, /) -> bool: ... - def __le__(self, value: object, /) -> bool: ... - def __lt__(self, value: object, /) -> bool: ... - def __ne__(self, value: object, /) -> bool: ... - -@final -class _Statement: ... - -class Warning(Exception): ... - -if sys.version_info >= (3, 11): - @final - class Blob: - def close(self) -> None: ... - def read(self, length: int = -1, /) -> bytes: ... - def write(self, data: ReadableBuffer, /) -> None: ... - def tell(self) -> int: ... - # whence must be one of os.SEEK_SET, os.SEEK_CUR, os.SEEK_END - def seek(self, offset: int, origin: int = 0, /) -> None: ... - def __len__(self) -> int: ... - def __enter__(self) -> Self: ... - def __exit__(self, type: object, val: object, tb: object, /) -> Literal[False]: ... - def __getitem__(self, key: SupportsIndex | slice, /) -> int: ... - def __setitem__(self, key: SupportsIndex | slice, value: int, /) -> None: ... diff --git a/mypy/typeshed/stdlib/sqlite3/dump.pyi b/mypy/typeshed/stdlib/sqlite3/dump.pyi new file mode 100644 index 000000000000..ed95fa46e1c7 --- /dev/null +++ b/mypy/typeshed/stdlib/sqlite3/dump.pyi @@ -0,0 +1,2 @@ +# This file is intentionally empty. The runtime module contains only +# private functions. diff --git a/mypy/typeshed/stdlib/sre_constants.pyi b/mypy/typeshed/stdlib/sre_constants.pyi index 0c1e484bb07e..383f0f7eb8bd 100644 --- a/mypy/typeshed/stdlib/sre_constants.pyi +++ b/mypy/typeshed/stdlib/sre_constants.pyi @@ -1,4 +1,5 @@ import sys +from re import error as error from typing import Any from typing_extensions import Self @@ -6,14 +7,6 @@ MAXGROUPS: int MAGIC: int -class error(Exception): - msg: str - pattern: str | bytes | None - pos: int | None - lineno: int - colno: int - def __init__(self, msg: str, pattern: str | bytes | None = None, pos: int | None = None) -> None: ... - class _NamedIntConstant(int): name: Any def __new__(cls, value: int, name: str) -> Self: ... diff --git a/mypy/typeshed/stdlib/ssl.pyi b/mypy/typeshed/stdlib/ssl.pyi index 81c68c69ec4e..f587b51d5ac0 100644 --- a/mypy/typeshed/stdlib/ssl.pyi +++ b/mypy/typeshed/stdlib/ssl.pyi @@ -1,18 +1,51 @@ import enum import socket import sys +from _ssl import ( + _DEFAULT_CIPHERS as _DEFAULT_CIPHERS, + _OPENSSL_API_VERSION as _OPENSSL_API_VERSION, + HAS_ALPN as HAS_ALPN, + HAS_ECDH as HAS_ECDH, + HAS_NPN as HAS_NPN, + HAS_SNI as HAS_SNI, + OPENSSL_VERSION as OPENSSL_VERSION, + OPENSSL_VERSION_INFO as OPENSSL_VERSION_INFO, + OPENSSL_VERSION_NUMBER as OPENSSL_VERSION_NUMBER, + HAS_SSLv2 as HAS_SSLv2, + HAS_SSLv3 as HAS_SSLv3, + HAS_TLSv1 as HAS_TLSv1, + HAS_TLSv1_1 as HAS_TLSv1_1, + HAS_TLSv1_2 as HAS_TLSv1_2, + HAS_TLSv1_3 as HAS_TLSv1_3, + MemoryBIO as MemoryBIO, + RAND_add as RAND_add, + RAND_bytes as RAND_bytes, + RAND_status as RAND_status, + SSLSession as SSLSession, + _PasswordType as _PasswordType, # typeshed only, but re-export for other type stubs to use + _SSLContext, +) from _typeshed import ReadableBuffer, StrOrBytesPath, WriteableBuffer from collections.abc import Callable, Iterable -from typing import Any, Literal, NamedTuple, TypedDict, final, overload +from typing import Any, Literal, NamedTuple, TypedDict, overload, type_check_only from typing_extensions import Never, Self, TypeAlias +if sys.version_info >= (3, 13): + from _ssl import HAS_PSK as HAS_PSK + +if sys.version_info < (3, 12): + from _ssl import RAND_pseudo_bytes as RAND_pseudo_bytes + +if sys.version_info < (3, 10): + from _ssl import RAND_egd as RAND_egd + +if sys.platform == "win32": + from _ssl import enum_certificates as enum_certificates, enum_crls as enum_crls + _PCTRTT: TypeAlias = tuple[tuple[str, str], ...] _PCTRTTT: TypeAlias = tuple[_PCTRTT, ...] _PeerCertRetDictType: TypeAlias = dict[str, str | _PCTRTTT | _PCTRTT] _PeerCertRetType: TypeAlias = _PeerCertRetDictType | bytes | None -_EnumRetType: TypeAlias = list[tuple[bytes, str, set[str] | bool]] -_PasswordType: TypeAlias = Callable[[], str | bytes | bytearray] | str | bytes | bytearray - _SrvnmeCbType: TypeAlias = Callable[[SSLSocket | SSLObject, str | None, SSLSocket], int | None] socket_error = OSError @@ -98,15 +131,6 @@ else: _create_default_https_context: Callable[..., SSLContext] -def RAND_bytes(n: int, /) -> bytes: ... - -if sys.version_info < (3, 12): - def RAND_pseudo_bytes(n: int, /) -> tuple[bytes, bool]: ... - -def RAND_status() -> bool: ... -def RAND_egd(path: str) -> None: ... -def RAND_add(string: str | ReadableBuffer, entropy: float, /) -> None: ... - if sys.version_info < (3, 12): def match_hostname(cert: _PeerCertRetDictType, hostname: str) -> None: ... @@ -133,10 +157,6 @@ class DefaultVerifyPaths(NamedTuple): def get_default_verify_paths() -> DefaultVerifyPaths: ... -if sys.platform == "win32": - def enum_certificates(store_name: str) -> _EnumRetType: ... - def enum_crls(store_name: str) -> _EnumRetType: ... - class VerifyMode(enum.IntEnum): CERT_NONE = 0 CERT_OPTIONAL = 1 @@ -229,21 +249,8 @@ if sys.version_info >= (3, 11) or sys.platform == "linux": OP_IGNORE_UNEXPECTED_EOF: Options HAS_NEVER_CHECK_COMMON_NAME: bool -HAS_SSLv2: bool -HAS_SSLv3: bool -HAS_TLSv1: bool -HAS_TLSv1_1: bool -HAS_TLSv1_2: bool -HAS_TLSv1_3: bool -HAS_ALPN: bool -HAS_ECDH: bool -HAS_SNI: bool -HAS_NPN: bool -CHANNEL_BINDING_TYPES: list[str] -OPENSSL_VERSION: str -OPENSSL_VERSION_INFO: tuple[int, int, int, int, int] -OPENSSL_VERSION_NUMBER: int +CHANNEL_BINDING_TYPES: list[str] class AlertDescription(enum.IntEnum): ALERT_DESCRIPTION_ACCESS_DENIED = 49 @@ -302,6 +309,8 @@ ALERT_DESCRIPTION_UNSUPPORTED_CERTIFICATE: AlertDescription ALERT_DESCRIPTION_UNSUPPORTED_EXTENSION: AlertDescription ALERT_DESCRIPTION_USER_CANCELLED: AlertDescription +# This class is not exposed. It calls itself ssl._ASN1Object. +@type_check_only class _ASN1ObjectBase(NamedTuple): nid: int shortname: str @@ -379,17 +388,15 @@ class TLSVersion(enum.IntEnum): TLSv1_2 = 771 TLSv1_3 = 772 -class SSLContext: - check_hostname: bool +class SSLContext(_SSLContext): options: Options verify_flags: VerifyFlags verify_mode: VerifyMode @property - def protocol(self) -> _SSLMethod: ... + def protocol(self) -> _SSLMethod: ... # type: ignore[override] hostname_checks_common_name: bool maximum_version: TLSVersion minimum_version: TLSVersion - sni_callback: Callable[[SSLObject, str, SSLContext], None | int] | None # The following two attributes have class-level defaults. # However, the docs explicitly state that it's OK to override these attributes on instances, # so making these ClassVars wouldn't be appropriate @@ -406,10 +413,6 @@ class SSLContext: else: def __new__(cls, protocol: int = ..., *args: Any, **kwargs: Any) -> Self: ... - def cert_store_stats(self) -> dict[str, int]: ... - def load_cert_chain( - self, certfile: StrOrBytesPath, keyfile: StrOrBytesPath | None = None, password: _PasswordType | None = None - ) -> None: ... def load_default_certs(self, purpose: Purpose = ...) -> None: ... def load_verify_locations( self, @@ -448,7 +451,6 @@ class SSLContext: server_hostname: str | bytes | None = None, session: SSLSession | None = None, ) -> SSLObject: ... - def session_stats(self) -> dict[str, int]: ... class SSLObject: context: SSLContext @@ -483,28 +485,6 @@ class SSLObject: def get_verified_chain(self) -> list[bytes]: ... def get_unverified_chain(self) -> list[bytes]: ... -@final -class MemoryBIO: - pending: int - eof: bool - def read(self, size: int = -1, /) -> bytes: ... - def write(self, b: ReadableBuffer, /) -> int: ... - def write_eof(self) -> None: ... - -@final -class SSLSession: - @property - def has_ticket(self) -> bool: ... - @property - def id(self) -> bytes: ... - @property - def ticket_lifetime_hint(self) -> int: ... - @property - def time(self) -> int: ... - @property - def timeout(self) -> int: ... - def __eq__(self, value: object, /) -> bool: ... - class SSLErrorNumber(enum.IntEnum): SSL_ERROR_EOF = 8 SSL_ERROR_INVALID_ERROR_CODE = 10 diff --git a/mypy/typeshed/stdlib/struct.pyi b/mypy/typeshed/stdlib/struct.pyi index e684632489ea..2c26908746ec 100644 --- a/mypy/typeshed/stdlib/struct.pyi +++ b/mypy/typeshed/stdlib/struct.pyi @@ -1,26 +1,5 @@ -from _typeshed import ReadableBuffer, WriteableBuffer -from collections.abc import Iterator -from typing import Any +from _struct import * __all__ = ["calcsize", "pack", "pack_into", "unpack", "unpack_from", "iter_unpack", "Struct", "error"] class error(Exception): ... - -def pack(fmt: str | bytes, /, *v: Any) -> bytes: ... -def pack_into(fmt: str | bytes, buffer: WriteableBuffer, offset: int, /, *v: Any) -> None: ... -def unpack(format: str | bytes, buffer: ReadableBuffer, /) -> tuple[Any, ...]: ... -def unpack_from(format: str | bytes, /, buffer: ReadableBuffer, offset: int = 0) -> tuple[Any, ...]: ... -def iter_unpack(format: str | bytes, buffer: ReadableBuffer, /) -> Iterator[tuple[Any, ...]]: ... -def calcsize(format: str | bytes, /) -> int: ... - -class Struct: - @property - def format(self) -> str: ... - @property - def size(self) -> int: ... - def __init__(self, format: str | bytes) -> None: ... - def pack(self, *v: Any) -> bytes: ... - def pack_into(self, buffer: WriteableBuffer, offset: int, *v: Any) -> None: ... - def unpack(self, buffer: ReadableBuffer, /) -> tuple[Any, ...]: ... - def unpack_from(self, buffer: ReadableBuffer, offset: int = 0) -> tuple[Any, ...]: ... - def iter_unpack(self, buffer: ReadableBuffer, /) -> Iterator[tuple[Any, ...]]: ... diff --git a/mypy/typeshed/stdlib/subprocess.pyi b/mypy/typeshed/stdlib/subprocess.pyi index 703a5012012c..fef35b56945a 100644 --- a/mypy/typeshed/stdlib/subprocess.pyi +++ b/mypy/typeshed/stdlib/subprocess.pyi @@ -1,5 +1,5 @@ import sys -from _typeshed import ReadableBuffer, StrOrBytesPath +from _typeshed import MaybeNone, ReadableBuffer, StrOrBytesPath from collections.abc import Callable, Collection, Iterable, Mapping, Sequence from types import TracebackType from typing import IO, Any, AnyStr, Final, Generic, Literal, TypeVar, overload @@ -1848,7 +1848,7 @@ class Popen(Generic[AnyStr]): stdout: IO[AnyStr] | None stderr: IO[AnyStr] | None pid: int - returncode: int | Any + returncode: int | MaybeNone universal_newlines: bool if sys.version_info >= (3, 11): diff --git a/mypy/typeshed/stdlib/sys/__init__.pyi b/mypy/typeshed/stdlib/sys/__init__.pyi index d65ddfe3825d..c4b1adca9bc6 100644 --- a/mypy/typeshed/stdlib/sys/__init__.pyi +++ b/mypy/typeshed/stdlib/sys/__init__.pyi @@ -5,14 +5,13 @@ from builtins import object as _object from collections.abc import AsyncGenerator, Callable, Sequence from io import TextIOWrapper from types import FrameType, ModuleType, TracebackType -from typing import Any, Final, Literal, NoReturn, Protocol, TextIO, TypeVar, final +from typing import Any, Final, Literal, NoReturn, Protocol, TextIO, TypeVar, final, type_check_only from typing_extensions import TypeAlias _T = TypeVar("_T") # see https://github.com/python/typeshed/issues/8513#issue-1333671093 for the rationale behind this alias _ExitCode: TypeAlias = str | int | None -_OptExcInfo: TypeAlias = OptExcInfo # noqa: Y047 # TODO: obsolete, remove fall 2022 or later # ----- sys variables ----- if sys.platform != "win32": @@ -90,13 +89,63 @@ _UninstantiableStructseq: TypeAlias = structseq[Any] flags: _flags -if sys.version_info >= (3, 10): - _FlagTuple: TypeAlias = tuple[int, int, int, int, int, int, int, int, int, int, int, int, int, bool, int, int] -else: - _FlagTuple: TypeAlias = tuple[int, int, int, int, int, int, int, int, int, int, int, int, int, bool, int] - +# This class is not exposed at runtime. It calls itself sys.flags. +# As a tuple, it can have a length between 15 and 18. We don't model +# the exact length here because that varies by patch version due to +# the backported security fix int_max_str_digits. The exact length shouldn't +# be relied upon. See #13031 +# This can be re-visited when typeshed drops support for 3.10, +# at which point all supported versions will include int_max_str_digits +# in all patch versions. +# 3.8 and 3.9 are 15 or 16-tuple +# 3.10 is 16 or 17-tuple +# 3.11+ is an 18-tuple. @final -class _flags(_UninstantiableStructseq, _FlagTuple): +@type_check_only +class _flags(_UninstantiableStructseq, tuple[int, ...]): + # `safe_path` was added in py311 + if sys.version_info >= (3, 11): + __match_args__: Final = ( + "debug", + "inspect", + "interactive", + "optimize", + "dont_write_bytecode", + "no_user_site", + "no_site", + "ignore_environment", + "verbose", + "bytes_warning", + "quiet", + "hash_randomization", + "isolated", + "dev_mode", + "utf8_mode", + "warn_default_encoding", + "safe_path", + "int_max_str_digits", + ) + elif sys.version_info >= (3, 10): + __match_args__: Final = ( + "debug", + "inspect", + "interactive", + "optimize", + "dont_write_bytecode", + "no_user_site", + "no_site", + "ignore_environment", + "verbose", + "bytes_warning", + "quiet", + "hash_randomization", + "isolated", + "dev_mode", + "utf8_mode", + "warn_default_encoding", + "int_max_str_digits", + ) + @property def debug(self) -> int: ... @property @@ -129,15 +178,39 @@ class _flags(_UninstantiableStructseq, _FlagTuple): def utf8_mode(self) -> int: ... if sys.version_info >= (3, 10): @property - def warn_default_encoding(self) -> int: ... # undocumented + def warn_default_encoding(self) -> int: ... if sys.version_info >= (3, 11): @property def safe_path(self) -> bool: ... + # Whether or not this exists on lower versions of Python + # may depend on which patch release you're using + # (it was backported to all Python versions on 3.8+ as a security fix) + # Added in: 3.8.14, 3.9.14, 3.10.7 + # and present in all versions of 3.11 and later. + @property + def int_max_str_digits(self) -> int: ... float_info: _float_info +# This class is not exposed at runtime. It calls itself sys.float_info. @final +@type_check_only class _float_info(structseq[float], tuple[float, int, int, float, int, int, int, int, float, int, int]): + if sys.version_info >= (3, 10): + __match_args__: Final = ( + "max", + "max_exp", + "max_10_exp", + "min", + "min_exp", + "min_10_exp", + "dig", + "mant_dig", + "epsilon", + "radix", + "rounds", + ) + @property def max(self) -> float: ... # DBL_MAX @property @@ -163,8 +236,13 @@ class _float_info(structseq[float], tuple[float, int, int, float, int, int, int, hash_info: _hash_info +# This class is not exposed at runtime. It calls itself sys.hash_info. @final +@type_check_only class _hash_info(structseq[Any | int], tuple[int, int, int, int, int, str, int, int, int]): + if sys.version_info >= (3, 10): + __match_args__: Final = ("width", "modulus", "inf", "nan", "imag", "algorithm", "hash_bits", "seed_bits", "cutoff") + @property def width(self) -> int: ... @property @@ -186,6 +264,9 @@ class _hash_info(structseq[Any | int], tuple[int, int, int, int, int, str, int, implementation: _implementation +# This class isn't really a thing. At runtime, implementation is an instance +# of types.SimpleNamespace. This allows for better typing. +@type_check_only class _implementation: name: str version: _version_info @@ -198,8 +279,13 @@ class _implementation: int_info: _int_info +# This class is not exposed at runtime. It calls itself sys.int_info. @final +@type_check_only class _int_info(structseq[int], tuple[int, int, int, int]): + if sys.version_info >= (3, 10): + __match_args__: Final = ("bits_per_digit", "sizeof_digit", "default_max_str_digits", "str_digits_check_threshold") + @property def bits_per_digit(self) -> int: ... @property @@ -212,8 +298,13 @@ class _int_info(structseq[int], tuple[int, int, int, int]): _ThreadInfoName: TypeAlias = Literal["nt", "pthread", "pthread-stubs", "solaris"] _ThreadInfoLock: TypeAlias = Literal["semaphore", "mutex+cond"] | None +# This class is not exposed at runtime. It calls itself sys.thread_info. @final +@type_check_only class _thread_info(_UninstantiableStructseq, tuple[_ThreadInfoName, _ThreadInfoLock, str | None]): + if sys.version_info >= (3, 10): + __match_args__: Final = ("name", "lock", "version") + @property def name(self) -> _ThreadInfoName: ... @property @@ -224,8 +315,13 @@ class _thread_info(_UninstantiableStructseq, tuple[_ThreadInfoName, _ThreadInfoL thread_info: _thread_info _ReleaseLevel: TypeAlias = Literal["alpha", "beta", "candidate", "final"] +# This class is not exposed at runtime. It calls itself sys.version_info. @final +@type_check_only class _version_info(_UninstantiableStructseq, tuple[int, int, int, _ReleaseLevel, int]): + if sys.version_info >= (3, 10): + __match_args__: Final = ("major", "minor", "micro", "releaselevel", "serial") + @property def major(self) -> int: ... @property @@ -318,6 +414,7 @@ if sys.version_info < (3, 9): def callstats() -> tuple[int, int, int, int, int, int, int, int, int, int, int] | None: ... # Doesn't exist at runtime, but exported in the stubs so pytest etc. can annotate their code more easily. +@type_check_only class UnraisableHookArgs(Protocol): exc_type: type[BaseException] exc_value: BaseException | None @@ -333,8 +430,13 @@ def audit(event: str, /, *args: Any) -> None: ... _AsyncgenHook: TypeAlias = Callable[[AsyncGenerator[Any, Any]], None] | None +# This class is not exposed at runtime. It calls itself builtins.asyncgen_hooks. @final +@type_check_only class _asyncgen_hooks(structseq[_AsyncgenHook], tuple[_AsyncgenHook, _AsyncgenHook]): + if sys.version_info >= (3, 10): + __match_args__: Final = ("firstiter", "finalizer") + @property def firstiter(self) -> _AsyncgenHook: ... @property diff --git a/mypy/typeshed/stdlib/tarfile.pyi b/mypy/typeshed/stdlib/tarfile.pyi index e46903bf610f..a7135d8150ee 100644 --- a/mypy/typeshed/stdlib/tarfile.pyi +++ b/mypy/typeshed/stdlib/tarfile.pyi @@ -1,7 +1,7 @@ import bz2 import io import sys -from _typeshed import StrOrBytesPath, StrPath +from _typeshed import StrOrBytesPath, StrPath, SupportsRead from builtins import list as _list # aliases to avoid name clashes with fields named "type" or "list" from collections.abc import Callable, Iterable, Iterator, Mapping from gzip import _ReadableFileobj as _GzipReadableFileobj, _WritableFileobj as _GzipWritableFileobj @@ -103,12 +103,10 @@ PAX_NAME_FIELDS: set[str] ENCODING: str -_FileCreationModes: TypeAlias = Literal["a", "w", "x"] - @overload def open( name: StrOrBytesPath | None = None, - mode: str = "r", + mode: Literal["r", "r:*", "r:", "r:gz", "r:bz2", "r:xz"] = "r", fileobj: IO[bytes] | None = None, bufsize: int = 10240, *, @@ -121,16 +119,124 @@ def open( pax_headers: Mapping[str, str] | None = ..., debug: int | None = ..., errorlevel: int | None = ..., - compresslevel: int | None = ..., +) -> TarFile: ... +@overload +def open( + name: StrOrBytesPath | None, + mode: Literal["x", "x:", "a", "a:", "w", "w:"], + fileobj: _Fileobj | None = None, + bufsize: int = 10240, + *, + format: int | None = ..., + tarinfo: type[TarInfo] | None = ..., + dereference: bool | None = ..., + ignore_zeros: bool | None = ..., + encoding: str | None = ..., + errors: str = ..., + pax_headers: Mapping[str, str] | None = ..., + debug: int | None = ..., + errorlevel: int | None = ..., +) -> TarFile: ... +@overload +def open( + name: StrOrBytesPath | None = None, + *, + mode: Literal["x", "x:", "a", "a:", "w", "w:"], + fileobj: _Fileobj | None = None, + bufsize: int = 10240, + format: int | None = ..., + tarinfo: type[TarInfo] | None = ..., + dereference: bool | None = ..., + ignore_zeros: bool | None = ..., + encoding: str | None = ..., + errors: str = ..., + pax_headers: Mapping[str, str] | None = ..., + debug: int | None = ..., + errorlevel: int | None = ..., +) -> TarFile: ... +@overload +def open( + name: StrOrBytesPath | None, + mode: Literal["x:gz", "x:bz2", "w:gz", "w:bz2"], + fileobj: _Fileobj | None = None, + bufsize: int = 10240, + *, + format: int | None = ..., + tarinfo: type[TarInfo] | None = ..., + dereference: bool | None = ..., + ignore_zeros: bool | None = ..., + encoding: str | None = ..., + errors: str = ..., + pax_headers: Mapping[str, str] | None = ..., + debug: int | None = ..., + errorlevel: int | None = ..., + compresslevel: int = 9, +) -> TarFile: ... +@overload +def open( + name: StrOrBytesPath | None = None, + *, + mode: Literal["x:gz", "x:bz2", "w:gz", "w:bz2"], + fileobj: _Fileobj | None = None, + bufsize: int = 10240, + format: int | None = ..., + tarinfo: type[TarInfo] | None = ..., + dereference: bool | None = ..., + ignore_zeros: bool | None = ..., + encoding: str | None = ..., + errors: str = ..., + pax_headers: Mapping[str, str] | None = ..., + debug: int | None = ..., + errorlevel: int | None = ..., + compresslevel: int = 9, +) -> TarFile: ... +@overload +def open( + name: StrOrBytesPath | None, + mode: Literal["x:xz", "w:xz"], + fileobj: _Fileobj | None = None, + bufsize: int = 10240, + *, + format: int | None = ..., + tarinfo: type[TarInfo] | None = ..., + dereference: bool | None = ..., + ignore_zeros: bool | None = ..., + encoding: str | None = ..., + errors: str = ..., + pax_headers: Mapping[str, str] | None = ..., + debug: int | None = ..., + errorlevel: int | None = ..., preset: Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | None = ..., ) -> TarFile: ... @overload def open( name: StrOrBytesPath | None = None, - mode: _FileCreationModes = ..., + *, + mode: Literal["x:xz", "w:xz"], fileobj: _Fileobj | None = None, bufsize: int = 10240, + format: int | None = ..., + tarinfo: type[TarInfo] | None = ..., + dereference: bool | None = ..., + ignore_zeros: bool | None = ..., + encoding: str | None = ..., + errors: str = ..., + pax_headers: Mapping[str, str] | None = ..., + debug: int | None = ..., + errorlevel: int | None = ..., + preset: Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | None = ..., +) -> TarFile: ... + +# TODO: Temporary fallback for modes containing pipe characters. These don't +# work with mypy 1.10, but this should be fixed with mypy 1.11. +# https://github.com/python/typeshed/issues/12182 +@overload +def open( + name: StrOrBytesPath | None = None, *, + mode: str, + fileobj: IO[bytes] | None = None, + bufsize: int = 10240, format: int | None = ..., tarinfo: type[TarInfo] | None = ..., dereference: bool | None = ..., @@ -140,7 +246,6 @@ def open( pax_headers: Mapping[str, str] | None = ..., debug: int | None = ..., errorlevel: int | None = ..., - compresslevel: int | None = ..., preset: int | None = ..., ) -> TarFile: ... @@ -376,7 +481,7 @@ class TarFile: *, filter: Callable[[TarInfo], TarInfo | None] | None = None, ) -> None: ... - def addfile(self, tarinfo: TarInfo, fileobj: IO[bytes] | None = None) -> None: ... + def addfile(self, tarinfo: TarInfo, fileobj: SupportsRead[bytes] | None = None) -> None: ... def gettarinfo( self, name: StrOrBytesPath | None = None, arcname: str | None = None, fileobj: IO[bytes] | None = None ) -> TarInfo: ... diff --git a/mypy/typeshed/stdlib/termios.pyi b/mypy/typeshed/stdlib/termios.pyi index a5378e40fdf2..5a5a1f53be3c 100644 --- a/mypy/typeshed/stdlib/termios.pyi +++ b/mypy/typeshed/stdlib/termios.pyi @@ -10,58 +10,38 @@ _AttrReturn: TypeAlias = list[Any] if sys.platform != "win32": B0: int - B1000000: int B110: int B115200: int - B1152000: int B1200: int B134: int B150: int - B1500000: int B1800: int B19200: int B200: int - B2000000: int B230400: int B2400: int - B2500000: int B300: int - B3000000: int - B3500000: int B38400: int - B4000000: int - B460800: int B4800: int B50: int - B500000: int B57600: int - B576000: int B600: int B75: int - B921600: int B9600: int BRKINT: int BS0: int BS1: int BSDLY: int - CBAUD: int - CBAUDEX: int - CDEL: int CDSUSP: int CEOF: int CEOL: int - CEOL2: int CEOT: int CERASE: int - CESC: int CFLUSH: int - CIBAUD: int CINTR: int CKILL: int CLNEXT: int CLOCAL: int - CNUL: int - COMMON: int CQUIT: int CR0: int CR1: int @@ -80,7 +60,6 @@ if sys.platform != "win32": CSTOP: int CSTOPB: int CSUSP: int - CSWTCH: int CWERASE: int ECHO: int ECHOCTL: int @@ -101,7 +80,6 @@ if sys.platform != "win32": FIONREAD: int FLUSHO: int HUPCL: int - IBSHIFT: int ICANON: int ICRNL: int IEXTEN: int @@ -109,33 +87,21 @@ if sys.platform != "win32": IGNCR: int IGNPAR: int IMAXBEL: int - INIT_C_CC: int INLCR: int INPCK: int - IOCSIZE_MASK: int - IOCSIZE_SHIFT: int ISIG: int ISTRIP: int - IUCLC: int IXANY: int IXOFF: int IXON: int - N_MOUSE: int - N_PPP: int - N_SLIP: int - N_STRIP: int - N_TTY: int - NCC: int NCCS: int NL0: int NL1: int NLDLY: int NOFLSH: int - NSWTCH: int OCRNL: int OFDEL: int OFILL: int - OLCUC: int ONLCR: int ONLRET: int ONOCR: int @@ -149,9 +115,6 @@ if sys.platform != "win32": TAB2: int TAB3: int TABDLY: int - TCFLSH: int - TCGETA: int - TCGETS: int TCIFLUSH: int TCIOFF: int TCIOFLUSH: int @@ -162,28 +125,11 @@ if sys.platform != "win32": TCSADRAIN: int TCSAFLUSH: int TCSANOW: int - TCSASOFT: int - TCSBRK: int - TCSBRKP: int - TCSETA: int - TCSETAF: int - TCSETAW: int - TCSETS: int - TCSETSF: int - TCSETSW: int - TCXONC: int TIOCCONS: int TIOCEXCL: int TIOCGETD: int - TIOCGICOUNT: int - TIOCGLCKTRMIOS: int TIOCGPGRP: int - TIOCGSERIAL: int - TIOCGSIZE: int - TIOCGSOFTCAR: int TIOCGWINSZ: int - TIOCINQ: int - TIOCLINUX: int TIOCM_CAR: int TIOCM_CD: int TIOCM_CTS: int @@ -198,7 +144,6 @@ if sys.platform != "win32": TIOCMBIC: int TIOCMBIS: int TIOCMGET: int - TIOCMIWAIT: int TIOCMSET: int TIOCNOTTY: int TIOCNXCL: int @@ -212,23 +157,10 @@ if sys.platform != "win32": TIOCPKT_STOP: int TIOCPKT: int TIOCSCTTY: int - TIOCSER_TEMT: int - TIOCSERCONFIG: int - TIOCSERGETLSR: int - TIOCSERGETMULTI: int - TIOCSERGSTRUCT: int - TIOCSERGWILD: int - TIOCSERSETMULTI: int - TIOCSERSWILD: int TIOCSETD: int - TIOCSLCKTRMIOS: int TIOCSPGRP: int - TIOCSSERIAL: int - TIOCSSIZE: int - TIOCSSOFTCAR: int TIOCSTI: int TIOCSWINSZ: int - TIOCTTYGSTRUCT: int TOSTOP: int VDISCARD: int VEOF: int @@ -244,15 +176,119 @@ if sys.platform != "win32": VSTART: int VSTOP: int VSUSP: int - VSWTC: int - VSWTCH: int VT0: int VT1: int VTDLY: int VTIME: int VWERASE: int - XCASE: int - XTABS: int + + if sys.version_info >= (3, 13): + EXTPROC: int + IUTF8: int + + if sys.platform == "darwin" and sys.version_info >= (3, 13): + ALTWERASE: int + B14400: int + B28800: int + B7200: int + B76800: int + CCAR_OFLOW: int + CCTS_OFLOW: int + CDSR_OFLOW: int + CDTR_IFLOW: int + CIGNORE: int + CRTS_IFLOW: int + MDMBUF: int + NL2: int + NL3: int + NOKERNINFO: int + ONOEOT: int + OXTABS: int + VDSUSP: int + VSTATUS: int + + if sys.platform == "darwin" and sys.version_info >= (3, 11): + TIOCGSIZE: int + TIOCSSIZE: int + + if sys.platform == "linux": + B1152000: int + B576000: int + CBAUD: int + CBAUDEX: int + CIBAUD: int + IOCSIZE_MASK: int + IOCSIZE_SHIFT: int + IUCLC: int + N_MOUSE: int + N_PPP: int + N_SLIP: int + N_STRIP: int + N_TTY: int + NCC: int + OLCUC: int + TCFLSH: int + TCGETA: int + TCGETS: int + TCSBRK: int + TCSBRKP: int + TCSETA: int + TCSETAF: int + TCSETAW: int + TCSETS: int + TCSETSF: int + TCSETSW: int + TCXONC: int + TIOCGICOUNT: int + TIOCGLCKTRMIOS: int + TIOCGSERIAL: int + TIOCGSOFTCAR: int + TIOCINQ: int + TIOCLINUX: int + TIOCMIWAIT: int + TIOCTTYGSTRUCT: int + TIOCSER_TEMT: int + TIOCSERCONFIG: int + TIOCSERGETLSR: int + TIOCSERGETMULTI: int + TIOCSERGSTRUCT: int + TIOCSERGWILD: int + TIOCSERSETMULTI: int + TIOCSERSWILD: int + TIOCSLCKTRMIOS: int + TIOCSSERIAL: int + TIOCSSOFTCAR: int + VSWTC: int + VSWTCH: int + XCASE: int + XTABS: int + + if sys.platform != "darwin": + B1000000: int + B1500000: int + B2000000: int + B2500000: int + B3000000: int + B3500000: int + B4000000: int + B460800: int + B500000: int + B921600: int + + if sys.platform != "linux": + TCSASOFT: int + + if sys.platform != "darwin" and sys.platform != "linux": + # not available on FreeBSD either. + CDEL: int + CEOL2: int + CESC: int + CNUL: int + COMMON: int + CSWTCH: int + IBSHIFT: int + INIT_C_CC: int + NSWTCH: int def tcgetattr(fd: FileDescriptorLike, /) -> _AttrReturn: ... def tcsetattr(fd: FileDescriptorLike, when: int, attributes: _Attr, /) -> None: ... diff --git a/mypy/typeshed/stdlib/tkinter/__init__.pyi b/mypy/typeshed/stdlib/tkinter/__init__.pyi index 4d25a04f8eb7..d6a234d67919 100644 --- a/mypy/typeshed/stdlib/tkinter/__init__.pyi +++ b/mypy/typeshed/stdlib/tkinter/__init__.pyi @@ -1,13 +1,18 @@ import _tkinter import sys -from _typeshed import Incomplete, StrEnum, StrOrBytesPath +from _typeshed import Incomplete, MaybeNone, StrOrBytesPath from collections.abc import Callable, Iterable, Mapping, Sequence from tkinter.constants import * from tkinter.font import _FontDescription from types import TracebackType -from typing import Any, Generic, Literal, NamedTuple, TypedDict, TypeVar, overload, type_check_only +from typing import Any, Generic, Literal, NamedTuple, Protocol, TypedDict, TypeVar, overload, type_check_only from typing_extensions import TypeAlias, TypeVarTuple, Unpack, deprecated +if sys.version_info >= (3, 11): + from enum import StrEnum +else: + from enum import Enum + if sys.version_info >= (3, 9): __all__ = [ "TclError", @@ -186,53 +191,99 @@ _XYScrollCommand: TypeAlias = str | Callable[[float, float], object] _TakeFocusValue: TypeAlias = bool | Literal[0, 1, ""] | Callable[[str], bool | None] # -takefocus in manual page named 'options' if sys.version_info >= (3, 11): - class _VersionInfoType(NamedTuple): + @type_check_only + class _VersionInfoTypeBase(NamedTuple): major: int minor: int micro: int releaselevel: str serial: int -class EventType(StrEnum): - Activate = "36" - ButtonPress = "4" - Button = ButtonPress - ButtonRelease = "5" - Circulate = "26" - CirculateRequest = "27" - ClientMessage = "33" - Colormap = "32" - Configure = "22" - ConfigureRequest = "23" - Create = "16" - Deactivate = "37" - Destroy = "17" - Enter = "7" - Expose = "12" - FocusIn = "9" - FocusOut = "10" - GraphicsExpose = "13" - Gravity = "24" - KeyPress = "2" - Key = "2" - KeyRelease = "3" - Keymap = "11" - Leave = "8" - Map = "19" - MapRequest = "20" - Mapping = "34" - Motion = "6" - MouseWheel = "38" - NoExpose = "14" - Property = "28" - Reparent = "21" - ResizeRequest = "25" - Selection = "31" - SelectionClear = "29" - SelectionRequest = "30" - Unmap = "18" - VirtualEvent = "35" - Visibility = "15" + class _VersionInfoType(_VersionInfoTypeBase): ... + +if sys.version_info >= (3, 11): + class EventType(StrEnum): + Activate = "36" + ButtonPress = "4" + Button = ButtonPress + ButtonRelease = "5" + Circulate = "26" + CirculateRequest = "27" + ClientMessage = "33" + Colormap = "32" + Configure = "22" + ConfigureRequest = "23" + Create = "16" + Deactivate = "37" + Destroy = "17" + Enter = "7" + Expose = "12" + FocusIn = "9" + FocusOut = "10" + GraphicsExpose = "13" + Gravity = "24" + KeyPress = "2" + Key = "2" + KeyRelease = "3" + Keymap = "11" + Leave = "8" + Map = "19" + MapRequest = "20" + Mapping = "34" + Motion = "6" + MouseWheel = "38" + NoExpose = "14" + Property = "28" + Reparent = "21" + ResizeRequest = "25" + Selection = "31" + SelectionClear = "29" + SelectionRequest = "30" + Unmap = "18" + VirtualEvent = "35" + Visibility = "15" + +else: + class EventType(str, Enum): + Activate = "36" + ButtonPress = "4" + Button = ButtonPress + ButtonRelease = "5" + Circulate = "26" + CirculateRequest = "27" + ClientMessage = "33" + Colormap = "32" + Configure = "22" + ConfigureRequest = "23" + Create = "16" + Deactivate = "37" + Destroy = "17" + Enter = "7" + Expose = "12" + FocusIn = "9" + FocusOut = "10" + GraphicsExpose = "13" + Gravity = "24" + KeyPress = "2" + Key = "2" + KeyRelease = "3" + Keymap = "11" + Leave = "8" + Map = "19" + MapRequest = "20" + Mapping = "34" + Motion = "6" + MouseWheel = "38" + NoExpose = "14" + Property = "28" + Reparent = "21" + ResizeRequest = "25" + Selection = "31" + SelectionClear = "29" + SelectionRequest = "30" + Unmap = "18" + VirtualEvent = "35" + Visibility = "15" _W = TypeVar("_W", bound=Misc) # Events considered covariant because you should never assign to event.widget. @@ -509,7 +560,7 @@ class Misc: pad: _ScreenUnits = ..., uniform: str = ..., weight: int = ..., - ) -> _GridIndexInfo | Any: ... # can be None but annoying to check + ) -> _GridIndexInfo | MaybeNone: ... # can be None but annoying to check def grid_rowconfigure( self, index: int | str | list[int] | tuple[int, ...], @@ -519,7 +570,7 @@ class Misc: pad: _ScreenUnits = ..., uniform: str = ..., weight: int = ..., - ) -> _GridIndexInfo | Any: ... # can be None but annoying to check + ) -> _GridIndexInfo | MaybeNone: ... # can be None but annoying to check columnconfigure = grid_columnconfigure rowconfigure = grid_rowconfigure def grid_location(self, x: _ScreenUnits, y: _ScreenUnits) -> tuple[int, int]: ... @@ -576,7 +627,8 @@ class Misc: def __getitem__(self, key: str) -> Any: ... def cget(self, key: str) -> Any: ... def configure(self, cnf: Any = None) -> Any: ... - # TODO: config is an alias of configure, but adding that here creates lots of mypy errors + # TODO: config is an alias of configure, but adding that here creates + # conflict with the type of config in the subclasses. See #13149 class CallWrapper: func: Incomplete @@ -3403,11 +3455,14 @@ class OptionMenu(Menubutton): # configure, config, cget are inherited from Menubutton # destroy and __getitem__ are overridden, signature does not change -# Marker to indicate that it is a valid bitmap/photo image. PIL implements compatible versions -# which don't share a class hierarchy. The actual API is a __str__() which returns a valid name, -# not something that type checkers can detect. +# This matches tkinter's image classes (PhotoImage and BitmapImage) +# and PIL's tkinter-compatible class (PIL.ImageTk.PhotoImage), +# but not a plain PIL image that isn't tkinter compatible. +# The reason is that PIL has width and height attributes, not methods. @type_check_only -class _Image: ... +class _Image(Protocol): + def width(self) -> int: ... + def height(self) -> int: ... @type_check_only class _BitmapImageLike(_Image): ... @@ -3426,9 +3481,7 @@ class Image(_Image): def __getitem__(self, key): ... configure: Incomplete config: Incomplete - def height(self) -> int: ... def type(self): ... - def width(self) -> int: ... class PhotoImage(Image, _PhotoImageLike): # This should be kept in sync with PIL.ImageTK.PhotoImage.__init__() diff --git a/mypy/typeshed/stdlib/tkinter/font.pyi b/mypy/typeshed/stdlib/tkinter/font.pyi index 317f3068be63..097c2e4b4382 100644 --- a/mypy/typeshed/stdlib/tkinter/font.pyi +++ b/mypy/typeshed/stdlib/tkinter/font.pyi @@ -1,7 +1,8 @@ import _tkinter +import itertools import sys import tkinter -from typing import Any, Final, Literal, TypedDict, overload +from typing import Any, ClassVar, Final, Literal, TypedDict, overload from typing_extensions import TypeAlias if sys.version_info >= (3, 9): @@ -40,6 +41,7 @@ class _MetricsDict(TypedDict): class Font: name: str delete_font: bool + counter: ClassVar[itertools.count[int]] # undocumented def __init__( self, # In tkinter, 'root' refers to tkinter.Tk by convention, but the code diff --git a/mypy/typeshed/stdlib/tkinter/ttk.pyi b/mypy/typeshed/stdlib/tkinter/ttk.pyi index b851f478140a..dacef0620b22 100644 --- a/mypy/typeshed/stdlib/tkinter/ttk.pyi +++ b/mypy/typeshed/stdlib/tkinter/ttk.pyi @@ -1,6 +1,6 @@ import _tkinter import tkinter -from _typeshed import Incomplete +from _typeshed import Incomplete, MaybeNone from collections.abc import Callable from tkinter.font import _FontDescription from typing import Any, Literal, TypedDict, overload @@ -1156,7 +1156,7 @@ class Treeview(Widget, tkinter.XView, tkinter.YView): background: str = ..., font: _FontDescription = ..., image: tkinter._ImageSpec = ..., - ) -> _TreeviewTagDict | Any: ... # can be None but annoying to check + ) -> _TreeviewTagDict | MaybeNone: ... # can be None but annoying to check @overload def tag_has(self, tagname: str, item: None = None) -> tuple[str, ...]: ... @overload diff --git a/mypy/typeshed/stdlib/tokenize.pyi b/mypy/typeshed/stdlib/tokenize.pyi index 3d2a93865df8..7e9a945cdc46 100644 --- a/mypy/typeshed/stdlib/tokenize.pyi +++ b/mypy/typeshed/stdlib/tokenize.pyi @@ -4,7 +4,7 @@ from collections.abc import Callable, Generator, Iterable, Sequence from re import Pattern from token import * from token import EXACT_TOKEN_TYPES as EXACT_TOKEN_TYPES -from typing import Any, NamedTuple, TextIO +from typing import Any, NamedTuple, TextIO, type_check_only from typing_extensions import TypeAlias __all__ = [ @@ -98,6 +98,8 @@ blank_re: Pattern[bytes] _Position: TypeAlias = tuple[int, int] +# This class is not exposed. It calls itself tokenize.TokenInfo. +@type_check_only class _TokenInfo(NamedTuple): type: int string: str @@ -133,7 +135,7 @@ class Untokenizer: def untokenize(iterable: Iterable[_Token]) -> Any: ... def detect_encoding(readline: Callable[[], bytes | bytearray]) -> tuple[str, Sequence[bytes]]: ... def tokenize(readline: Callable[[], bytes | bytearray]) -> Generator[TokenInfo, None, None]: ... -def generate_tokens(readline: Callable[[], str]) -> Generator[TokenInfo, None, None]: ... # undocumented +def generate_tokens(readline: Callable[[], str]) -> Generator[TokenInfo, None, None]: ... def open(filename: FileDescriptorOrPath) -> TextIO: ... def group(*choices: str) -> str: ... # undocumented def any(*choices: str) -> str: ... # undocumented diff --git a/mypy/typeshed/stdlib/traceback.pyi b/mypy/typeshed/stdlib/traceback.pyi index 075c0f4b9de8..1c4a59de66aa 100644 --- a/mypy/typeshed/stdlib/traceback.pyi +++ b/mypy/typeshed/stdlib/traceback.pyi @@ -231,7 +231,7 @@ class TracebackException: if sys.version_info >= (3, 11): def print(self, *, file: SupportsWrite[str] | None = None, chain: bool = True) -> None: ... -class FrameSummary(Iterable[Any]): +class FrameSummary: if sys.version_info >= (3, 11): def __init__( self, @@ -276,6 +276,8 @@ class FrameSummary(Iterable[Any]): def __getitem__(self, pos: Literal[3]) -> str | None: ... @overload def __getitem__(self, pos: int) -> Any: ... + @overload + def __getitem__(self, pos: slice) -> tuple[Any, ...]: ... def __iter__(self) -> Iterator[Any]: ... def __eq__(self, other: object) -> bool: ... def __len__(self) -> Literal[4]: ... diff --git a/mypy/typeshed/stdlib/turtle.pyi b/mypy/typeshed/stdlib/turtle.pyi index 29d289303927..a2ab728de943 100644 --- a/mypy/typeshed/stdlib/turtle.pyi +++ b/mypy/typeshed/stdlib/turtle.pyi @@ -1,7 +1,7 @@ import sys from collections.abc import Callable, Sequence from tkinter import Canvas, Frame, Misc, PhotoImage, Scrollbar -from typing import Any, ClassVar, overload +from typing import Any, ClassVar, Literal, TypedDict, overload from typing_extensions import Self, TypeAlias __all__ = [ @@ -141,8 +141,18 @@ if sys.version_info < (3, 13): _Color: TypeAlias = str | tuple[float, float, float] _AnyColor: TypeAlias = Any -# TODO: Replace this with a TypedDict once it becomes standardized. -_PenState: TypeAlias = dict[str, Any] +class _PenState(TypedDict): + shown: bool + pendown: bool + pencolor: _Color + fillcolor: _Color + pensize: int + speed: int + resizemode: Literal["auto", "user", "noresize"] + stretchfactor: tuple[float, float] + shearfactor: float + outline: int + tilt: float _Speed: TypeAlias = str | float _PolygonCoords: TypeAlias = Sequence[tuple[float, float]] @@ -283,6 +293,7 @@ class TNavigator: def heading(self) -> float: ... def setheading(self, to_angle: float) -> None: ... def circle(self, radius: float, extent: float | None = None, steps: int | None = None) -> None: ... + def speed(self, s: int | None = 0) -> int | None: ... fd = forward bk = back backward = back @@ -363,7 +374,7 @@ class TPen: st = showturtle ht = hideturtle -class RawTurtle(TPen, TNavigator): +class RawTurtle(TPen, TNavigator): # type: ignore[misc] # Conflicting methods in base classes screen: TurtleScreen screens: ClassVar[list[TurtleScreen]] def __init__( diff --git a/mypy/typeshed/stdlib/types.pyi b/mypy/typeshed/stdlib/types.pyi index 0f6592a9883e..b513bd77468a 100644 --- a/mypy/typeshed/stdlib/types.pyi +++ b/mypy/typeshed/stdlib/types.pyi @@ -1,5 +1,5 @@ import sys -from _typeshed import SupportsKeysAndGetItem +from _typeshed import MaybeNone, SupportsKeysAndGetItem from _typeshed.importlib import LoaderProtocol from collections.abc import ( AsyncGenerator, @@ -337,6 +337,13 @@ class ModuleType: __package__: str | None __path__: MutableSequence[str] __spec__: ModuleSpec | None + # N.B. Although this is the same type as `builtins.object.__doc__`, + # it is deliberately redeclared here. Most symbols declared in the namespace + # of `types.ModuleType` are available as "implicit globals" within a module's + # namespace, but this is not true for symbols declared in the namespace of `builtins.object`. + # Redeclaring `__doc__` here helps some type checkers understand that `__doc__` is available + # as an implicit global in all modules, similar to `__name__`, `__file__`, `__spec__`, etc. + __doc__: str | None def __init__(self, name: str, doc: str | None = ...) -> None: ... # __getattr__ doesn't exist at runtime, # but having it here in typeshed makes dynamic imports @@ -424,6 +431,8 @@ class MethodType: @property def __closure__(self) -> tuple[CellType, ...] | None: ... # inherited from the added function @property + def __code__(self) -> CodeType: ... # inherited from the added function + @property def __defaults__(self) -> tuple[Any, ...] | None: ... # inherited from the added function @property def __func__(self) -> Callable[..., Any]: ... @@ -526,9 +535,9 @@ class FrameType: def f_lasti(self) -> int: ... # see discussion in #6769: f_lineno *can* sometimes be None, # but you should probably file a bug report with CPython if you encounter it being None in the wild. - # An `int | None` annotation here causes too many false-positive errors. + # An `int | None` annotation here causes too many false-positive errors, so applying `int | Any`. @property - def f_lineno(self) -> int | Any: ... + def f_lineno(self) -> int | MaybeNone: ... @property def f_locals(self) -> dict[str, Any]: ... f_trace: Callable[[FrameType, str, Any], Any] | None diff --git a/mypy/typeshed/stdlib/typing.pyi b/mypy/typeshed/stdlib/typing.pyi index ce16d9adff99..8f0d4fbb6a02 100644 --- a/mypy/typeshed/stdlib/typing.pyi +++ b/mypy/typeshed/stdlib/typing.pyi @@ -133,6 +133,8 @@ if sys.version_info >= (3, 13): Any = object() +class _Final: ... + def final(f: _T) -> _T: ... @final class TypeVar: @@ -191,7 +193,7 @@ _promote = object() # N.B. Keep this definition in sync with typing_extensions._SpecialForm @final -class _SpecialForm: +class _SpecialForm(_Final): def __getitem__(self, parameters: Any) -> object: ... if sys.version_info >= (3, 10): def __or__(self, other: Any) -> _SpecialForm: ... @@ -211,8 +213,7 @@ Tuple: _SpecialForm Final: _SpecialForm Literal: _SpecialForm -# TypedDict is a (non-subscriptable) special form. -TypedDict: object +TypedDict: _SpecialForm if sys.version_info >= (3, 11): Self: _SpecialForm @@ -462,7 +463,11 @@ class Generator(Iterator[_YieldT_co], Generic[_YieldT_co, _SendT_contra, _Return @overload @abstractmethod def throw(self, typ: BaseException, val: None = None, tb: TracebackType | None = None, /) -> _YieldT_co: ... - def close(self) -> None: ... + if sys.version_info >= (3, 13): + def close(self) -> _ReturnT_co | None: ... + else: + def close(self) -> None: ... + def __iter__(self) -> Generator[_YieldT_co, _SendT_contra, _ReturnT_co]: ... @property def gi_code(self) -> CodeType: ... @@ -575,7 +580,7 @@ class Collection(Iterable[_T_co], Container[_T_co], Protocol[_T_co]): @abstractmethod def __len__(self) -> int: ... -class Sequence(Collection[_T_co], Reversible[_T_co]): +class Sequence(Reversible[_T_co], Collection[_T_co]): @overload @abstractmethod def __getitem__(self, index: int) -> _T_co: ... @@ -659,7 +664,6 @@ class ItemsView(MappingView, AbstractSet[tuple[_KT_co, _VT_co]], Generic[_KT_co, def __rand__(self, other: Iterable[_T]) -> set[_T]: ... def __contains__(self, item: object) -> bool: ... def __iter__(self) -> Iterator[tuple[_KT_co, _VT_co]]: ... - def __reversed__(self) -> Iterator[tuple[_KT_co, _VT_co]]: ... def __or__(self, other: Iterable[_T]) -> set[tuple[_KT_co, _VT_co] | _T]: ... def __ror__(self, other: Iterable[_T]) -> set[tuple[_KT_co, _VT_co] | _T]: ... def __sub__(self, other: Iterable[Any]) -> set[tuple[_KT_co, _VT_co]]: ... @@ -673,7 +677,6 @@ class KeysView(MappingView, AbstractSet[_KT_co]): def __rand__(self, other: Iterable[_T]) -> set[_T]: ... def __contains__(self, key: object) -> bool: ... def __iter__(self) -> Iterator[_KT_co]: ... - def __reversed__(self) -> Iterator[_KT_co]: ... def __or__(self, other: Iterable[_T]) -> set[_KT_co | _T]: ... def __ror__(self, other: Iterable[_T]) -> set[_KT_co | _T]: ... def __sub__(self, other: Iterable[Any]) -> set[_KT_co]: ... @@ -685,7 +688,6 @@ class ValuesView(MappingView, Collection[_VT_co]): def __init__(self, mapping: Mapping[Any, _VT_co]) -> None: ... # undocumented def __contains__(self, value: object) -> bool: ... def __iter__(self) -> Iterator[_VT_co]: ... - def __reversed__(self) -> Iterator[_VT_co]: ... class Mapping(Collection[_KT], Generic[_KT, _VT_co]): # TODO: We wish the key type could also be covariant, but that doesn't work, @@ -760,7 +762,7 @@ TYPE_CHECKING: bool # In stubs, the arguments of the IO class are marked as positional-only. # This differs from runtime, but better reflects the fact that in reality # classes deriving from IO use different names for the arguments. -class IO(Iterator[AnyStr]): +class IO(Generic[AnyStr]): # At runtime these are all abstract properties, # but making them abstract in the stub is hugely disruptive, for not much gain. # See #8726 @@ -973,7 +975,7 @@ class _TypedDict(Mapping[str, object], metaclass=ABCMeta): def __ior__(self, value: typing_extensions.Self, /) -> typing_extensions.Self: ... # type: ignore[misc] @final -class ForwardRef: +class ForwardRef(_Final): __forward_arg__: str __forward_code__: CodeType __forward_evaluated__: bool diff --git a/mypy/typeshed/stdlib/typing_extensions.pyi b/mypy/typeshed/stdlib/typing_extensions.pyi index 3240eff0f5e9..a6b606e6b670 100644 --- a/mypy/typeshed/stdlib/typing_extensions.pyi +++ b/mypy/typeshed/stdlib/typing_extensions.pyi @@ -58,6 +58,7 @@ from typing import ( # noqa: Y022,Y037,Y038,Y039 TextIO as TextIO, Tuple as Tuple, Type as Type, + TypedDict as TypedDict, Union as Union, ValuesView as ValuesView, _Alias, @@ -190,8 +191,10 @@ _T = typing.TypeVar("_T") _F = typing.TypeVar("_F", bound=Callable[..., Any]) _TC = typing.TypeVar("_TC", bound=type[object]) +class _Final: ... # This should be imported from typing but that breaks pytype + # unfortunately we have to duplicate this class definition from typing.pyi or we break pytype -class _SpecialForm: +class _SpecialForm(_Final): def __getitem__(self, parameters: Any) -> object: ... if sys.version_info >= (3, 10): def __or__(self, other: Any) -> _SpecialForm: ... @@ -253,9 +256,6 @@ class _TypedDict(Mapping[str, object], metaclass=abc.ABCMeta): # supposedly incompatible definitions of `__ior__` and `__or__`: def __ior__(self, value: Self, /) -> Self: ... # type: ignore[misc] -# TypedDict is a (non-subscriptable) special form. -TypedDict: object - OrderedDict = _Alias() def get_type_hints( @@ -409,8 +409,11 @@ else: def __or__(self, right: Any) -> _SpecialForm: ... def __ror__(self, left: Any) -> _SpecialForm: ... + # mypy and pyright object to this being both ABC and Protocol. + # At runtime it inherits from ABC and is not a Protocol, but it is on the + # allowlist for use as a Protocol. @runtime_checkable - class Buffer(Protocol): + class Buffer(Protocol, abc.ABC): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] # Not actually a Protocol at runtime; see # https://github.com/python/typeshed/issues/10224 for why we're defining it this way def __buffer__(self, flags: int, /) -> memoryview: ... diff --git a/mypy/typeshed/stdlib/unittest/mock.pyi b/mypy/typeshed/stdlib/unittest/mock.pyi index 1cfd38f540a4..193a4123c395 100644 --- a/mypy/typeshed/stdlib/unittest/mock.pyi +++ b/mypy/typeshed/stdlib/unittest/mock.pyi @@ -363,7 +363,7 @@ class _patcher: patch: _patcher -class MagicMixin: +class MagicMixin(Base): def __init__(self, *args: Any, **kw: Any) -> None: ... class NonCallableMagicMock(MagicMixin, NonCallableMock): ... @@ -393,7 +393,7 @@ class AsyncMock(AsyncMockMixin, AsyncMagicMixin, Mock): # But, `NonCallableMock` super-class has the better version. def reset_mock(self, visited: Any = None, *, return_value: bool = False, side_effect: bool = False) -> None: ... -class MagicProxy: +class MagicProxy(Base): name: str parent: Any def __init__(self, name: str, parent: Any) -> None: ... diff --git a/mypy/typeshed/stdlib/unittest/runner.pyi b/mypy/typeshed/stdlib/unittest/runner.pyi index 46da85619d30..393d03dfa0fc 100644 --- a/mypy/typeshed/stdlib/unittest/runner.pyi +++ b/mypy/typeshed/stdlib/unittest/runner.pyi @@ -13,17 +13,21 @@ class _SupportsWriteAndFlush(SupportsWrite[str], SupportsFlush, Protocol): ... # All methods used by unittest.runner.TextTestResult's stream class _TextTestStream(_SupportsWriteAndFlush, Protocol): - def writeln(self, arg: str | None = None) -> str: ... + def writeln(self, arg: str | None = None, /) -> str: ... # _WritelnDecorator should have all the same attrs as its stream param. # But that's not feasible to do Generically # We can expand the attributes if requested -class _WritelnDecorator(_TextTestStream): +class _WritelnDecorator: def __init__(self, stream: _TextTestStream) -> None: ... + def writeln(self, arg: str | None = None) -> str: ... def __getattr__(self, attr: str) -> Any: ... # Any attribute from the stream type passed to __init__ # These attributes are prevented by __getattr__ stream: Never __getstate__: Never + # Methods proxied from the wrapped stream object via __getattr__ + def flush(self) -> object: ... + def write(self, s: str, /) -> object: ... _StreamT = TypeVar("_StreamT", bound=_TextTestStream, default=_WritelnDecorator) diff --git a/mypy/typeshed/stdlib/unittest/suite.pyi b/mypy/typeshed/stdlib/unittest/suite.pyi index c10cbc75d7fd..ff583d0766a0 100644 --- a/mypy/typeshed/stdlib/unittest/suite.pyi +++ b/mypy/typeshed/stdlib/unittest/suite.pyi @@ -5,7 +5,7 @@ from typing_extensions import TypeAlias _TestType: TypeAlias = unittest.case.TestCase | TestSuite -class BaseTestSuite(Iterable[_TestType]): +class BaseTestSuite: _tests: list[unittest.case.TestCase] _removed_tests: int def __init__(self, tests: Iterable[_TestType] = ()) -> None: ... diff --git a/mypy/typeshed/stdlib/warnings.pyi b/mypy/typeshed/stdlib/warnings.pyi index c7ab1cb091dd..533a36817506 100644 --- a/mypy/typeshed/stdlib/warnings.pyi +++ b/mypy/typeshed/stdlib/warnings.pyi @@ -1,3 +1,4 @@ +import re import sys from _warnings import warn as warn, warn_explicit as warn_explicit from collections.abc import Sequence @@ -25,7 +26,7 @@ if sys.version_info >= (3, 14): _ActionKind: TypeAlias = Literal["default", "error", "ignore", "always", "module", "once"] else: _ActionKind: TypeAlias = Literal["default", "error", "ignore", "always", "all", "module", "once"] -filters: Sequence[tuple[str, str | None, type[Warning], str | None, int]] # undocumented, do not mutate +filters: Sequence[tuple[str, re.Pattern[str] | None, type[Warning], re.Pattern[str] | None, int]] # undocumented, do not mutate def showwarning( message: Warning | str, diff --git a/mypy/typeshed/stdlib/weakref.pyi b/mypy/typeshed/stdlib/weakref.pyi index aaba7ffc98d9..853caf3e8abb 100644 --- a/mypy/typeshed/stdlib/weakref.pyi +++ b/mypy/typeshed/stdlib/weakref.pyi @@ -1,19 +1,14 @@ import sys from _typeshed import SupportsKeysAndGetItem -from _weakref import ( - CallableProxyType as CallableProxyType, - ProxyType as ProxyType, - ReferenceType as ReferenceType, - getweakrefcount as getweakrefcount, - getweakrefs as getweakrefs, - proxy as proxy, - ref as ref, -) +from _weakref import getweakrefcount as getweakrefcount, getweakrefs as getweakrefs, proxy as proxy from _weakrefset import WeakSet as WeakSet from collections.abc import Callable, Iterable, Iterator, Mapping, MutableMapping -from typing import Any, Generic, TypeVar, overload +from typing import Any, Generic, TypeVar, final, overload from typing_extensions import ParamSpec, Self +if sys.version_info >= (3, 9): + from types import GenericAlias + __all__ = [ "ref", "proxy", @@ -40,11 +35,39 @@ _P = ParamSpec("_P") ProxyTypes: tuple[type[Any], ...] +# These classes are implemented in C and imported from _weakref at runtime. However, +# they consider themselves to live in the weakref module for sys.version_info >= (3, 11), +# so defining their stubs here means we match their __module__ value. +# Prior to 3.11 they did not declare a module for themselves and ended up looking like they +# came from the builtin module at runtime, which was just wrong, and we won't attempt to +# duplicate that. + +@final +class CallableProxyType(Generic[_CallableT]): # "weakcallableproxy" + def __eq__(self, value: object, /) -> bool: ... + def __getattr__(self, attr: str) -> Any: ... + __call__: _CallableT + +@final +class ProxyType(Generic[_T]): # "weakproxy" + def __eq__(self, value: object, /) -> bool: ... + def __getattr__(self, attr: str) -> Any: ... + +class ReferenceType(Generic[_T]): # "weakref" + __callback__: Callable[[Self], Any] + def __new__(cls, o: _T, callback: Callable[[Self], Any] | None = ..., /) -> Self: ... + def __call__(self) -> _T | None: ... + def __eq__(self, value: object, /) -> bool: ... + def __hash__(self) -> int: ... + if sys.version_info >= (3, 9): + def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... + +ref = ReferenceType + +# everything below here is implemented in weakref.py + class WeakMethod(ref[_CallableT]): - # `ref` is implemented in `C` so positional-only arguments are enforced, but not in `WeakMethod`. - def __new__( # pyright: ignore[reportInconsistentConstructor] - cls, meth: _CallableT, callback: Callable[[Self], Any] | None = None - ) -> Self: ... + def __new__(cls, meth: _CallableT, callback: Callable[[Self], Any] | None = None) -> Self: ... def __call__(self) -> _CallableT | None: ... def __eq__(self, other: object) -> bool: ... def __ne__(self, other: object) -> bool: ... @@ -103,8 +126,8 @@ class WeakValueDictionary(MutableMapping[_KT, _VT]): class KeyedRef(ref[_T], Generic[_KT, _T]): key: _KT - def __new__(type, ob: _T, callback: Callable[[_T], Any], key: _KT) -> Self: ... - def __init__(self, ob: _T, callback: Callable[[_T], Any], key: _KT) -> None: ... + def __new__(type, ob: _T, callback: Callable[[Self], Any], key: _KT) -> Self: ... + def __init__(self, ob: _T, callback: Callable[[Self], Any], key: _KT) -> None: ... class WeakKeyDictionary(MutableMapping[_KT, _VT]): @overload diff --git a/mypy/typeshed/stdlib/webbrowser.pyi b/mypy/typeshed/stdlib/webbrowser.pyi index d7bf033172f6..773786c24821 100644 --- a/mypy/typeshed/stdlib/webbrowser.pyi +++ b/mypy/typeshed/stdlib/webbrowser.pyi @@ -66,6 +66,7 @@ if sys.platform == "darwin": if sys.version_info < (3, 13): @deprecated("Deprecated in 3.11, to be removed in 3.13.") class MacOSX(BaseBrowser): + def __init__(self, name: str) -> None: ... def open(self, url: str, new: int = 0, autoraise: bool = True) -> bool: ... class MacOSXOSAScript(BaseBrowser): # In runtime this class does not have `name` and `basename` diff --git a/mypy/typeshed/stdlib/wsgiref/types.pyi b/mypy/typeshed/stdlib/wsgiref/types.pyi index 86212df8ccdc..57276fd05ea8 100644 --- a/mypy/typeshed/stdlib/wsgiref/types.pyi +++ b/mypy/typeshed/stdlib/wsgiref/types.pyi @@ -1,5 +1,5 @@ +from _typeshed import OptExcInfo from collections.abc import Callable, Iterable, Iterator -from sys import _OptExcInfo from typing import Any, Protocol from typing_extensions import TypeAlias @@ -7,7 +7,7 @@ __all__ = ["StartResponse", "WSGIEnvironment", "WSGIApplication", "InputStream", class StartResponse(Protocol): def __call__( - self, status: str, headers: list[tuple[str, str]], exc_info: _OptExcInfo | None = ..., / + self, status: str, headers: list[tuple[str, str]], exc_info: OptExcInfo | None = ..., / ) -> Callable[[bytes], object]: ... WSGIEnvironment: TypeAlias = dict[str, Any] diff --git a/mypy/typeshed/stdlib/xml/__init__.pyi b/mypy/typeshed/stdlib/xml/__init__.pyi index a487d2467f41..7a240965136e 100644 --- a/mypy/typeshed/stdlib/xml/__init__.pyi +++ b/mypy/typeshed/stdlib/xml/__init__.pyi @@ -1 +1,3 @@ -from xml import parsers as parsers +# At runtime, listing submodules in __all__ without them being imported is +# valid, and causes them to be included in a star import. See #6523 +__all__ = ["dom", "parsers", "sax", "etree"] # noqa: F822 # pyright: ignore[reportUnsupportedDunderAll] diff --git a/mypy/typeshed/stdlib/xml/parsers/expat/__init__.pyi b/mypy/typeshed/stdlib/xml/parsers/expat/__init__.pyi index 73f3758c61ec..d9b7ea536999 100644 --- a/mypy/typeshed/stdlib/xml/parsers/expat/__init__.pyi +++ b/mypy/typeshed/stdlib/xml/parsers/expat/__init__.pyi @@ -1 +1,7 @@ from pyexpat import * + +# This is actually implemented in the C module pyexpat, but considers itself to live here. +class ExpatError(Exception): + code: int + lineno: int + offset: int diff --git a/mypy/typeshed/stdlib/xmlrpc/client.pyi b/mypy/typeshed/stdlib/xmlrpc/client.pyi index d254102acc55..5899d1d72a38 100644 --- a/mypy/typeshed/stdlib/xmlrpc/client.pyi +++ b/mypy/typeshed/stdlib/xmlrpc/client.pyi @@ -200,7 +200,7 @@ def dumps( allow_none: bool = False, ) -> str: ... def loads( - data: str, use_datetime: bool = False, use_builtin_types: bool = False + data: str | ReadableBuffer, use_datetime: bool = False, use_builtin_types: bool = False ) -> tuple[tuple[_Marshallable, ...], str | None]: ... def gzip_encode(data: ReadableBuffer) -> bytes: ... # undocumented def gzip_decode(data: ReadableBuffer, max_decode: int = 20971520) -> bytes: ... # undocumented diff --git a/mypy/typeshed/stdlib/xmlrpc/server.pyi b/mypy/typeshed/stdlib/xmlrpc/server.pyi index 8ca3a4d1a33c..5f497aa7190e 100644 --- a/mypy/typeshed/stdlib/xmlrpc/server.pyi +++ b/mypy/typeshed/stdlib/xmlrpc/server.pyi @@ -1,6 +1,7 @@ import http.server import pydoc import socketserver +from _typeshed import ReadableBuffer from collections.abc import Callable, Iterable, Mapping from re import Pattern from typing import Any, ClassVar, Protocol @@ -48,8 +49,8 @@ class SimpleXMLRPCDispatcher: # undocumented def register_multicall_functions(self) -> None: ... def _marshaled_dispatch( self, - data: str, - dispatch_method: Callable[[str | None, tuple[_Marshallable, ...]], Fault | tuple[_Marshallable, ...]] | None = None, + data: str | ReadableBuffer, + dispatch_method: Callable[[str, tuple[_Marshallable, ...]], Fault | tuple[_Marshallable, ...]] | None = None, path: Any | None = None, ) -> str: ... # undocumented def system_listMethods(self) -> list[str]: ... # undocumented diff --git a/mypy/typeshed/stdlib/zipfile/_path.pyi b/mypy/typeshed/stdlib/zipfile/_path.pyi index 933acf2c4803..a7248ba7ab72 100644 --- a/mypy/typeshed/stdlib/zipfile/_path.pyi +++ b/mypy/typeshed/stdlib/zipfile/_path.pyi @@ -12,6 +12,8 @@ _ReadWriteBinaryMode: TypeAlias = Literal["r", "w", "rb", "wb"] _ZF = TypeVar("_ZF", bound=ZipFile) if sys.version_info >= (3, 12): + __all__ = ["Path"] + class InitializedState: def __init__(self, *args: object, **kwargs: object) -> None: ... def __getstate__(self) -> tuple[list[object], dict[object, object]]: ... diff --git a/mypy/typeshed/stdlib/zipimport.pyi b/mypy/typeshed/stdlib/zipimport.pyi index f53b09e188eb..3e94c681b7a2 100644 --- a/mypy/typeshed/stdlib/zipimport.pyi +++ b/mypy/typeshed/stdlib/zipimport.pyi @@ -3,12 +3,18 @@ from _typeshed import StrOrBytesPath from importlib.abc import ResourceReader from importlib.machinery import ModuleSpec from types import CodeType, ModuleType +from typing_extensions import deprecated + +if sys.version_info >= (3, 10): + from _frozen_importlib_external import _LoaderBasics +else: + _LoaderBasics = object __all__ = ["ZipImportError", "zipimporter"] class ZipImportError(ImportError): ... -class zipimporter: +class zipimporter(_LoaderBasics): archive: str prefix: str if sys.version_info >= (3, 11): @@ -26,6 +32,7 @@ class zipimporter: def get_resource_reader(self, fullname: str) -> ResourceReader | None: ... # undocumented def get_source(self, fullname: str) -> str | None: ... def is_package(self, fullname: str) -> bool: ... + @deprecated("Deprecated since 3.10; use exec_module() instead") def load_module(self, fullname: str) -> ModuleType: ... if sys.version_info >= (3, 10): def exec_module(self, module: ModuleType) -> None: ... diff --git a/mypy/typeshed/stdlib/zlib.pyi b/mypy/typeshed/stdlib/zlib.pyi index 2f6c40656038..7cafb44b34a7 100644 --- a/mypy/typeshed/stdlib/zlib.pyi +++ b/mypy/typeshed/stdlib/zlib.pyi @@ -1,6 +1,7 @@ import sys from _typeshed import ReadableBuffer -from typing import Final +from typing import Any, Final, final, type_check_only +from typing_extensions import Self DEFLATED: Final = 8 DEF_MEM_LEVEL: int # can change @@ -27,17 +28,30 @@ Z_TREES: Final = 6 class error(Exception): ... +# This class is not exposed at runtime. It calls itself zlib.Compress. +@final +@type_check_only class _Compress: - def compress(self, data: ReadableBuffer) -> bytes: ... - def flush(self, mode: int = ...) -> bytes: ... + def __copy__(self) -> Self: ... + def __deepcopy__(self, memo: Any, /) -> Self: ... + def compress(self, data: ReadableBuffer, /) -> bytes: ... + def flush(self, mode: int = 4, /) -> bytes: ... def copy(self) -> _Compress: ... +# This class is not exposed at runtime. It calls itself zlib.Decompress. +@final +@type_check_only class _Decompress: - unused_data: bytes - unconsumed_tail: bytes - eof: bool - def decompress(self, data: ReadableBuffer, max_length: int = ...) -> bytes: ... - def flush(self, length: int = ...) -> bytes: ... + @property + def unused_data(self) -> bytes: ... + @property + def unconsumed_tail(self) -> bytes: ... + @property + def eof(self) -> bool: ... + def __copy__(self) -> Self: ... + def __deepcopy__(self, memo: Any, /) -> Self: ... + def decompress(self, data: ReadableBuffer, /, max_length: int = 0) -> bytes: ... + def flush(self, length: int = 16384, /) -> bytes: ... def copy(self) -> _Decompress: ... def adler32(data: ReadableBuffer, value: int = 1, /) -> int: ... diff --git a/mypy/typeshed/stdlib/zoneinfo/__init__.pyi b/mypy/typeshed/stdlib/zoneinfo/__init__.pyi index 77930ac79dd5..cc483afad9ff 100644 --- a/mypy/typeshed/stdlib/zoneinfo/__init__.pyi +++ b/mypy/typeshed/stdlib/zoneinfo/__init__.pyi @@ -1,38 +1,35 @@ -from _typeshed import StrPath -from collections.abc import Iterable, Sequence +import sys +from collections.abc import Iterable from datetime import datetime, timedelta, tzinfo -from typing import Any, Protocol from typing_extensions import Self -__all__ = ["ZoneInfo", "reset_tzpath", "available_timezones", "TZPATH", "ZoneInfoNotFoundError", "InvalidTZPathWarning"] +# TODO: remove this version check +# In theory we shouldn't need this version check. Pyright complains about the imports +# from zoneinfo.* when run on 3.8 and 3.7 without this. Updates to typeshed's +# pyright test script are probably needed, see #11189 +if sys.version_info >= (3, 9): + from zoneinfo._common import ZoneInfoNotFoundError as ZoneInfoNotFoundError, _IOBytes + from zoneinfo._tzpath import ( + TZPATH as TZPATH, + InvalidTZPathWarning as InvalidTZPathWarning, + available_timezones as available_timezones, + reset_tzpath as reset_tzpath, + ) -class _IOBytes(Protocol): - def read(self, size: int, /) -> bytes: ... - def seek(self, size: int, whence: int = ..., /) -> Any: ... + __all__ = ["ZoneInfo", "reset_tzpath", "available_timezones", "TZPATH", "ZoneInfoNotFoundError", "InvalidTZPathWarning"] -class ZoneInfo(tzinfo): - @property - def key(self) -> str: ... - def __init__(self, key: str) -> None: ... - @classmethod - def no_cache(cls, key: str) -> Self: ... - @classmethod - def from_file(cls, fobj: _IOBytes, /, key: str | None = None) -> Self: ... - @classmethod - def clear_cache(cls, *, only_keys: Iterable[str] | None = None) -> None: ... - def tzname(self, dt: datetime | None, /) -> str | None: ... - def utcoffset(self, dt: datetime | None, /) -> timedelta | None: ... - def dst(self, dt: datetime | None, /) -> timedelta | None: ... + class ZoneInfo(tzinfo): + @property + def key(self) -> str: ... + def __init__(self, key: str) -> None: ... + @classmethod + def no_cache(cls, key: str) -> Self: ... + @classmethod + def from_file(cls, fobj: _IOBytes, /, key: str | None = None) -> Self: ... + @classmethod + def clear_cache(cls, *, only_keys: Iterable[str] | None = None) -> None: ... + def tzname(self, dt: datetime | None, /) -> str | None: ... + def utcoffset(self, dt: datetime | None, /) -> timedelta | None: ... + def dst(self, dt: datetime | None, /) -> timedelta | None: ... -# Note: Both here and in clear_cache, the types allow the use of `str` where -# a sequence of strings is required. This should be remedied if a solution -# to this typing bug is found: https://github.com/python/typing/issues/256 -def reset_tzpath(to: Sequence[StrPath] | None = None) -> None: ... -def available_timezones() -> set[str]: ... - -TZPATH: tuple[str, ...] - -class ZoneInfoNotFoundError(KeyError): ... -class InvalidTZPathWarning(RuntimeWarning): ... - -def __dir__() -> list[str]: ... + def __dir__() -> list[str]: ... diff --git a/mypy/typeshed/stdlib/zoneinfo/_common.pyi b/mypy/typeshed/stdlib/zoneinfo/_common.pyi new file mode 100644 index 000000000000..a2f29f2d14f0 --- /dev/null +++ b/mypy/typeshed/stdlib/zoneinfo/_common.pyi @@ -0,0 +1,13 @@ +import io +from typing import Any, Protocol + +class _IOBytes(Protocol): + def read(self, size: int, /) -> bytes: ... + def seek(self, size: int, whence: int = ..., /) -> Any: ... + +def load_tzdata(key: str) -> io.BufferedReader: ... +def load_data( + fobj: _IOBytes, +) -> tuple[tuple[int, ...], tuple[int, ...], tuple[int, ...], tuple[int, ...], tuple[str, ...], bytes | None]: ... + +class ZoneInfoNotFoundError(KeyError): ... diff --git a/mypy/typeshed/stdlib/zoneinfo/_tzpath.pyi b/mypy/typeshed/stdlib/zoneinfo/_tzpath.pyi new file mode 100644 index 000000000000..0ef78d03e5f4 --- /dev/null +++ b/mypy/typeshed/stdlib/zoneinfo/_tzpath.pyi @@ -0,0 +1,13 @@ +from _typeshed import StrPath +from collections.abc import Sequence + +# Note: Both here and in clear_cache, the types allow the use of `str` where +# a sequence of strings is required. This should be remedied if a solution +# to this typing bug is found: https://github.com/python/typing/issues/256 +def reset_tzpath(to: Sequence[StrPath] | None = None) -> None: ... +def find_tzfile(key: str) -> str | None: ... +def available_timezones() -> set[str]: ... + +TZPATH: tuple[str, ...] + +class InvalidTZPathWarning(RuntimeWarning): ... diff --git a/mypy/typevartuples.py b/mypy/typevartuples.py index 2a9998c10746..3bc67dc55ef3 100644 --- a/mypy/typevartuples.py +++ b/mypy/typevartuples.py @@ -7,12 +7,10 @@ from mypy.types import ( AnyType, Instance, - ProperType, Type, TypeVarLikeType, TypeVarTupleType, UnpackType, - get_proper_type, split_with_prefix_and_suffix, ) @@ -27,14 +25,6 @@ def split_with_instance( ) -def extract_unpack(types: Sequence[Type]) -> ProperType | None: - """Given a list of types, extracts either a single type from an unpack, or returns None.""" - if len(types) == 1: - if isinstance(types[0], UnpackType): - return get_proper_type(types[0].type) - return None - - def erased_vars(type_vars: Sequence[TypeVarLikeType], type_of_any: int) -> list[Type]: args: list[Type] = [] for tv in type_vars: diff --git a/mypy/util.py b/mypy/util.py index 4b1b918b92e6..e0a9cf9ce1b2 100644 --- a/mypy/util.py +++ b/mypy/util.py @@ -4,20 +4,25 @@ import hashlib import io +import json import os -import pathlib import re import shutil import sys import time from importlib import resources as importlib_resources -from typing import IO, Callable, Container, Final, Iterable, Sequence, Sized, TypeVar +from typing import IO, Any, Callable, Container, Final, Iterable, Sequence, Sized, TypeVar from typing_extensions import Literal +orjson: Any try: - import curses + import orjson # type: ignore[import-not-found, no-redef, unused-ignore] +except ImportError: + orjson = None +try: import _curses # noqa: F401 + import curses CURSES_ENABLED = True except ImportError: @@ -196,7 +201,7 @@ def trim_source_line(line: str, max_len: int, col: int, min_width: int) -> tuple A typical result looks like this: ...some_variable = function_to_call(one_arg, other_arg) or... - Return the trimmed string and the column offset to to adjust error location. + Return the trimmed string and the column offset to adjust error location. """ if max_len < 2 * min_width + 1: # In case the window is too tiny it is better to still show something. @@ -412,9 +417,43 @@ def replace_object_state( pass -def is_sub_path(path1: str, path2: str) -> bool: - """Given two paths, return if path1 is a sub-path of path2.""" - return pathlib.Path(path2) in pathlib.Path(path1).parents +def is_sub_path_normabs(path: str, dir: str) -> bool: + """Given two paths, return if path is a sub-path of dir. + + Moral equivalent of: Path(dir) in Path(path).parents + + Similar to the pathlib version: + - Treats paths case-sensitively + - Does not fully handle unnormalised paths (e.g. paths with "..") + - Does not handle a mix of absolute and relative paths + Unlike the pathlib version: + - Fast + - On Windows, assumes input has been slash normalised + - Handles even fewer unnormalised paths (e.g. paths with "." and "//") + + As a result, callers should ensure that inputs have had os.path.abspath called on them + (note that os.path.abspath will normalise) + """ + if not dir.endswith(os.sep): + dir += os.sep + return path.startswith(dir) + + +if sys.platform == "linux" or sys.platform == "darwin": + + def os_path_join(path: str, b: str) -> str: + # Based off of os.path.join, but simplified to str-only, 2 args and mypyc can compile it. + if b.startswith("/") or not path: + return b + elif path.endswith("/"): + return path + b + else: + return path + "/" + b + +else: + + def os_path_join(a: str, p: str) -> str: + return os.path.join(a, p) def hard_exit(status: int = 0) -> None: @@ -535,9 +574,7 @@ def hash_digest(data: bytes) -> str: accidental collision, but we don't really care about any of the cryptographic properties. """ - # Once we drop Python 3.5 support, we should consider using - # blake2b, which is faster. - return hashlib.sha256(data).hexdigest() + return hashlib.sha1(data).hexdigest() def parse_gray_color(cup: bytes) -> str: @@ -833,6 +870,18 @@ def is_typeshed_file(typeshed_dir: str | None, file: str) -> bool: return False +def is_stdlib_file(typeshed_dir: str | None, file: str) -> bool: + if "stdlib" not in file: + # Fast path + return False + typeshed_dir = typeshed_dir if typeshed_dir is not None else TYPESHED_DIR + stdlib_dir = os.path.join(typeshed_dir, "stdlib") + try: + return os.path.commonpath((stdlib_dir, os.path.abspath(file))) == stdlib_dir + except ValueError: # Different drives on Windows + return False + + def is_stub_package_file(file: str) -> bool: # Use hacky heuristics to check whether file is part of a PEP 561 stub package. if not file.endswith(".pyi"): @@ -874,3 +923,31 @@ def quote_docstring(docstr: str) -> str: return f"''{docstr_repr}''" else: return f'""{docstr_repr}""' + + +def json_dumps(obj: object, debug: bool = False) -> bytes: + if orjson is not None: + if debug: + dumps_option = orjson.OPT_INDENT_2 | orjson.OPT_SORT_KEYS + else: + # TODO: If we don't sort keys here, testIncrementalInternalScramble fails + # We should document exactly what is going on there + dumps_option = orjson.OPT_SORT_KEYS + + try: + return orjson.dumps(obj, option=dumps_option) # type: ignore[no-any-return] + except TypeError as e: + if str(e) != "Integer exceeds 64-bit range": + raise + + if debug: + return json.dumps(obj, indent=2, sort_keys=True).encode("utf-8") + else: + # See above for sort_keys comment + return json.dumps(obj, sort_keys=True, separators=(",", ":")).encode("utf-8") + + +def json_loads(data: bytes) -> Any: + if orjson is not None: + return orjson.loads(data) + return json.loads(data) diff --git a/mypy/version.py b/mypy/version.py index 8e00b4cce702..eca889c708e0 100644 --- a/mypy/version.py +++ b/mypy/version.py @@ -8,7 +8,7 @@ # - Release versions have the form "1.2.3". # - Dev versions have the form "1.2.3+dev" (PLUS sign to conform to PEP 440). # - Before 1.0 we had the form "0.NNN". -__version__ = "1.12.0+dev" +__version__ = "1.14.0" base_version = __version__ mypy_dir = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) diff --git a/mypy_bootstrap.ini b/mypy_bootstrap.ini index c680990fbd9e..6e82f23b0530 100644 --- a/mypy_bootstrap.ini +++ b/mypy_bootstrap.ini @@ -1,16 +1,6 @@ [mypy] -disallow_untyped_calls = True -disallow_untyped_defs = True -disallow_incomplete_defs = True -check_untyped_defs = True -disallow_subclassing_any = True -warn_no_return = True -strict_optional = True -no_implicit_optional = True -disallow_any_generics = True -disallow_any_unimported = True -warn_redundant_casts = True -warn_unused_configs = True +strict = True +warn_unused_ignores = False show_traceback = True always_true = MYPYC diff --git a/mypyc/__main__.py b/mypyc/__main__.py index a3b9d21bc65a..653199e0fb55 100644 --- a/mypyc/__main__.py +++ b/mypyc/__main__.py @@ -24,7 +24,7 @@ from mypyc.build import mypycify setup(name='mypyc_output', - ext_modules=mypycify({}, opt_level="{}", debug_level="{}"), + ext_modules=mypycify({}, opt_level="{}", debug_level="{}", strict_dunder_typing={}), ) """ @@ -38,10 +38,11 @@ def main() -> None: opt_level = os.getenv("MYPYC_OPT_LEVEL", "3") debug_level = os.getenv("MYPYC_DEBUG_LEVEL", "1") + strict_dunder_typing = bool(int(os.getenv("MYPYC_STRICT_DUNDER_TYPING", "0"))) setup_file = os.path.join(build_dir, "setup.py") with open(setup_file, "w") as f: - f.write(setup_format.format(sys.argv[1:], opt_level, debug_level)) + f.write(setup_format.format(sys.argv[1:], opt_level, debug_level, strict_dunder_typing)) # We don't use run_setup (like we do in the test suite) because it throws # away the error code from distutils, and we don't care about the slight diff --git a/mypyc/analysis/dataflow.py b/mypyc/analysis/dataflow.py index 9babf860fb31..411fc8093404 100644 --- a/mypyc/analysis/dataflow.py +++ b/mypyc/analysis/dataflow.py @@ -5,7 +5,6 @@ from abc import abstractmethod from typing import Dict, Generic, Iterable, Iterator, Set, Tuple, TypeVar -from mypyc.ir.func_ir import all_values from mypyc.ir.ops import ( Assign, AssignMulti, @@ -437,27 +436,6 @@ def visit_set_mem(self, op: SetMem) -> GenAndKill[Value]: return set(), set() -def analyze_undefined_regs( - blocks: list[BasicBlock], cfg: CFG, initial_defined: set[Value] -) -> AnalysisResult[Value]: - """Calculate potentially undefined registers at each CFG location. - - A register is undefined if there is some path from initial block - where it has an undefined value. - - Function arguments are assumed to be always defined. - """ - initial_undefined = set(all_values([], blocks)) - initial_defined - return run_analysis( - blocks=blocks, - cfg=cfg, - gen_and_kill=UndefinedVisitor(), - initial=initial_undefined, - backward=False, - kind=MAYBE_ANALYSIS, - ) - - def non_trivial_sources(op: Op) -> set[Value]: result = set() for source in op.sources(): diff --git a/mypyc/build.py b/mypyc/build.py index 485803acba46..6d59113ef872 100644 --- a/mypyc/build.py +++ b/mypyc/build.py @@ -470,6 +470,7 @@ def mypycify( skip_cgen_input: Any | None = None, target_dir: str | None = None, include_runtime_files: bool | None = None, + strict_dunder_typing: bool = False, ) -> list[Extension]: """Main entry point to building using mypyc. @@ -509,6 +510,9 @@ def mypycify( should be directly #include'd instead of linked separately in order to reduce compiler invocations. Defaults to False in multi_file mode, True otherwise. + strict_dunder_typing: If True, force dunder methods to have the return type + of the method strictly, which can lead to more + optimization opportunities. Defaults to False. """ # Figure out our configuration @@ -519,6 +523,7 @@ def mypycify( separate=separate is not False, target_dir=target_dir, include_runtime_files=include_runtime_files, + strict_dunder_typing=strict_dunder_typing, ) # Generate all the actual important C code diff --git a/mypyc/codegen/emitclass.py b/mypyc/codegen/emitclass.py index ad95a1b0f323..d1a9ad3bace1 100644 --- a/mypyc/codegen/emitclass.py +++ b/mypyc/codegen/emitclass.py @@ -213,8 +213,7 @@ def generate_class(cl: ClassIR, module: str, emitter: Emitter) -> None: methods_name = f"{name_prefix}_methods" vtable_setup_name = f"{name_prefix}_trait_vtable_setup" - fields: dict[str, str] = {} - fields["tp_name"] = f'"{name}"' + fields: dict[str, str] = {"tp_name": f'"{name}"'} generate_full = not cl.is_trait and not cl.builtin_base needs_getseters = cl.needs_getseters or not cl.is_generated or cl.has_dict @@ -571,6 +570,7 @@ def generate_setup_for_class( emitter.emit_line("}") else: emitter.emit_line(f"self->vtable = {vtable_name};") + for i in range(0, len(cl.bitmap_attrs), BITMAP_BITS): field = emitter.bitmap_field(i) emitter.emit_line(f"self->{field} = 0;") diff --git a/mypyc/codegen/emitfunc.py b/mypyc/codegen/emitfunc.py index d945a28d8481..6088fb06dd32 100644 --- a/mypyc/codegen/emitfunc.py +++ b/mypyc/codegen/emitfunc.py @@ -72,6 +72,7 @@ from mypyc.ir.pprint import generate_names_for_ir from mypyc.ir.rtypes import ( RArray, + RInstance, RStruct, RTuple, RType, @@ -362,20 +363,23 @@ def visit_get_attr(self, op: GetAttr) -> None: prefer_method = cl.is_trait and attr_rtype.error_overlap if cl.get_method(op.attr, prefer_method=prefer_method): # Properties are essentially methods, so use vtable access for them. - version = "_TRAIT" if cl.is_trait else "" - self.emit_line( - "%s = CPY_GET_ATTR%s(%s, %s, %d, %s, %s); /* %s */" - % ( - dest, - version, - obj, - self.emitter.type_struct_name(rtype.class_ir), - rtype.getter_index(op.attr), - rtype.struct_name(self.names), - self.ctype(rtype.attr_type(op.attr)), - op.attr, + if cl.is_method_final(op.attr): + self.emit_method_call(f"{dest} = ", op.obj, op.attr, []) + else: + version = "_TRAIT" if cl.is_trait else "" + self.emit_line( + "%s = CPY_GET_ATTR%s(%s, %s, %d, %s, %s); /* %s */" + % ( + dest, + version, + obj, + self.emitter.type_struct_name(rtype.class_ir), + rtype.getter_index(op.attr), + rtype.struct_name(self.names), + self.ctype(rtype.attr_type(op.attr)), + op.attr, + ) ) - ) else: # Otherwise, use direct or offset struct access. attr_expr = self.get_attr_expr(obj, op, decl_cl) @@ -529,11 +533,13 @@ def visit_call(self, op: Call) -> None: def visit_method_call(self, op: MethodCall) -> None: """Call native method.""" dest = self.get_dest_assign(op) - obj = self.reg(op.obj) + self.emit_method_call(dest, op.obj, op.method, op.args) - rtype = op.receiver_type + def emit_method_call(self, dest: str, op_obj: Value, name: str, op_args: list[Value]) -> None: + obj = self.reg(op_obj) + rtype = op_obj.type + assert isinstance(rtype, RInstance) class_ir = rtype.class_ir - name = op.method method = rtype.class_ir.get_method(name) assert method is not None @@ -547,7 +553,7 @@ def visit_method_call(self, op: MethodCall) -> None: if method.decl.kind == FUNC_STATICMETHOD else [f"(PyObject *)Py_TYPE({obj})"] if method.decl.kind == FUNC_CLASSMETHOD else [obj] ) - args = ", ".join(obj_args + [self.reg(arg) for arg in op.args]) + args = ", ".join(obj_args + [self.reg(arg) for arg in op_args]) mtype = native_function_type(method, self.emitter) version = "_TRAIT" if rtype.class_ir.is_trait else "" if is_direct: @@ -567,7 +573,7 @@ def visit_method_call(self, op: MethodCall) -> None: rtype.struct_name(self.names), mtype, args, - op.method, + name, ) ) diff --git a/mypyc/codegen/emitmodule.py b/mypyc/codegen/emitmodule.py index 1d8708912de5..5b2812c2293a 100644 --- a/mypyc/codegen/emitmodule.py +++ b/mypyc/codegen/emitmodule.py @@ -24,7 +24,7 @@ from mypy.nodes import MypyFile from mypy.options import Options from mypy.plugin import Plugin, ReportConfigContext -from mypy.util import hash_digest +from mypy.util import hash_digest, json_dumps from mypyc.codegen.cstring import c_string_initializer from mypyc.codegen.emit import Emitter, EmitterContext, HeaderDeclaration, c_array_initializer from mypyc.codegen.emitclass import generate_class, generate_class_type_decl @@ -47,7 +47,6 @@ use_vectorcall, ) from mypyc.errors import Errors -from mypyc.ir.class_ir import ClassIR from mypyc.ir.func_ir import FuncIR from mypyc.ir.module_ir import ModuleIR, ModuleIRs, deserialize_modules from mypyc.ir.ops import DeserMaps, LoadLiteral @@ -154,7 +153,7 @@ def report_config_data(self, ctx: ReportConfigContext) -> tuple[str | None, list ir_data = json.loads(ir_json) # Check that the IR cache matches the metadata cache - if compute_hash(meta_json) != ir_data["meta_hash"]: + if hash_digest(meta_json) != ir_data["meta_hash"]: return None # Check that all of the source files are present and as @@ -369,11 +368,11 @@ def write_cache( newpath = get_state_ir_cache_name(st) ir_data = { "ir": module.serialize(), - "meta_hash": compute_hash(meta_data), + "meta_hash": hash_digest(meta_data), "src_hashes": hashes[group_map[id]], } - result.manager.metastore.write(newpath, json.dumps(ir_data, separators=(",", ":"))) + result.manager.metastore.write(newpath, json_dumps(ir_data)) result.manager.metastore.commit() @@ -1075,20 +1074,6 @@ def declare_type_vars(self, module: str, type_var_names: list[str], emitter: Emi ) -def sort_classes(classes: list[tuple[str, ClassIR]]) -> list[tuple[str, ClassIR]]: - mod_name = {ir: name for name, ir in classes} - irs = [ir for _, ir in classes] - deps: dict[ClassIR, set[ClassIR]] = {} - for ir in irs: - if ir not in deps: - deps[ir] = set() - if ir.base: - deps[ir].add(ir.base) - deps[ir].update(ir.traits) - sorted_irs = toposort(deps) - return [(mod_name[ir], ir) for ir in sorted_irs] - - T = TypeVar("T") diff --git a/mypyc/codegen/literals.py b/mypyc/codegen/literals.py index 1f0c3bc6ec7b..2c4ab0c1dc2e 100644 --- a/mypyc/codegen/literals.py +++ b/mypyc/codegen/literals.py @@ -230,7 +230,7 @@ def format_int(n: int) -> bytes: def format_str_literal(s: str) -> bytes: - utf8 = s.encode("utf-8") + utf8 = s.encode("utf-8", errors="surrogatepass") return format_int(len(utf8)) + utf8 diff --git a/mypyc/doc/bytes_operations.rst b/mypyc/doc/bytes_operations.rst new file mode 100644 index 000000000000..038da6391949 --- /dev/null +++ b/mypyc/doc/bytes_operations.rst @@ -0,0 +1,46 @@ +.. _bytes-ops: + +Native bytes operations +======================== + +These ``bytes`` operations have fast, optimized implementations. Other +bytes operations use generic implementations that are often slower. + +Construction +------------ + +* Bytes literal +* ``bytes(x: list)`` + +Operators +--------- + +* Concatenation (``b1 + b2``) +* Indexing (``b[n]``) +* Slicing (``b[n:m]``, ``b[n:]``, ``b[:m]``) +* Comparisons (``==``, ``!=``) + +.. _bytes-methods: + +Methods +------- + +* ``b.decode()`` +* ``b.decode(encoding: str)`` +* ``b.decode(encoding: str, errors: str)`` +* ``b.join(x: Iterable)`` + +.. note:: + + :ref:`str.encode() ` is also optimized. + +Formatting +---------- + +A subset of % formatting operations are optimized (``b"..." % (...)``). + +Functions +--------- + +* ``len(b: bytes)`` +* ``ord(b: bytes)`` diff --git a/mypyc/doc/dev-intro.md b/mypyc/doc/dev-intro.md index d11df7068e91..461a19d37121 100644 --- a/mypyc/doc/dev-intro.md +++ b/mypyc/doc/dev-intro.md @@ -202,6 +202,10 @@ general overview of how things work. Test cases live under -q mypyc`. If you don't make changes to code under `mypy/`, it's not important to regularly run mypy tests during development. +You can use `python runtests.py mypyc-fast` to run a subset of mypyc +tests that covers most functionality but runs significantly quicker +than the entire test suite. + When you create a PR, we have Continuous Integration jobs set up that compile mypy using mypyc and run the mypy test suite using the compiled mypy. This will sometimes catch additional issues not caught diff --git a/mypyc/doc/index.rst b/mypyc/doc/index.rst index 5b1cc48fab3d..584d6739e803 100644 --- a/mypyc/doc/index.rst +++ b/mypyc/doc/index.rst @@ -36,6 +36,7 @@ generate fast code. bool_operations float_operations str_operations + bytes_operations list_operations dict_operations set_operations diff --git a/mypyc/doc/str_operations.rst b/mypyc/doc/str_operations.rst index 5420c8af7d31..9e94f1b6d7bb 100644 --- a/mypyc/doc/str_operations.rst +++ b/mypyc/doc/str_operations.rst @@ -22,9 +22,14 @@ Operators * Comparisons (``==``, ``!=``) * Augmented assignment (``s1 += s2``) +.. _str-methods: + Methods ------- +* ``s.encode()`` +* ``s.encode(encoding: str)`` +* ``s.encode(encoding: str, errors: str)`` * ``s1.endswith(s2: str)`` * ``s.join(x: Iterable)`` * ``s.replace(old: str, new: str)`` @@ -33,3 +38,22 @@ Methods * ``s.split(sep: str)`` * ``s.split(sep: str, maxsplit: int)`` * ``s1.startswith(s2: str)`` + +.. note:: + + :ref:`bytes.decode() ` is also optimized. + +Formatting +---------- + +A subset of these common string formatting expressions are optimized: + +* F-strings +* ``"...".format(...)`` +* ``"..." % (...)`` + +Functions +--------- + +* ``len(s: str)`` +* ``ord(s: str)`` diff --git a/mypyc/external/googletest/src/gtest.cc b/mypyc/external/googletest/src/gtest.cc index d882ab2e36a1..4df3bd6b418a 100644 --- a/mypyc/external/googletest/src/gtest.cc +++ b/mypyc/external/googletest/src/gtest.cc @@ -1784,7 +1784,7 @@ std::string CodePointToUtf8(UInt32 code_point) { return str; } -// The following two functions only make sense if the the system +// The following two functions only make sense if the system // uses UTF-16 for wide string encoding. All supported systems // with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16. diff --git a/mypyc/ir/class_ir.py b/mypyc/ir/class_ir.py index 18f3cbcff987..94bf714b28d4 100644 --- a/mypyc/ir/class_ir.py +++ b/mypyc/ir/class_ir.py @@ -93,6 +93,7 @@ def __init__( is_generated: bool = False, is_abstract: bool = False, is_ext_class: bool = True, + is_final_class: bool = False, ) -> None: self.name = name self.module_name = module_name @@ -100,6 +101,7 @@ def __init__( self.is_generated = is_generated self.is_abstract = is_abstract self.is_ext_class = is_ext_class + self.is_final_class = is_final_class # An augmented class has additional methods separate from what mypyc generates. # Right now the only one is dataclasses. self.is_augmented = False @@ -199,7 +201,8 @@ def __repr__(self) -> str: "ClassIR(" "name={self.name}, module_name={self.module_name}, " "is_trait={self.is_trait}, is_generated={self.is_generated}, " - "is_abstract={self.is_abstract}, is_ext_class={self.is_ext_class}" + "is_abstract={self.is_abstract}, is_ext_class={self.is_ext_class}, " + "is_final_class={self.is_final_class}" ")".format(self=self) ) @@ -248,8 +251,7 @@ def has_method(self, name: str) -> bool: def is_method_final(self, name: str) -> bool: subs = self.subclasses() if subs is None: - # TODO: Look at the final attribute! - return False + return self.is_final_class if self.has_method(name): method_decl = self.method_decl(name) @@ -349,6 +351,7 @@ def serialize(self) -> JsonDict: "is_abstract": self.is_abstract, "is_generated": self.is_generated, "is_augmented": self.is_augmented, + "is_final_class": self.is_final_class, "inherits_python": self.inherits_python, "has_dict": self.has_dict, "allow_interpreted_subclasses": self.allow_interpreted_subclasses, @@ -404,6 +407,7 @@ def deserialize(cls, data: JsonDict, ctx: DeserMaps) -> ClassIR: ir.is_abstract = data["is_abstract"] ir.is_ext_class = data["is_ext_class"] ir.is_augmented = data["is_augmented"] + ir.is_final_class = data["is_final_class"] ir.inherits_python = data["inherits_python"] ir.has_dict = data["has_dict"] ir.allow_interpreted_subclasses = data["allow_interpreted_subclasses"] diff --git a/mypyc/ir/ops.py b/mypyc/ir/ops.py index 896ba3ac091c..6e186c4ef0fc 100644 --- a/mypyc/ir/ops.py +++ b/mypyc/ir/ops.py @@ -625,7 +625,7 @@ def __init__( assert error_kind == ERR_NEVER def __repr__(self) -> str: - return f"" + return f"" class PrimitiveOp(RegisterOp): diff --git a/mypyc/ir/rtypes.py b/mypyc/ir/rtypes.py index fecfaee5ef77..53e3cee74e56 100644 --- a/mypyc/ir/rtypes.py +++ b/mypyc/ir/rtypes.py @@ -64,7 +64,7 @@ class RType: @abstractmethod def accept(self, visitor: RTypeVisitor[T]) -> T: - raise NotImplementedError + raise NotImplementedError() def short_name(self) -> str: return short_name(self.name) diff --git a/mypyc/irbuild/builder.py b/mypyc/irbuild/builder.py index a9e1ce471953..a0837ba2bfc7 100644 --- a/mypyc/irbuild/builder.py +++ b/mypyc/irbuild/builder.py @@ -84,6 +84,7 @@ IntOp, LoadStatic, Op, + PrimitiveDescription, RaiseStandardError, Register, SetAttr, @@ -381,6 +382,9 @@ def load_module(self, name: str) -> Value: def call_c(self, desc: CFunctionDescription, args: list[Value], line: int) -> Value: return self.builder.call_c(desc, args, line) + def primitive_op(self, desc: PrimitiveDescription, args: list[Value], line: int) -> Value: + return self.builder.primitive_op(desc, args, line) + def int_op(self, type: RType, lhs: Value, rhs: Value, op: int, line: int) -> Value: return self.builder.int_op(type, lhs, rhs, op, line) @@ -400,7 +404,7 @@ def add_to_non_ext_dict( ) -> None: # Add an attribute entry into the class dict of a non-extension class. key_unicode = self.load_str(key) - self.call_c(dict_set_item_op, [non_ext.dict, key_unicode, val], line) + self.primitive_op(dict_set_item_op, [non_ext.dict, key_unicode, val], line) def gen_import(self, id: str, line: int) -> None: self.imports[id] = None @@ -431,7 +435,7 @@ def get_module(self, module: str, line: int) -> Value: # Python 3.7 has a nice 'PyImport_GetModule' function that we can't use :( mod_dict = self.call_c(get_module_dict_op, [], line) # Get module object from modules dict. - return self.call_c(dict_get_item_op, [mod_dict, self.load_str(module)], line) + return self.primitive_op(dict_get_item_op, [mod_dict, self.load_str(module)], line) def get_module_attr(self, module: str, attr: str, line: int) -> Value: """Look up an attribute of a module without storing it in the local namespace. @@ -594,7 +598,7 @@ def get_assignment_target( if isinstance(symbol, Decorator): symbol = symbol.func if symbol is None: - # New semantic analyzer doesn't create ad-hoc Vars for special forms. + # Semantic analyzer doesn't create ad-hoc Vars for special forms. assert lvalue.is_special_form symbol = Var(lvalue.name) if not for_read and isinstance(symbol, Var) and symbol.is_cls: @@ -691,7 +695,7 @@ def assign(self, target: Register | AssignmentTarget, rvalue_reg: Value, line: i else: key = self.load_str(target.attr) boxed_reg = self.builder.box(rvalue_reg) - self.call_c(py_setattr_op, [target.obj, key, boxed_reg], line) + self.primitive_op(py_setattr_op, [target.obj, key, boxed_reg], line) elif isinstance(target, AssignmentTargetIndex): target_reg2 = self.gen_method_call( target.base, "__setitem__", [target.index, rvalue_reg], None, line @@ -768,7 +772,7 @@ def process_iterator_tuple_assignment_helper( def process_iterator_tuple_assignment( self, target: AssignmentTargetTuple, rvalue_reg: Value, line: int ) -> None: - iterator = self.call_c(iter_op, [rvalue_reg], line) + iterator = self.primitive_op(iter_op, [rvalue_reg], line) # This may be the whole lvalue list if there is no starred value split_idx = target.star_idx if target.star_idx is not None else len(target.items) @@ -794,7 +798,7 @@ def process_iterator_tuple_assignment( # Assign the starred value and all values after it if target.star_idx is not None: post_star_vals = target.items[split_idx + 1 :] - iter_list = self.call_c(to_list, [iterator], line) + iter_list = self.primitive_op(to_list, [iterator], line) iter_list_len = self.builtin_len(iter_list, line) post_star_len = Integer(len(post_star_vals)) condition = self.binary_op(post_star_len, iter_list_len, "<=", line) @@ -813,7 +817,7 @@ def process_iterator_tuple_assignment( self.activate_block(ok_block) for litem in reversed(post_star_vals): - ritem = self.call_c(list_pop_last, [iter_list], line) + ritem = self.primitive_op(list_pop_last, [iter_list], line) self.assign(litem, ritem, line) # Assign the starred value @@ -979,17 +983,13 @@ def _analyze_iterable_item_type(self, expr: Expression) -> Type: def is_native_module(self, module: str) -> bool: """Is the given module one compiled by mypyc?""" - return module in self.mapper.group_map + return self.mapper.is_native_module(module) def is_native_ref_expr(self, expr: RefExpr) -> bool: - if expr.node is None: - return False - if "." in expr.node.fullname: - return self.is_native_module(expr.node.fullname.rpartition(".")[0]) - return True + return self.mapper.is_native_ref_expr(expr) def is_native_module_ref_expr(self, expr: RefExpr) -> bool: - return self.is_native_ref_expr(expr) and expr.kind == GDEF + return self.mapper.is_native_module_ref_expr(expr) def is_synthetic_type(self, typ: TypeInfo) -> bool: """Is a type something other than just a class we've created?""" @@ -1055,9 +1055,9 @@ def call_refexpr_with_args( # Handle data-driven special-cased primitive call ops. if callee.fullname and expr.arg_kinds == [ARG_POS] * len(arg_values): fullname = get_call_target_fullname(callee) - call_c_ops_candidates = function_ops.get(fullname, []) - target = self.builder.matching_call_c( - call_c_ops_candidates, arg_values, expr.line, self.node_type(expr) + primitive_candidates = function_ops.get(fullname, []) + target = self.builder.matching_primitive_op( + primitive_candidates, arg_values, expr.line, self.node_type(expr) ) if target: return target @@ -1302,7 +1302,7 @@ def load_global(self, expr: NameExpr) -> Value: def load_global_str(self, name: str, line: int) -> Value: _globals = self.load_globals_dict() reg = self.load_str(name) - return self.call_c(dict_get_item_op, [_globals, reg], line) + return self.primitive_op(dict_get_item_op, [_globals, reg], line) def load_globals_dict(self) -> Value: return self.add(LoadStatic(dict_rprimitive, "globals", self.module_name)) diff --git a/mypyc/irbuild/classdef.py b/mypyc/irbuild/classdef.py index 7e0a842b1b41..6072efa2c593 100644 --- a/mypyc/irbuild/classdef.py +++ b/mypyc/irbuild/classdef.py @@ -7,11 +7,13 @@ from typing import Callable, Final from mypy.nodes import ( + EXCLUDED_ENUM_ATTRIBUTES, TYPE_VAR_TUPLE_KIND, AssignmentStmt, CallExpr, ClassDef, Decorator, + EllipsisExpr, ExpressionStmt, FuncDef, Lvalue, @@ -26,7 +28,7 @@ TypeParam, is_class_var, ) -from mypy.types import ENUM_REMOVED_PROPS, Instance, UnboundType, get_proper_type +from mypy.types import Instance, UnboundType, get_proper_type from mypyc.common import PROPSET_PREFIX from mypyc.ir.class_ir import ClassIR, NonExtClassInfo from mypyc.ir.func_ir import FuncDecl, FuncSignature @@ -80,6 +82,7 @@ pytype_from_template_op, type_object_op, ) +from mypyc.subtype import is_subtype def transform_class_def(builder: IRBuilder, cdef: ClassDef) -> None: @@ -145,7 +148,9 @@ def transform_class_def(builder: IRBuilder, cdef: ClassDef) -> None: continue with builder.catch_errors(stmt.line): cls_builder.add_method(get_func_def(stmt)) - elif isinstance(stmt, PassStmt): + elif isinstance(stmt, PassStmt) or ( + isinstance(stmt, ExpressionStmt) and isinstance(stmt.expr, EllipsisExpr) + ): continue elif isinstance(stmt, AssignmentStmt): if len(stmt.lvalues) != 1: @@ -251,7 +256,7 @@ def finalize(self, ir: ClassIR) -> None: ) # Add the non-extension class to the dict - self.builder.call_c( + self.builder.primitive_op( dict_set_item_op, [ self.builder.load_globals_dict(), @@ -287,7 +292,7 @@ def add_attr(self, lvalue: NameExpr, stmt: AssignmentStmt) -> None: return typ = self.builder.load_native_type_object(self.cdef.fullname) value = self.builder.accept(stmt.rvalue) - self.builder.call_c( + self.builder.primitive_op( py_setattr_op, [typ, self.builder.load_str(lvalue.name), value], stmt.line ) if self.builder.non_function_scope() and stmt.is_final_def: @@ -447,7 +452,7 @@ def allocate_class(builder: IRBuilder, cdef: ClassDef) -> Value: ) ) # Populate a '__mypyc_attrs__' field containing the list of attrs - builder.call_c( + builder.primitive_op( py_setattr_op, [ tp, @@ -461,7 +466,7 @@ def allocate_class(builder: IRBuilder, cdef: ClassDef) -> Value: builder.add(InitStatic(tp, cdef.name, builder.module_name, NAMESPACE_TYPE)) # Add it to the dict - builder.call_c( + builder.primitive_op( dict_set_item_op, [builder.load_globals_dict(), builder.load_str(cdef.name), tp], cdef.line ) @@ -478,7 +483,7 @@ def make_generic_base_class( for tv, type_param in zip(tvs, type_args): if type_param.kind == TYPE_VAR_TUPLE_KIND: # Evaluate *Ts for a TypeVarTuple - it = builder.call_c(iter_op, [tv], line) + it = builder.primitive_op(iter_op, [tv], line) tv = builder.call_c(next_op, [it], line) args.append(tv) @@ -488,7 +493,7 @@ def make_generic_base_class( else: arg = builder.new_tuple(args, line) - base = builder.call_c(py_get_item_op, [gent, arg], line) + base = builder.primitive_op(py_get_item_op, [gent, arg], line) return base @@ -508,7 +513,7 @@ def populate_non_ext_bases(builder: IRBuilder, cdef: ClassDef) -> Value: is_named_tuple = cdef.info.is_named_tuple ir = builder.mapper.type_to_ir[cdef.info] bases = [] - for cls in cdef.info.mro[1:]: + for cls in (b.type for b in cdef.info.bases): if cls.fullname == "builtins.object": continue if is_named_tuple and cls.fullname in ( @@ -598,7 +603,7 @@ def setup_non_ext_dict( This class dictionary is passed to the metaclass constructor. """ # Check if the metaclass defines a __prepare__ method, and if so, call it. - has_prepare = builder.call_c( + has_prepare = builder.primitive_op( py_hasattr_op, [metaclass, builder.load_str("__prepare__")], cdef.line ) @@ -656,7 +661,7 @@ def add_non_ext_class_attr_ann( typ = builder.add(LoadAddress(type_object_op.type, type_object_op.src, stmt.line)) key = builder.load_str(lvalue.name) - builder.call_c(dict_set_item_op, [non_ext.anns, key, typ], stmt.line) + builder.primitive_op(dict_set_item_op, [non_ext.anns, key, typ], stmt.line) def add_non_ext_class_attr( @@ -677,9 +682,9 @@ def add_non_ext_class_attr( # are final. if ( cdef.info.bases - and cdef.info.bases[0].type.fullname == "enum.Enum" + and cdef.info.bases[0].type.is_enum # Skip these since Enum will remove it - and lvalue.name not in ENUM_REMOVED_PROPS + and lvalue.name not in EXCLUDED_ENUM_ATTRIBUTES ): # Enum values are always boxed, so use object_rprimitive. attr_to_cache.append((lvalue, object_rprimitive)) @@ -798,30 +803,42 @@ def create_ne_from_eq(builder: IRBuilder, cdef: ClassDef) -> None: def gen_glue_ne_method(builder: IRBuilder, cls: ClassIR, line: int) -> None: """Generate a "__ne__" method from a "__eq__" method.""" - with builder.enter_method(cls, "__ne__", object_rprimitive): - rhs_arg = builder.add_argument("rhs", object_rprimitive) - - # If __eq__ returns NotImplemented, then __ne__ should also - not_implemented_block, regular_block = BasicBlock(), BasicBlock() + func_ir = cls.get_method("__eq__") + assert func_ir + eq_sig = func_ir.decl.sig + strict_typing = builder.options.strict_dunders_typing + with builder.enter_method(cls, "__ne__", eq_sig.ret_type): + rhs_type = eq_sig.args[0].type if strict_typing else object_rprimitive + rhs_arg = builder.add_argument("rhs", rhs_type) eqval = builder.add(MethodCall(builder.self(), "__eq__", [rhs_arg], line)) - not_implemented = builder.add( - LoadAddress(not_implemented_op.type, not_implemented_op.src, line) - ) - builder.add( - Branch( - builder.translate_is_op(eqval, not_implemented, "is", line), - not_implemented_block, - regular_block, - Branch.BOOL, - ) - ) - builder.activate_block(regular_block) - retval = builder.coerce(builder.unary_op(eqval, "not", line), object_rprimitive, line) - builder.add(Return(retval)) + can_return_not_implemented = is_subtype(not_implemented_op.type, eq_sig.ret_type) + return_bool = is_subtype(eq_sig.ret_type, bool_rprimitive) - builder.activate_block(not_implemented_block) - builder.add(Return(not_implemented)) + if not strict_typing or can_return_not_implemented: + # If __eq__ returns NotImplemented, then __ne__ should also + not_implemented_block, regular_block = BasicBlock(), BasicBlock() + not_implemented = builder.add( + LoadAddress(not_implemented_op.type, not_implemented_op.src, line) + ) + builder.add( + Branch( + builder.translate_is_op(eqval, not_implemented, "is", line), + not_implemented_block, + regular_block, + Branch.BOOL, + ) + ) + builder.activate_block(regular_block) + rettype = bool_rprimitive if return_bool and strict_typing else object_rprimitive + retval = builder.coerce(builder.unary_op(eqval, "not", line), rettype, line) + builder.add(Return(retval)) + builder.activate_block(not_implemented_block) + builder.add(Return(not_implemented)) + else: + rettype = bool_rprimitive if return_bool and strict_typing else object_rprimitive + retval = builder.coerce(builder.unary_op(eqval, "not", line), rettype, line) + builder.add(Return(retval)) def load_non_ext_class( diff --git a/mypyc/irbuild/expression.py b/mypyc/irbuild/expression.py index 8d7c089e20cd..97cd31af93af 100644 --- a/mypyc/irbuild/expression.py +++ b/mypyc/irbuild/expression.py @@ -10,6 +10,7 @@ from typing import Callable, Sequence from mypy.nodes import ( + ARG_NAMED, ARG_POS, LDEF, AssertTypeExpr, @@ -59,6 +60,7 @@ Integer, LoadAddress, LoadLiteral, + PrimitiveDescription, RaiseStandardError, Register, TupleGet, @@ -98,7 +100,7 @@ from mypyc.primitives.generic_ops import iter_op from mypyc.primitives.list_ops import list_append_op, list_extend_op, list_slice_op from mypyc.primitives.misc_ops import ellipsis_op, get_module_dict_op, new_slice_op, type_op -from mypyc.primitives.registry import CFunctionDescription, builtin_names +from mypyc.primitives.registry import builtin_names from mypyc.primitives.set_ops import set_add_op, set_in_op, set_update_op from mypyc.primitives.str_ops import str_slice_op from mypyc.primitives.tuple_ops import list_tuple_op, tuple_slice_op @@ -181,7 +183,7 @@ def transform_name_expr(builder: IRBuilder, expr: NameExpr) -> Value: # AST doesn't include a Var node for the module. We # instead load the module separately on each access. mod_dict = builder.call_c(get_module_dict_op, [], expr.line) - obj = builder.call_c( + obj = builder.primitive_op( dict_get_item_op, [mod_dict, builder.load_str(expr.node.fullname)], expr.line ) return obj @@ -355,6 +357,7 @@ def translate_method_call(builder: IRBuilder, expr: CallExpr, callee: MemberExpr and isinstance(callee.expr.node, TypeInfo) and callee.expr.node in builder.mapper.type_to_ir and builder.mapper.type_to_ir[callee.expr.node].has_method(callee.name) + and all(kind in (ARG_POS, ARG_NAMED) for kind in expr.arg_kinds) ): # Call a method via the *class* assert isinstance(callee.expr.node, TypeInfo) @@ -476,7 +479,7 @@ def translate_super_method_call(builder: IRBuilder, expr: CallExpr, callee: Supe # Grab first argument vself: Value = builder.self() if decl.kind == FUNC_CLASSMETHOD: - vself = builder.call_c(type_op, [vself], expr.line) + vself = builder.primitive_op(type_op, [vself], expr.line) elif builder.fn_info.is_generator: # For generator classes, the self target is the 6th value # in the symbol table (which is an ordered dict). This is sort @@ -953,7 +956,7 @@ def transform_tuple_expr(builder: IRBuilder, expr: TupleExpr) -> Value: def _visit_tuple_display(builder: IRBuilder, expr: TupleExpr) -> Value: """Create a list, then turn it into a tuple.""" val_as_list = _visit_list_display(builder, expr.items, expr.line) - return builder.call_c(list_tuple_op, [val_as_list], expr.line) + return builder.primitive_op(list_tuple_op, [val_as_list], expr.line) def transform_dict_expr(builder: IRBuilder, expr: DictExpr) -> Value: @@ -977,8 +980,8 @@ def _visit_display( builder: IRBuilder, items: list[Expression], constructor_op: Callable[[list[Value], int], Value], - append_op: CFunctionDescription, - extend_op: CFunctionDescription, + append_op: PrimitiveDescription, + extend_op: PrimitiveDescription, line: int, is_list: bool, ) -> Value: @@ -999,7 +1002,7 @@ def _visit_display( if result is None: result = constructor_op(initial_items, line) - builder.call_c(extend_op if starred else append_op, [result, value], line) + builder.primitive_op(extend_op if starred else append_op, [result, value], line) if result is None: result = constructor_op(initial_items, line) @@ -1028,7 +1031,7 @@ def transform_dictionary_comprehension(builder: IRBuilder, o: DictionaryComprehe def gen_inner_stmts() -> None: k = builder.accept(o.key) v = builder.accept(o.value) - builder.call_c(dict_set_item_op, [builder.read(d), k, v], o.line) + builder.primitive_op(dict_set_item_op, [builder.read(d), k, v], o.line) comprehension_helper(builder, loop_params, gen_inner_stmts, o.line) return builder.read(d) @@ -1045,12 +1048,12 @@ def get_arg(arg: Expression | None) -> Value: return builder.accept(arg) args = [get_arg(expr.begin_index), get_arg(expr.end_index), get_arg(expr.stride)] - return builder.call_c(new_slice_op, args, expr.line) + return builder.primitive_op(new_slice_op, args, expr.line) def transform_generator_expr(builder: IRBuilder, o: GeneratorExpr) -> Value: builder.warning("Treating generator comprehension as list", o.line) - return builder.call_c(iter_op, [translate_list_comprehension(builder, o)], o.line) + return builder.primitive_op(iter_op, [translate_list_comprehension(builder, o)], o.line) def transform_assignment_expr(builder: IRBuilder, o: AssignmentExpr) -> Value: diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index 5d8315e88f72..9b34a094db60 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -251,7 +251,7 @@ def translate_list_comprehension(builder: IRBuilder, gen: GeneratorExpr) -> Valu def gen_inner_stmts() -> None: e = builder.accept(gen.left_expr) - builder.call_c(list_append_op, [builder.read(list_ops), e], gen.line) + builder.primitive_op(list_append_op, [builder.read(list_ops), e], gen.line) comprehension_helper(builder, loop_params, gen_inner_stmts, gen.line) return builder.read(list_ops) @@ -286,7 +286,7 @@ def translate_set_comprehension(builder: IRBuilder, gen: GeneratorExpr) -> Value def gen_inner_stmts() -> None: e = builder.accept(gen.left_expr) - builder.call_c(set_add_op, [builder.read(set_ops), e], gen.line) + builder.primitive_op(set_add_op, [builder.read(set_ops), e], gen.line) comprehension_helper(builder, loop_params, gen_inner_stmts, gen.line) return builder.read(set_ops) @@ -586,7 +586,7 @@ def init(self, expr_reg: Value, target_type: RType) -> None: # for the for-loop. If we are inside of a generator function, spill these into the # environment class. builder = self.builder - iter_reg = builder.call_c(iter_op, [expr_reg], self.line) + iter_reg = builder.primitive_op(iter_op, [expr_reg], self.line) builder.maybe_spill(expr_reg) self.iter_target = builder.maybe_spill(iter_reg) self.target_type = target_type @@ -985,7 +985,6 @@ def init(self) -> None: zero = Integer(0) self.index_reg = builder.maybe_spill_assignable(zero) self.index_target: Register | AssignmentTarget = builder.get_assignment_target(self.index) - builder.assign(self.index_target, zero, self.line) def gen_step(self) -> None: builder = self.builder @@ -997,7 +996,9 @@ def gen_step(self) -> None: short_int_rprimitive, builder.read(self.index_reg, line), Integer(1), IntOp.ADD, line ) builder.assign(self.index_reg, new_val, line) - builder.assign(self.index_target, new_val, line) + + def begin_body(self) -> None: + self.builder.assign(self.index_target, self.builder.read(self.index_reg), self.line) class ForEnumerate(ForGenerator): diff --git a/mypyc/irbuild/format_str_tokenizer.py b/mypyc/irbuild/format_str_tokenizer.py index 0b46887811fb..eaa4027ed768 100644 --- a/mypyc/irbuild/format_str_tokenizer.py +++ b/mypyc/irbuild/format_str_tokenizer.py @@ -146,12 +146,12 @@ def convert_format_expr_to_str( if is_str_rprimitive(node_type): var_str = builder.accept(x) elif is_int_rprimitive(node_type) or is_short_int_rprimitive(node_type): - var_str = builder.call_c(int_to_str_op, [builder.accept(x)], line) + var_str = builder.primitive_op(int_to_str_op, [builder.accept(x)], line) else: - var_str = builder.call_c(str_op, [builder.accept(x)], line) + var_str = builder.primitive_op(str_op, [builder.accept(x)], line) elif format_op == FormatOp.INT: if is_int_rprimitive(node_type) or is_short_int_rprimitive(node_type): - var_str = builder.call_c(int_to_str_op, [builder.accept(x)], line) + var_str = builder.primitive_op(int_to_str_op, [builder.accept(x)], line) else: return None else: diff --git a/mypyc/irbuild/function.py b/mypyc/irbuild/function.py index c985e88b0e0c..a84db5a08863 100644 --- a/mypyc/irbuild/function.py +++ b/mypyc/irbuild/function.py @@ -96,7 +96,8 @@ def transform_func_def(builder: IRBuilder, fdef: FuncDef) -> None: - func_ir, func_reg = gen_func_item(builder, fdef, fdef.name, builder.mapper.fdef_to_sig(fdef)) + sig = builder.mapper.fdef_to_sig(fdef, builder.options.strict_dunders_typing) + func_ir, func_reg = gen_func_item(builder, fdef, fdef.name, sig) # If the function that was visited was a nested function, then either look it up in our # current environment or define it if it was not already defined. @@ -113,9 +114,8 @@ def transform_overloaded_func_def(builder: IRBuilder, o: OverloadedFuncDef) -> N def transform_decorator(builder: IRBuilder, dec: Decorator) -> None: - func_ir, func_reg = gen_func_item( - builder, dec.func, dec.func.name, builder.mapper.fdef_to_sig(dec.func) - ) + sig = builder.mapper.fdef_to_sig(dec.func, builder.options.strict_dunders_typing) + func_ir, func_reg = gen_func_item(builder, dec.func, dec.func.name, sig) decorated_func: Value | None = None if func_reg: decorated_func = load_decorated_func(builder, dec.func, func_reg) @@ -133,7 +133,7 @@ def transform_decorator(builder: IRBuilder, dec: Decorator) -> None: if decorated_func is not None: # Set the callable object representing the decorated function as a global. - builder.call_c( + builder.primitive_op( dict_set_item_op, [builder.load_globals_dict(), builder.load_str(dec.func.name), decorated_func], decorated_func.line, @@ -416,7 +416,8 @@ def handle_ext_method(builder: IRBuilder, cdef: ClassDef, fdef: FuncDef) -> None # Perform the function of visit_method for methods inside extension classes. name = fdef.name class_ir = builder.mapper.type_to_ir[cdef.info] - func_ir, func_reg = gen_func_item(builder, fdef, name, builder.mapper.fdef_to_sig(fdef), cdef) + sig = builder.mapper.fdef_to_sig(fdef, builder.options.strict_dunders_typing) + func_ir, func_reg = gen_func_item(builder, fdef, name, sig, cdef) builder.functions.append(func_ir) if is_decorated(builder, fdef): @@ -432,7 +433,9 @@ def handle_ext_method(builder: IRBuilder, cdef: ClassDef, fdef: FuncDef) -> None # Set the callable object representing the decorated method as an attribute of the # extension class. - builder.call_c(py_setattr_op, [typ, builder.load_str(name), decorated_func], fdef.line) + builder.primitive_op( + py_setattr_op, [typ, builder.load_str(name), decorated_func], fdef.line + ) if fdef.is_property: # If there is a property setter, it will be processed after the getter, @@ -481,7 +484,8 @@ def handle_non_ext_method( ) -> None: # Perform the function of visit_method for methods inside non-extension classes. name = fdef.name - func_ir, func_reg = gen_func_item(builder, fdef, name, builder.mapper.fdef_to_sig(fdef), cdef) + sig = builder.mapper.fdef_to_sig(fdef, builder.options.strict_dunders_typing) + func_ir, func_reg = gen_func_item(builder, fdef, name, sig, cdef) assert func_reg is not None builder.functions.append(func_ir) @@ -804,6 +808,11 @@ def load_type(builder: IRBuilder, typ: TypeInfo, line: int) -> Value: elif typ.fullname in builtin_names: builtin_addr_type, src = builtin_names[typ.fullname] class_obj = builder.add(LoadAddress(builtin_addr_type, src, line)) + elif typ.module_name in builder.imports: + loaded_module = builder.load_module(typ.module_name) + class_obj = builder.builder.get_attr( + loaded_module, typ.name, object_rprimitive, line, borrow=False + ) else: class_obj = builder.load_global_str(typ.name, line) @@ -840,7 +849,7 @@ def generate_singledispatch_dispatch_function( dispatch_func_obj, "dispatch_cache", dict_rprimitive, line ) call_find_impl, use_cache, call_func = BasicBlock(), BasicBlock(), BasicBlock() - get_result = builder.call_c(dict_get_method_with_none, [dispatch_cache, arg_type], line) + get_result = builder.primitive_op(dict_get_method_with_none, [dispatch_cache, arg_type], line) is_not_none = builder.translate_is_op(get_result, builder.none_object(), "is not", line) impl_to_use = Register(object_rprimitive) builder.add_bool_branch(is_not_none, use_cache, call_find_impl) @@ -853,7 +862,7 @@ def generate_singledispatch_dispatch_function( find_impl = builder.load_module_attr_by_fullname("functools._find_impl", line) registry = load_singledispatch_registry(builder, dispatch_func_obj, line) uncached_impl = builder.py_call(find_impl, [arg_type, registry], line) - builder.call_c(dict_set_item_op, [dispatch_cache, arg_type, uncached_impl], line) + builder.primitive_op(dict_set_item_op, [dispatch_cache, arg_type, uncached_impl], line) builder.assign(impl_to_use, uncached_impl, line) builder.goto(call_func) @@ -966,7 +975,7 @@ def generate_singledispatch_callable_class_ctor(builder: IRBuilder) -> None: cache_dict = builder.call_c(dict_new_op, [], line) dispatch_cache_str = builder.load_str("dispatch_cache") # use the py_setattr_op instead of SetAttr so that it also gets added to our __dict__ - builder.call_c(py_setattr_op, [builder.self(), dispatch_cache_str, cache_dict], line) + builder.primitive_op(py_setattr_op, [builder.self(), dispatch_cache_str, cache_dict], line) # the generated C code seems to expect that __init__ returns a char, so just return 1 builder.add(Return(Integer(1, bool_rprimitive, line), line)) @@ -988,10 +997,6 @@ def singledispatch_main_func_name(orig_name: str) -> str: return f"__mypyc_singledispatch_main_function_{orig_name}__" -def get_registry_identifier(fitem: FuncDef) -> str: - return f"__mypyc_singledispatch_registry_{fitem.fullname}__" - - def maybe_insert_into_registry_dict(builder: IRBuilder, fitem: FuncDef) -> None: line = fitem.line is_singledispatch_main_func = fitem in builder.singledispatch_impls @@ -1013,7 +1018,7 @@ def maybe_insert_into_registry_dict(builder: IRBuilder, fitem: FuncDef) -> None: registry_dict = builder.builder.make_dict([(loaded_object_type, main_func_obj)], line) dispatch_func_obj = builder.load_global_str(fitem.name, line) - builder.call_c( + builder.primitive_op( py_setattr_op, [dispatch_func_obj, builder.load_str("registry"), registry_dict], line ) @@ -1034,7 +1039,7 @@ def maybe_insert_into_registry_dict(builder: IRBuilder, fitem: FuncDef) -> None: registry = load_singledispatch_registry(builder, dispatch_func_obj, line) for typ in types: loaded_type = load_type(builder, typ, line) - builder.call_c(dict_set_item_op, [registry, loaded_type, to_insert], line) + builder.primitive_op(dict_set_item_op, [registry, loaded_type, to_insert], line) dispatch_cache = builder.builder.get_attr( dispatch_func_obj, "dispatch_cache", dict_rprimitive, line ) diff --git a/mypyc/irbuild/ll_builder.py b/mypyc/irbuild/ll_builder.py index 0c9310e6a5ca..556d753b89f8 100644 --- a/mypyc/irbuild/ll_builder.py +++ b/mypyc/irbuild/ll_builder.py @@ -14,7 +14,7 @@ from mypy.argmap import map_actuals_to_formals from mypy.nodes import ARG_POS, ARG_STAR, ARG_STAR2, ArgKind -from mypy.operators import op_methods +from mypy.operators import op_methods, unary_op_methods from mypy.types import AnyType, TypeOfAny from mypyc.common import ( BITMAP_BITS, @@ -167,6 +167,7 @@ buf_init_item, fast_isinstance_op, none_object_op, + not_implemented_op, var_object_size, ) from mypyc.primitives.registry import ( @@ -619,7 +620,7 @@ def py_get_attr(self, obj: Value, attr: str, line: int) -> Value: Prefer get_attr() which generates optimized code for native classes. """ key = self.load_str(attr) - return self.call_c(py_getattr_op, [obj, key], line) + return self.primitive_op(py_getattr_op, [obj, key], line) # isinstance() checks @@ -655,7 +656,9 @@ def isinstance_native(self, obj: Value, class_ir: ClassIR, line: int) -> Value: """ concrete = all_concrete_classes(class_ir) if concrete is None or len(concrete) > FAST_ISINSTANCE_MAX_SUBCLASSES + 1: - return self.call_c(fast_isinstance_op, [obj, self.get_native_type(class_ir)], line) + return self.primitive_op( + fast_isinstance_op, [obj, self.get_native_type(class_ir)], line + ) if not concrete: # There can't be any concrete instance that matches this. return self.false() @@ -759,7 +762,7 @@ def _construct_varargs( if kind == ARG_STAR: if star_result is None: star_result = self.new_list_op(star_values, line) - self.call_c(list_extend_op, [star_result, value], line) + self.primitive_op(list_extend_op, [star_result, value], line) elif kind == ARG_STAR2: if star2_result is None: star2_result = self._create_dict(star2_keys, star2_values, line) @@ -856,7 +859,7 @@ def _construct_varargs( if star_result is None: star_result = self.new_tuple(star_values, line) else: - star_result = self.call_c(list_tuple_op, [star_result], line) + star_result = self.primitive_op(list_tuple_op, [star_result], line) if has_star2 and star2_result is None: star2_result = self._create_dict(star2_keys, star2_values, line) @@ -1398,11 +1401,48 @@ def binary_op(self, lreg: Value, rreg: Value, op: str, line: int) -> Value: if base_op in float_op_to_id: return self.float_op(lreg, rreg, base_op, line) + dunder_op = self.dunder_op(lreg, rreg, op, line) + if dunder_op: + return dunder_op + primitive_ops_candidates = binary_ops.get(op, []) target = self.matching_primitive_op(primitive_ops_candidates, [lreg, rreg], line) assert target, "Unsupported binary operation: %s" % op return target + def dunder_op(self, lreg: Value, rreg: Value | None, op: str, line: int) -> Value | None: + """ + Dispatch a dunder method if applicable. + For example for `a + b` it will use `a.__add__(b)` which can lead to higher performance + due to the fact that the method could be already compiled and optimized instead of going + all the way through `PyNumber_Add(a, b)` python api (making a jump into the python DL). + """ + ltype = lreg.type + if not isinstance(ltype, RInstance): + return None + + method_name = op_methods.get(op) if rreg else unary_op_methods.get(op) + if method_name is None: + return None + + if not ltype.class_ir.has_method(method_name): + return None + + decl = ltype.class_ir.method_decl(method_name) + if not rreg and len(decl.sig.args) != 1: + return None + + if rreg and (len(decl.sig.args) != 2 or not is_subtype(rreg.type, decl.sig.args[1].type)): + return None + + if rreg and is_subtype(not_implemented_op.type, decl.sig.ret_type): + # If the method is able to return NotImplemented, we should not optimize it. + # We can just let go so it will be handled through the python api. + return None + + args = [rreg] if rreg else [] + return self.gen_method_call(lreg, method_name, args, decl.sig.ret_type, line) + def check_tagged_short_int(self, val: Value, line: int, negated: bool = False) -> Value: """Check if a tagged integer is a short integer. @@ -1477,7 +1517,7 @@ def compare_tuples(self, lhs: Value, rhs: Value, op: str, line: int = -1) -> Val # Cast to bool if necessary since most types uses comparison returning a object type # See generic_ops.py for more information if not is_bool_rprimitive(compare.type): - compare = self.call_c(bool_op, [compare], line) + compare = self.primitive_op(bool_op, [compare], line) if i < len(lhs.type.types) - 1: branch = Branch(compare, early_stop, check_blocks[i + 1], Branch.BOOL) else: @@ -1496,7 +1536,7 @@ def compare_tuples(self, lhs: Value, rhs: Value, op: str, line: int = -1) -> Val def translate_instance_contains(self, inst: Value, item: Value, op: str, line: int) -> Value: res = self.gen_method_call(inst, "__contains__", [item], None, line) if not is_bool_rprimitive(res.type): - res = self.call_c(bool_op, [res], line) + res = self.primitive_op(bool_op, [res], line) if op == "not in": res = self.bool_bitwise_op(res, Integer(1, rtype=bool_rprimitive), "^", line) return res @@ -1558,18 +1598,11 @@ def unary_op(self, value: Value, expr_op: str, line: int) -> Value: if isinstance(value, Float): return Float(-value.value, value.line) if isinstance(typ, RInstance): - if expr_op == "-": - method = "__neg__" - elif expr_op == "+": - method = "__pos__" - elif expr_op == "~": - method = "__invert__" - else: - method = "" - if method and typ.class_ir.has_method(method): - return self.gen_method_call(value, method, [], None, line) - call_c_ops_candidates = unary_ops.get(expr_op, []) - target = self.matching_call_c(call_c_ops_candidates, [value], line) + result = self.dunder_op(value, None, expr_op, line) + if result is not None: + return result + primitive_ops_candidates = unary_ops.get(expr_op, []) + target = self.matching_primitive_op(primitive_ops_candidates, [value], line) assert target, "Unsupported unary operation: %s" % expr_op return target @@ -1636,7 +1669,7 @@ def new_list_op(self, values: list[Value], line: int) -> Value: return result_list def new_set_op(self, values: list[Value], line: int) -> Value: - return self.call_c(new_set_op, values, line) + return self.primitive_op(new_set_op, values, line) def setup_rarray( self, item_type: RType, values: Sequence[Value], *, object_ptr: bool = False @@ -1744,7 +1777,7 @@ def bool_value(self, value: Value) -> Value: self.goto(end) self.activate_block(end) else: - result = self.call_c(bool_op, [value], value.line) + result = self.primitive_op(bool_op, [value], value.line) return result def add_bool_branch(self, value: Value, true: BasicBlock, false: BasicBlock) -> None: @@ -1889,7 +1922,7 @@ def primitive_op( # Does this primitive map into calling a Python C API # or an internal mypyc C API function? if desc.c_function_name: - # TODO: Generate PrimitiOps here and transform them into CallC + # TODO: Generate PrimitiveOps here and transform them into CallC # ops only later in the lowering pass c_desc = CFunctionDescription( desc.name, @@ -1906,9 +1939,9 @@ def primitive_op( desc.priority, is_pure=desc.is_pure, ) - return self.call_c(c_desc, args, line, result_type) + return self.call_c(c_desc, args, line, result_type=result_type) - # This primitve gets transformed in a lowering pass to + # This primitive gets transformed in a lowering pass to # lower-level IR ops using a custom transform function. coerced = [] @@ -1972,7 +2005,7 @@ def matching_primitive_op( else: matching = desc if matching: - return self.primitive_op(matching, args, line=line) + return self.primitive_op(matching, args, line=line, result_type=result_type) return None def int_op(self, type: RType, lhs: Value, rhs: Value, op: int, line: int = -1) -> Value: @@ -2034,7 +2067,7 @@ def float_mod(self, lhs: Value, rhs: Value, line: int) -> Value: self.activate_block(copysign) # If the remainder is zero, CPython ensures the result has the # same sign as the denominator. - adj = self.call_c(copysign_op, [Float(0.0), rhs], line) + adj = self.primitive_op(copysign_op, [Float(0.0), rhs], line) self.add(Assign(res, adj)) self.add(Goto(done)) self.activate_block(done) @@ -2229,7 +2262,7 @@ def new_tuple_with_length(self, length: Value, line: int) -> Value: return self.call_c(new_tuple_with_length_op, [length], line) def int_to_float(self, n: Value, line: int) -> Value: - return self.call_c(int_to_float_op, [n], line) + return self.primitive_op(int_to_float_op, [n], line) # Internal helpers @@ -2313,11 +2346,11 @@ def translate_special_method_call( Return None if no translation found; otherwise return the target register. """ - call_c_ops_candidates = method_call_ops.get(name, []) - call_c_op = self.matching_call_c( - call_c_ops_candidates, [base_reg] + args, line, result_type, can_borrow=can_borrow + primitive_ops_candidates = method_call_ops.get(name, []) + primitive_op = self.matching_primitive_op( + primitive_ops_candidates, [base_reg] + args, line, result_type, can_borrow=can_borrow ) - return call_c_op + return primitive_op def translate_eq_cmp(self, lreg: Value, rreg: Value, expr_op: str, line: int) -> Value | None: """Add a equality comparison operation. diff --git a/mypyc/irbuild/mapper.py b/mypyc/irbuild/mapper.py index 90ce0e16c741..9cd263c40ae4 100644 --- a/mypyc/irbuild/mapper.py +++ b/mypyc/irbuild/mapper.py @@ -62,6 +62,7 @@ def __init__(self, group_map: dict[str, str | None]) -> None: self.group_map = group_map self.type_to_ir: dict[TypeInfo, ClassIR] = {} self.func_to_decl: dict[SymbolNode, FuncDecl] = {} + self.symbol_fullnames: set[str] = set() def type_to_rtype(self, typ: Type | None) -> RType: if typ is None: @@ -160,7 +161,7 @@ def get_arg_rtype(self, typ: Type, kind: ArgKind) -> RType: else: return self.type_to_rtype(typ) - def fdef_to_sig(self, fdef: FuncDef) -> FuncSignature: + def fdef_to_sig(self, fdef: FuncDef, strict_dunders_typing: bool) -> FuncSignature: if isinstance(fdef.type, CallableType): arg_types = [ self.get_arg_rtype(typ, kind) @@ -199,11 +200,14 @@ def fdef_to_sig(self, fdef: FuncDef) -> FuncSignature: ) ] - # We force certain dunder methods to return objects to support letting them - # return NotImplemented. It also avoids some pointless boxing and unboxing, - # since tp_richcompare needs an object anyways. - if fdef.name in ("__eq__", "__ne__", "__lt__", "__gt__", "__le__", "__ge__"): - ret = object_rprimitive + if not strict_dunders_typing: + # We force certain dunder methods to return objects to support letting them + # return NotImplemented. It also avoids some pointless boxing and unboxing, + # since tp_richcompare needs an object anyways. + # However, it also prevents some optimizations. + if fdef.name in ("__eq__", "__ne__", "__lt__", "__gt__", "__le__", "__ge__"): + ret = object_rprimitive + return FuncSignature(args, ret) def is_native_module(self, module: str) -> bool: @@ -214,7 +218,8 @@ def is_native_ref_expr(self, expr: RefExpr) -> bool: if expr.node is None: return False if "." in expr.node.fullname: - return self.is_native_module(expr.node.fullname.rpartition(".")[0]) + name = expr.node.fullname.rpartition(".")[0] + return self.is_native_module(name) or name in self.symbol_fullnames return True def is_native_module_ref_expr(self, expr: RefExpr) -> bool: diff --git a/mypyc/irbuild/match.py b/mypyc/irbuild/match.py index a1e671911ea5..976a8810b327 100644 --- a/mypyc/irbuild/match.py +++ b/mypyc/irbuild/match.py @@ -131,7 +131,7 @@ def visit_class_pattern(self, pattern: ClassPattern) -> None: else slow_isinstance_op ) - cond = self.builder.call_c( + cond = self.builder.primitive_op( isinstance_op, [self.subject, self.builder.accept(pattern.class_ref)], pattern.line ) @@ -246,7 +246,7 @@ def visit_mapping_pattern(self, pattern: MappingPattern) -> None: self.builder.activate_block(self.code_block) self.code_block = BasicBlock() - rest = self.builder.call_c(dict_copy, [self.subject], pattern.rest.line) + rest = self.builder.primitive_op(dict_copy, [self.subject], pattern.rest.line) target = self.builder.get_assignment_target(pattern.rest) diff --git a/mypyc/irbuild/prepare.py b/mypyc/irbuild/prepare.py index 29e06439abdd..4b132bb83722 100644 --- a/mypyc/irbuild/prepare.py +++ b/mypyc/irbuild/prepare.py @@ -81,7 +81,11 @@ def build_type_map( # references even if there are import cycles. for module, cdef in classes: class_ir = ClassIR( - cdef.name, module.fullname, is_trait(cdef), is_abstract=cdef.info.is_abstract + cdef.name, + module.fullname, + is_trait(cdef), + is_abstract=cdef.info.is_abstract, + is_final_class=cdef.info.is_final, ) class_ir.is_ext_class = is_extension_class(cdef) if class_ir.is_ext_class: @@ -90,14 +94,17 @@ def build_type_map( if not options.global_opts: class_ir.children = None mapper.type_to_ir[cdef.info] = class_ir + mapper.symbol_fullnames.add(class_ir.fullname) # Populate structural information in class IR for extension classes. for module, cdef in classes: with catch_errors(module.path, cdef.line): if mapper.type_to_ir[cdef.info].is_ext_class: - prepare_class_def(module.path, module.fullname, cdef, errors, mapper) + prepare_class_def(module.path, module.fullname, cdef, errors, mapper, options) else: - prepare_non_ext_class_def(module.path, module.fullname, cdef, errors, mapper) + prepare_non_ext_class_def( + module.path, module.fullname, cdef, errors, mapper, options + ) # Prepare implicit attribute accessors as needed if an attribute overrides a property. for module, cdef in classes: @@ -110,7 +117,7 @@ def build_type_map( # is conditionally defined. for module in modules: for func in get_module_func_defs(module): - prepare_func_def(module.fullname, None, func, mapper) + prepare_func_def(module.fullname, None, func, mapper, options) # TODO: what else? # Check for incompatible attribute definitions that were not @@ -143,6 +150,7 @@ def load_type_map(mapper: Mapper, modules: list[MypyFile], deser_ctx: DeserMaps) if isinstance(node.node, TypeInfo) and is_from_module(node.node, module): ir = deser_ctx.classes[node.node.fullname] mapper.type_to_ir[node.node] = ir + mapper.symbol_fullnames.add(node.node.fullname) mapper.func_to_decl[node.node] = ir.ctor for module in modules: @@ -164,27 +172,39 @@ def get_module_func_defs(module: MypyFile) -> Iterable[FuncDef]: def prepare_func_def( - module_name: str, class_name: str | None, fdef: FuncDef, mapper: Mapper + module_name: str, + class_name: str | None, + fdef: FuncDef, + mapper: Mapper, + options: CompilerOptions, ) -> FuncDecl: kind = ( FUNC_STATICMETHOD if fdef.is_static else (FUNC_CLASSMETHOD if fdef.is_class else FUNC_NORMAL) ) - decl = FuncDecl(fdef.name, class_name, module_name, mapper.fdef_to_sig(fdef), kind) + sig = mapper.fdef_to_sig(fdef, options.strict_dunders_typing) + decl = FuncDecl(fdef.name, class_name, module_name, sig, kind) mapper.func_to_decl[fdef] = decl return decl def prepare_method_def( - ir: ClassIR, module_name: str, cdef: ClassDef, mapper: Mapper, node: FuncDef | Decorator + ir: ClassIR, + module_name: str, + cdef: ClassDef, + mapper: Mapper, + node: FuncDef | Decorator, + options: CompilerOptions, ) -> None: if isinstance(node, FuncDef): - ir.method_decls[node.name] = prepare_func_def(module_name, cdef.name, node, mapper) + ir.method_decls[node.name] = prepare_func_def( + module_name, cdef.name, node, mapper, options + ) elif isinstance(node, Decorator): # TODO: do something about abstract methods here. Currently, they are handled just like # normal methods. - decl = prepare_func_def(module_name, cdef.name, node.func, mapper) + decl = prepare_func_def(module_name, cdef.name, node.func, mapper, options) if not node.decorators: ir.method_decls[node.name] = decl elif isinstance(node.decorators[0], MemberExpr) and node.decorators[0].name == "setter": @@ -237,7 +257,12 @@ def can_subclass_builtin(builtin_base: str) -> bool: def prepare_class_def( - path: str, module_name: str, cdef: ClassDef, errors: Errors, mapper: Mapper + path: str, + module_name: str, + cdef: ClassDef, + errors: Errors, + mapper: Mapper, + options: CompilerOptions, ) -> None: """Populate the interface-level information in a class IR. @@ -304,7 +329,7 @@ def prepare_class_def( ir.mro = mro ir.base_mro = base_mro - prepare_methods_and_attributes(cdef, ir, path, module_name, errors, mapper) + prepare_methods_and_attributes(cdef, ir, path, module_name, errors, mapper, options) prepare_init_method(cdef, ir, module_name, mapper) for base in bases: @@ -316,7 +341,13 @@ def prepare_class_def( def prepare_methods_and_attributes( - cdef: ClassDef, ir: ClassIR, path: str, module_name: str, errors: Errors, mapper: Mapper + cdef: ClassDef, + ir: ClassIR, + path: str, + module_name: str, + errors: Errors, + mapper: Mapper, + options: CompilerOptions, ) -> None: """Populate attribute and method declarations.""" info = cdef.info @@ -338,20 +369,20 @@ def prepare_methods_and_attributes( add_setter_declaration(ir, name, attr_rtype, module_name) ir.attributes[name] = attr_rtype elif isinstance(node.node, (FuncDef, Decorator)): - prepare_method_def(ir, module_name, cdef, mapper, node.node) + prepare_method_def(ir, module_name, cdef, mapper, node.node, options) elif isinstance(node.node, OverloadedFuncDef): # Handle case for property with both a getter and a setter if node.node.is_property: if is_valid_multipart_property_def(node.node): for item in node.node.items: - prepare_method_def(ir, module_name, cdef, mapper, item) + prepare_method_def(ir, module_name, cdef, mapper, item, options) else: errors.error("Unsupported property decorator semantics", path, cdef.line) # Handle case for regular function overload else: assert node.node.impl - prepare_method_def(ir, module_name, cdef, mapper, node.node.impl) + prepare_method_def(ir, module_name, cdef, mapper, node.node.impl, options) if ir.builtin_base: ir.attributes.clear() @@ -436,7 +467,7 @@ def prepare_init_method(cdef: ClassDef, ir: ClassIR, module_name: str, mapper: M # Set up a constructor decl init_node = cdef.info["__init__"].node if not ir.is_trait and not ir.builtin_base and isinstance(init_node, FuncDef): - init_sig = mapper.fdef_to_sig(init_node) + init_sig = mapper.fdef_to_sig(init_node, True) defining_ir = mapper.type_to_ir.get(init_node.info) # If there is a nontrivial __init__ that wasn't defined in an @@ -463,24 +494,29 @@ def prepare_init_method(cdef: ClassDef, ir: ClassIR, module_name: str, mapper: M def prepare_non_ext_class_def( - path: str, module_name: str, cdef: ClassDef, errors: Errors, mapper: Mapper + path: str, + module_name: str, + cdef: ClassDef, + errors: Errors, + mapper: Mapper, + options: CompilerOptions, ) -> None: ir = mapper.type_to_ir[cdef.info] info = cdef.info for node in info.names.values(): if isinstance(node.node, (FuncDef, Decorator)): - prepare_method_def(ir, module_name, cdef, mapper, node.node) + prepare_method_def(ir, module_name, cdef, mapper, node.node, options) elif isinstance(node.node, OverloadedFuncDef): # Handle case for property with both a getter and a setter if node.node.is_property: if not is_valid_multipart_property_def(node.node): errors.error("Unsupported property decorator semantics", path, cdef.line) for item in node.node.items: - prepare_method_def(ir, module_name, cdef, mapper, item) + prepare_method_def(ir, module_name, cdef, mapper, item, options) # Handle case for regular function overload else: - prepare_method_def(ir, module_name, cdef, mapper, get_func_def(node.node)) + prepare_method_def(ir, module_name, cdef, mapper, get_func_def(node.node), options) if any(cls in mapper.type_to_ir and mapper.type_to_ir[cls].is_ext_class for cls in info.mro): errors.error( diff --git a/mypyc/irbuild/specialize.py b/mypyc/irbuild/specialize.py index 7c5958457886..f652449f5289 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -19,6 +19,7 @@ from mypy.nodes import ( ARG_NAMED, ARG_POS, + BytesExpr, CallExpr, DictExpr, Expression, @@ -89,6 +90,11 @@ dict_values_op, ) from mypyc.primitives.list_ops import new_list_set_item_op +from mypyc.primitives.str_ops import ( + str_encode_ascii_strict, + str_encode_latin1_strict, + str_encode_utf8_strict, +) from mypyc.primitives.tuple_ops import new_tuple_set_item_op # Specializers are attempted before compiling the arguments to the @@ -682,6 +688,58 @@ def translate_fstring(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Va return None +@specialize_function("encode", str_rprimitive) +def str_encode_fast_path(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Value | None: + """Specialize common cases of str.encode for most used encodings and strict errors.""" + + if not isinstance(callee, MemberExpr): + return None + + # We can only specialize if we have string literals as args + if len(expr.arg_kinds) > 0 and not isinstance(expr.args[0], StrExpr): + return None + if len(expr.arg_kinds) > 1 and not isinstance(expr.args[1], StrExpr): + return None + + encoding = "utf8" + errors = "strict" + if len(expr.arg_kinds) > 0 and isinstance(expr.args[0], StrExpr): + if expr.arg_kinds[0] == ARG_NAMED: + if expr.arg_names[0] == "encoding": + encoding = expr.args[0].value + elif expr.arg_names[0] == "errors": + errors = expr.args[0].value + elif expr.arg_kinds[0] == ARG_POS: + encoding = expr.args[0].value + else: + return None + if len(expr.arg_kinds) > 1 and isinstance(expr.args[1], StrExpr): + if expr.arg_kinds[1] == ARG_NAMED: + if expr.arg_names[1] == "encoding": + encoding = expr.args[1].value + elif expr.arg_names[1] == "errors": + errors = expr.args[1].value + elif expr.arg_kinds[1] == ARG_POS: + errors = expr.args[1].value + else: + return None + + if errors != "strict": + # We can only specialize strict errors + return None + + encoding = encoding.lower().replace("-", "").replace("_", "") # normalize + # Specialized encodings and their accepted aliases + if encoding in ["u8", "utf", "utf8", "cp65001"]: + return builder.call_c(str_encode_utf8_strict, [builder.accept(callee.expr)], expr.line) + elif encoding in ["646", "ascii", "usascii"]: + return builder.call_c(str_encode_ascii_strict, [builder.accept(callee.expr)], expr.line) + elif encoding in ["iso88591", "8859", "cp819", "latin", "latin1", "l1"]: + return builder.call_c(str_encode_latin1_strict, [builder.accept(callee.expr)], expr.line) + + return None + + @specialize_function("mypy_extensions.i64") def translate_i64(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Value | None: if len(expr.args) != 1 or expr.arg_kinds[0] != ARG_POS: @@ -820,3 +878,13 @@ def translate_float(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Valu # No-op float conversion. return builder.accept(arg) return None + + +@specialize_function("builtins.ord") +def translate_ord(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Value | None: + if len(expr.args) != 1 or expr.arg_kinds[0] != ARG_POS: + return None + arg = expr.args[0] + if isinstance(arg, (StrExpr, BytesExpr)) and len(arg.value) == 1: + return Integer(ord(arg.value)) + return None diff --git a/mypyc/irbuild/statement.py b/mypyc/irbuild/statement.py index 4d828b1b9d82..bd4acccf077a 100644 --- a/mypyc/irbuild/statement.py +++ b/mypyc/irbuild/statement.py @@ -58,6 +58,7 @@ LoadLiteral, LoadStatic, MethodCall, + PrimitiveDescription, RaiseStandardError, Register, Return, @@ -347,10 +348,10 @@ def transform_import_from(builder: IRBuilder, node: ImportFrom) -> None: return module_state = builder.graph[builder.module_name] - if module_state.ancestors is not None and module_state.ancestors: - module_package = module_state.ancestors[0] - elif builder.module_path.endswith("__init__.py"): + if builder.module_path.endswith("__init__.py"): module_package = builder.module_name + elif module_state.ancestors is not None and module_state.ancestors: + module_package = module_state.ancestors[0] else: module_package = "" @@ -757,7 +758,7 @@ def transform_with( value = builder.add(MethodCall(mgr_v, f"__{al}enter__", args=[], line=line)) exit_ = None else: - typ = builder.call_c(type_op, [mgr_v], line) + typ = builder.primitive_op(type_op, [mgr_v], line) exit_ = builder.maybe_spill(builder.py_get_attr(typ, f"__{al}exit__", line)) value = builder.py_call(builder.py_get_attr(typ, f"__{al}enter__", line), [mgr_v], line) @@ -876,7 +877,7 @@ def transform_del_item(builder: IRBuilder, target: AssignmentTarget, line: int) line, ) key = builder.load_str(target.attr) - builder.call_c(py_delattr_op, [target.obj, key], line) + builder.primitive_op(py_delattr_op, [target.obj, key], line) elif isinstance(target, AssignmentTargetRegister): # Delete a local by assigning an error value to it, which will # prompt the insertion of uninit checks. @@ -924,7 +925,10 @@ def emit_yield_from_or_await( received_reg = Register(object_rprimitive) get_op = coro_op if is_await else iter_op - iter_val = builder.call_c(get_op, [val], line) + if isinstance(get_op, PrimitiveDescription): + iter_val = builder.primitive_op(get_op, [val], line) + else: + iter_val = builder.call_c(get_op, [val], line) iter_reg = builder.maybe_spill_assignable(iter_val) diff --git a/mypyc/irbuild/util.py b/mypyc/irbuild/util.py index ed01a59d1214..e27e509ad7fa 100644 --- a/mypyc/irbuild/util.py +++ b/mypyc/irbuild/util.py @@ -27,10 +27,16 @@ UnaryExpr, Var, ) +from mypy.semanal import refers_to_fullname +from mypy.types import FINAL_DECORATOR_NAMES DATACLASS_DECORATORS = {"dataclasses.dataclass", "attr.s", "attr.attrs"} +def is_final_decorator(d: Expression) -> bool: + return refers_to_fullname(d, FINAL_DECORATOR_NAMES) + + def is_trait_decorator(d: Expression) -> bool: return isinstance(d, RefExpr) and d.fullname == "mypy_extensions.trait" @@ -119,7 +125,10 @@ def get_mypyc_attrs(stmt: ClassDef | Decorator) -> dict[str, Any]: def is_extension_class(cdef: ClassDef) -> bool: if any( - not is_trait_decorator(d) and not is_dataclass_decorator(d) and not get_mypyc_attr_call(d) + not is_trait_decorator(d) + and not is_dataclass_decorator(d) + and not get_mypyc_attr_call(d) + and not is_final_decorator(d) for d in cdef.decorators ): return False diff --git a/mypyc/lib-rt/CPy.h b/mypyc/lib-rt/CPy.h index 833b1bd2e76a..d3637cde49ff 100644 --- a/mypyc/lib-rt/CPy.h +++ b/mypyc/lib-rt/CPy.h @@ -730,6 +730,7 @@ bool CPyStr_IsTrue(PyObject *obj); Py_ssize_t CPyStr_Size_size_t(PyObject *str); PyObject *CPy_Decode(PyObject *obj, PyObject *encoding, PyObject *errors); PyObject *CPy_Encode(PyObject *obj, PyObject *encoding, PyObject *errors); +CPyTagged CPyStr_Ord(PyObject *obj); // Bytes operations @@ -740,6 +741,7 @@ PyObject *CPyBytes_GetSlice(PyObject *obj, CPyTagged start, CPyTagged end); CPyTagged CPyBytes_GetItem(PyObject *o, CPyTagged index); PyObject *CPyBytes_Concat(PyObject *a, PyObject *b); PyObject *CPyBytes_Join(PyObject *sep, PyObject *iter); +CPyTagged CPyBytes_Ord(PyObject *obj); int CPyBytes_Compare(PyObject *left, PyObject *right); diff --git a/mypyc/lib-rt/bytes_ops.c b/mypyc/lib-rt/bytes_ops.c index 4da62be11571..5ddf3528211f 100644 --- a/mypyc/lib-rt/bytes_ops.c +++ b/mypyc/lib-rt/bytes_ops.c @@ -99,7 +99,7 @@ PyObject *CPyBytes_GetSlice(PyObject *obj, CPyTagged start, CPyTagged end) { // (mostly commonly, for bytearrays) PyObject *CPyBytes_Join(PyObject *sep, PyObject *iter) { if (PyBytes_CheckExact(sep)) { - return _PyBytes_Join(sep, iter); + return PyBytes_Join(sep, iter); } else { _Py_IDENTIFIER(join); return _PyObject_CallMethodIdOneArg(sep, &PyId_join, iter); @@ -141,3 +141,20 @@ PyObject *CPyBytes_Build(Py_ssize_t len, ...) { return (PyObject *)ret; } + + +CPyTagged CPyBytes_Ord(PyObject *obj) { + if (PyBytes_Check(obj)) { + Py_ssize_t s = PyBytes_GET_SIZE(obj); + if (s == 1) { + return (unsigned char)(PyBytes_AS_STRING(obj)[0]) << 1; + } + } else if (PyByteArray_Check(obj)) { + Py_ssize_t s = PyByteArray_GET_SIZE(obj); + if (s == 1) { + return (unsigned char)(PyByteArray_AS_STRING(obj)[0]) << 1; + } + } + PyErr_SetString(PyExc_TypeError, "ord() expects a character"); + return CPY_INT_TAG; +} diff --git a/mypyc/lib-rt/getargs.c b/mypyc/lib-rt/getargs.c index 1bc2f5b02ba8..4f2f8aa0be83 100644 --- a/mypyc/lib-rt/getargs.c +++ b/mypyc/lib-rt/getargs.c @@ -247,14 +247,14 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format, #endif if (!skip) { if (i < nargs && i < max) { - current_arg = PyTuple_GET_ITEM(args, i); + current_arg = Py_NewRef(PyTuple_GET_ITEM(args, i)); } else if (nkwargs && i >= pos) { - current_arg = _PyDict_GetItemStringWithError(kwargs, kwlist[i]); - if (current_arg) { + int res = PyDict_GetItemStringRef(kwargs, kwlist[i], ¤t_arg); + if (res == 1) { --nkwargs; } - else if (PyErr_Occurred()) { + else if (res == -1) { return 0; } } @@ -265,6 +265,7 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format, if (current_arg) { PyObject **p = va_arg(*p_va, PyObject **); *p = current_arg; + Py_DECREF(current_arg); format++; continue; } @@ -370,8 +371,11 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format, Py_ssize_t j; /* make sure there are no arguments given by name and position */ for (i = pos; i < bound_pos_args && i < len; i++) { - current_arg = _PyDict_GetItemStringWithError(kwargs, kwlist[i]); - if (unlikely(current_arg != NULL)) { + int res = PyDict_GetItemStringRef(kwargs, kwlist[i], ¤t_arg); + if (res == 1) { + Py_DECREF(current_arg); + } + else if (unlikely(res == 0)) { /* arg present in tuple and in dict */ PyErr_Format(PyExc_TypeError, "argument for %.200s%s given by name ('%s') " @@ -381,7 +385,7 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format, kwlist[i], i+1); goto latefail; } - else if (unlikely(PyErr_Occurred() != NULL)) { + else if (unlikely(res == -1)) { goto latefail; } } diff --git a/mypyc/lib-rt/getargsfast.c b/mypyc/lib-rt/getargsfast.c index 62d0dfed0a6d..e5667e22efe3 100644 --- a/mypyc/lib-rt/getargsfast.c +++ b/mypyc/lib-rt/getargsfast.c @@ -271,16 +271,9 @@ find_keyword(PyObject *kwnames, PyObject *const *kwstack, PyObject *key) for (i = 0; i < nkwargs; i++) { PyObject *kwname = PyTuple_GET_ITEM(kwnames, i); assert(PyUnicode_Check(kwname)); -#if CPY_3_13_FEATURES - if (_PyUnicode_Equal(kwname, key)) { + if (PyUnicode_Equal(kwname, key)) { return kwstack[i]; } -#else - if (_PyUnicode_EQ(kwname, key)) { - return kwstack[i]; - } -#endif - } return NULL; } diff --git a/mypyc/lib-rt/misc_ops.c b/mypyc/lib-rt/misc_ops.c index 1572c4496e30..d3e8e69ed19b 100644 --- a/mypyc/lib-rt/misc_ops.c +++ b/mypyc/lib-rt/misc_ops.c @@ -563,7 +563,7 @@ int CPyStatics_Initialize(PyObject **statics, while (num-- > 0) { size_t len; data = parse_int(data, &len); - PyObject *obj = PyUnicode_FromStringAndSize(data, len); + PyObject *obj = PyUnicode_DecodeUTF8(data, len, "surrogatepass"); if (obj == NULL) { return -1; } diff --git a/mypyc/lib-rt/pythoncapi_compat.h b/mypyc/lib-rt/pythoncapi_compat.h index 1b59f93de7ec..acaadf34bf2e 100644 --- a/mypyc/lib-rt/pythoncapi_compat.h +++ b/mypyc/lib-rt/pythoncapi_compat.h @@ -45,6 +45,13 @@ extern "C" { # define _PyObject_CAST(op) _Py_CAST(PyObject*, op) #endif +#ifndef Py_BUILD_ASSERT +# define Py_BUILD_ASSERT(cond) \ + do { \ + (void)sizeof(char [1 - 2 * !(cond)]); \ + } while(0) +#endif + // bpo-42262 added Py_NewRef() to Python 3.10.0a3 #if PY_VERSION_HEX < 0x030A00A3 && !defined(Py_NewRef) @@ -1338,9 +1345,169 @@ PyDict_SetDefaultRef(PyObject *d, PyObject *key, PyObject *default_value, } #endif +#if PY_VERSION_HEX < 0x030D00B3 +# define Py_BEGIN_CRITICAL_SECTION(op) { +# define Py_END_CRITICAL_SECTION() } +# define Py_BEGIN_CRITICAL_SECTION2(a, b) { +# define Py_END_CRITICAL_SECTION2() } +#endif + +#if PY_VERSION_HEX < 0x030E0000 && PY_VERSION_HEX >= 0x03060000 && !defined(PYPY_VERSION) +typedef struct PyUnicodeWriter PyUnicodeWriter; + +static inline void PyUnicodeWriter_Discard(PyUnicodeWriter *writer) +{ + _PyUnicodeWriter_Dealloc((_PyUnicodeWriter*)writer); + PyMem_Free(writer); +} + +static inline PyUnicodeWriter* PyUnicodeWriter_Create(Py_ssize_t length) +{ + if (length < 0) { + PyErr_SetString(PyExc_ValueError, + "length must be positive"); + return NULL; + } + + const size_t size = sizeof(_PyUnicodeWriter); + PyUnicodeWriter *pub_writer = (PyUnicodeWriter *)PyMem_Malloc(size); + if (pub_writer == _Py_NULL) { + PyErr_NoMemory(); + return _Py_NULL; + } + _PyUnicodeWriter *writer = (_PyUnicodeWriter *)pub_writer; + + _PyUnicodeWriter_Init(writer); + if (_PyUnicodeWriter_Prepare(writer, length, 127) < 0) { + PyUnicodeWriter_Discard(pub_writer); + return NULL; + } + writer->overallocate = 1; + return pub_writer; +} + +static inline PyObject* PyUnicodeWriter_Finish(PyUnicodeWriter *writer) +{ + PyObject *str = _PyUnicodeWriter_Finish((_PyUnicodeWriter*)writer); + assert(((_PyUnicodeWriter*)writer)->buffer == NULL); + PyMem_Free(writer); + return str; +} + +static inline int +PyUnicodeWriter_WriteChar(PyUnicodeWriter *writer, Py_UCS4 ch) +{ + if (ch > 0x10ffff) { + PyErr_SetString(PyExc_ValueError, + "character must be in range(0x110000)"); + return -1; + } + + return _PyUnicodeWriter_WriteChar((_PyUnicodeWriter*)writer, ch); +} + +static inline int +PyUnicodeWriter_WriteStr(PyUnicodeWriter *writer, PyObject *obj) +{ + PyObject *str = PyObject_Str(obj); + if (str == NULL) { + return -1; + } + + int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str); + Py_DECREF(str); + return res; +} + +static inline int +PyUnicodeWriter_WriteRepr(PyUnicodeWriter *writer, PyObject *obj) +{ + PyObject *str = PyObject_Repr(obj); + if (str == NULL) { + return -1; + } + + int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str); + Py_DECREF(str); + return res; +} + +static inline int +PyUnicodeWriter_WriteUTF8(PyUnicodeWriter *writer, + const char *str, Py_ssize_t size) +{ + if (size < 0) { + size = (Py_ssize_t)strlen(str); + } + + PyObject *str_obj = PyUnicode_FromStringAndSize(str, size); + if (str_obj == _Py_NULL) { + return -1; + } + + int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str_obj); + Py_DECREF(str_obj); + return res; +} + +static inline int +PyUnicodeWriter_WriteWideChar(PyUnicodeWriter *writer, + const wchar_t *str, Py_ssize_t size) +{ + if (size < 0) { + size = (Py_ssize_t)wcslen(str); + } + + PyObject *str_obj = PyUnicode_FromWideChar(str, size); + if (str_obj == _Py_NULL) { + return -1; + } + + int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str_obj); + Py_DECREF(str_obj); + return res; +} + +static inline int +PyUnicodeWriter_WriteSubstring(PyUnicodeWriter *writer, PyObject *str, + Py_ssize_t start, Py_ssize_t end) +{ + if (!PyUnicode_Check(str)) { + PyErr_Format(PyExc_TypeError, "expect str, not %T", str); + return -1; + } + if (start < 0 || start > end) { + PyErr_Format(PyExc_ValueError, "invalid start argument"); + return -1; + } + if (end > PyUnicode_GET_LENGTH(str)) { + PyErr_Format(PyExc_ValueError, "invalid end argument"); + return -1; + } + + return _PyUnicodeWriter_WriteSubstring((_PyUnicodeWriter*)writer, str, + start, end); +} + +static inline int +PyUnicodeWriter_Format(PyUnicodeWriter *writer, const char *format, ...) +{ + va_list vargs; + va_start(vargs, format); + PyObject *str = PyUnicode_FromFormatV(format, vargs); + va_end(vargs); + if (str == _Py_NULL) { + return -1; + } + + int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str); + Py_DECREF(str); + return res; +} +#endif // PY_VERSION_HEX < 0x030E0000 -// gh-116560 added PyLong_GetSign() to Python 3.14a4 -#if PY_VERSION_HEX < 0x030E00A1 +// gh-116560 added PyLong_GetSign() to Python 3.14.0a0 +#if PY_VERSION_HEX < 0x030E00A0 static inline int PyLong_GetSign(PyObject *obj, int *sign) { if (!PyLong_Check(obj)) { @@ -1354,6 +1521,175 @@ static inline int PyLong_GetSign(PyObject *obj, int *sign) #endif +// gh-124502 added PyUnicode_Equal() to Python 3.14.0a0 +#if PY_VERSION_HEX < 0x030E00A0 +static inline int PyUnicode_Equal(PyObject *str1, PyObject *str2) +{ + if (!PyUnicode_Check(str1)) { + PyErr_Format(PyExc_TypeError, "first argument must be str, not %s", + Py_TYPE(str1)->tp_name); + return -1; + } + if (!PyUnicode_Check(str2)) { + PyErr_Format(PyExc_TypeError, "second argument must be str, not %s", + Py_TYPE(str2)->tp_name); + return -1; + } + +#if PY_VERSION_HEX >= 0x030d0000 && !defined(PYPY_VERSION) + PyAPI_FUNC(int) _PyUnicode_Equal(PyObject *str1, PyObject *str2); + + return _PyUnicode_Equal(str1, str2); +#elif PY_VERSION_HEX >= 0x03060000 && !defined(PYPY_VERSION) + return _PyUnicode_EQ(str1, str2); +#elif PY_VERSION_HEX >= 0x03090000 && defined(PYPY_VERSION) + return _PyUnicode_EQ(str1, str2); +#else + return (PyUnicode_Compare(str1, str2) == 0); +#endif +} +#endif + + +// gh-121645 added PyBytes_Join() to Python 3.14.0a0 +#if PY_VERSION_HEX < 0x030E00A0 +static inline PyObject* PyBytes_Join(PyObject *sep, PyObject *iterable) +{ + return _PyBytes_Join(sep, iterable); +} +#endif + + +#if PY_VERSION_HEX < 0x030E00A0 +static inline Py_hash_t Py_HashBuffer(const void *ptr, Py_ssize_t len) +{ +#if PY_VERSION_HEX >= 0x03000000 && !defined(PYPY_VERSION) + PyAPI_FUNC(Py_hash_t) _Py_HashBytes(const void *src, Py_ssize_t len); + + return _Py_HashBytes(ptr, len); +#else + Py_hash_t hash; + PyObject *bytes = PyBytes_FromStringAndSize((const char*)ptr, len); + if (bytes == NULL) { + return -1; + } + hash = PyObject_Hash(bytes); + Py_DECREF(bytes); + return hash; +#endif +} +#endif + + +#if PY_VERSION_HEX < 0x030E00A0 +static inline int PyIter_NextItem(PyObject *iter, PyObject **item) +{ + iternextfunc tp_iternext; + + assert(iter != NULL); + assert(item != NULL); + + tp_iternext = Py_TYPE(iter)->tp_iternext; + if (tp_iternext == NULL) { + *item = NULL; + PyErr_Format(PyExc_TypeError, "expected an iterator, got '%s'", + Py_TYPE(iter)->tp_name); + return -1; + } + + if ((*item = tp_iternext(iter))) { + return 1; + } + if (!PyErr_Occurred()) { + return 0; + } + if (PyErr_ExceptionMatches(PyExc_StopIteration)) { + PyErr_Clear(); + return 0; + } + return -1; +} +#endif + + +#if PY_VERSION_HEX < 0x030E00A0 +static inline PyObject* PyLong_FromInt32(int32_t value) +{ + Py_BUILD_ASSERT(sizeof(long) >= 4); + return PyLong_FromLong(value); +} + +static inline PyObject* PyLong_FromInt64(int64_t value) +{ + Py_BUILD_ASSERT(sizeof(long long) >= 8); + return PyLong_FromLongLong(value); +} + +static inline PyObject* PyLong_FromUInt32(uint32_t value) +{ + Py_BUILD_ASSERT(sizeof(unsigned long) >= 4); + return PyLong_FromUnsignedLong(value); +} + +static inline PyObject* PyLong_FromUInt64(uint64_t value) +{ + Py_BUILD_ASSERT(sizeof(unsigned long long) >= 8); + return PyLong_FromUnsignedLongLong(value); +} + +static inline int PyLong_AsInt32(PyObject *obj, int32_t *pvalue) +{ + Py_BUILD_ASSERT(sizeof(int) == 4); + int value = PyLong_AsInt(obj); + if (value == -1 && PyErr_Occurred()) { + return -1; + } + *pvalue = (int32_t)value; + return 0; +} + +static inline int PyLong_AsInt64(PyObject *obj, int64_t *pvalue) +{ + Py_BUILD_ASSERT(sizeof(long long) == 8); + long long value = PyLong_AsLongLong(obj); + if (value == -1 && PyErr_Occurred()) { + return -1; + } + *pvalue = (int64_t)value; + return 0; +} + +static inline int PyLong_AsUInt32(PyObject *obj, uint32_t *pvalue) +{ + Py_BUILD_ASSERT(sizeof(long) >= 4); + unsigned long value = PyLong_AsUnsignedLong(obj); + if (value == (unsigned long)-1 && PyErr_Occurred()) { + return -1; + } +#if SIZEOF_LONG > 4 + if ((unsigned long)UINT32_MAX < value) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C uint32_t"); + return -1; + } +#endif + *pvalue = (uint32_t)value; + return 0; +} + +static inline int PyLong_AsUInt64(PyObject *obj, uint64_t *pvalue) +{ + Py_BUILD_ASSERT(sizeof(long long) == 8); + unsigned long long value = PyLong_AsUnsignedLongLong(obj); + if (value == (unsigned long long)-1 && PyErr_Occurred()) { + return -1; + } + *pvalue = (uint64_t)value; + return 0; +} +#endif + + #ifdef __cplusplus } #endif diff --git a/mypyc/lib-rt/pythonsupport.h b/mypyc/lib-rt/pythonsupport.h index bf7e5203758d..61929f512608 100644 --- a/mypyc/lib-rt/pythonsupport.h +++ b/mypyc/lib-rt/pythonsupport.h @@ -17,13 +17,10 @@ #ifndef Py_BUILD_CORE #define Py_BUILD_CORE #endif -#include "internal/pycore_bytesobject.h" // _PyBytes_Join -#include "internal/pycore_call.h" // _PyObject_CallMethodIdNoArgs, _PyObject_CallMethodIdObjArgs, _PyObject_CallMethodIdOneArg +#include "internal/pycore_call.h" // _PyObject_CallMethodIdNoArgs, _PyObject_CallMethodIdOneArg #include "internal/pycore_genobject.h" // _PyGen_FetchStopIterationValue -#include "internal/pycore_object.h" // _PyType_CalculateMetaclass #include "internal/pycore_pyerrors.h" // _PyErr_FormatFromCause, _PyErr_SetKeyError #include "internal/pycore_setobject.h" // _PySet_Update -#include "internal/pycore_unicodeobject.h" // _PyUnicode_EQ, _PyUnicode_FastCopyCharacters #endif #if CPY_3_12_FEATURES @@ -405,45 +402,15 @@ _CPyObject_HasAttrId(PyObject *v, _Py_Identifier *name) { PyObject_CallMethodObjArgs((self), (name), (arg), NULL) #endif -#if CPY_3_13_FEATURES - -// These are copied from genobject.c in Python 3.13 - -/* Returns a borrowed reference */ -static inline PyCodeObject * -_PyGen_GetCode(PyGenObject *gen) { - _PyInterpreterFrame *frame = (_PyInterpreterFrame *)(gen->gi_iframe); - return _PyFrame_GetCode(frame); -} - -static int -gen_is_coroutine(PyObject *o) -{ - if (PyGen_CheckExact(o)) { - PyCodeObject *code = _PyGen_GetCode((PyGenObject*)o); - if (code->co_flags & CO_ITERABLE_COROUTINE) { - return 1; - } - } - return 0; -} - -#elif CPY_3_12_FEATURES +#if CPY_3_12_FEATURES // These are copied from genobject.c in Python 3.12 -/* Returns a borrowed reference */ -static inline PyCodeObject * -_PyGen_GetCode(PyGenObject *gen) { - _PyInterpreterFrame *frame = (_PyInterpreterFrame *)(gen->gi_iframe); - return frame->f_code; -} - static int gen_is_coroutine(PyObject *o) { if (PyGen_CheckExact(o)) { - PyCodeObject *code = _PyGen_GetCode((PyGenObject*)o); + PyCodeObject *code = PyGen_GetCode((PyGenObject*)o); if (code->co_flags & CO_ITERABLE_COROUTINE) { return 1; } diff --git a/mypyc/lib-rt/setup.py b/mypyc/lib-rt/setup.py index 66b130581cb3..1faacc8fc136 100644 --- a/mypyc/lib-rt/setup.py +++ b/mypyc/lib-rt/setup.py @@ -21,7 +21,7 @@ compile_args = ["--std=c++11"] -class build_ext_custom(build_ext): +class build_ext_custom(build_ext): # noqa: N801 def get_library_names(self): return ["gtest"] diff --git a/mypyc/lib-rt/str_ops.c b/mypyc/lib-rt/str_ops.c index 4ba181bcce85..68026037502d 100644 --- a/mypyc/lib-rt/str_ops.c +++ b/mypyc/lib-rt/str_ops.c @@ -243,3 +243,15 @@ PyObject *CPy_Encode(PyObject *obj, PyObject *encoding, PyObject *errors) { return NULL; } } + + +CPyTagged CPyStr_Ord(PyObject *obj) { + Py_ssize_t s = PyUnicode_GET_LENGTH(obj); + if (s == 1) { + int kind = PyUnicode_KIND(obj); + return PyUnicode_READ(kind, PyUnicode_DATA(obj), 0) << 1; + } + PyErr_Format( + PyExc_TypeError, "ord() expected a character, but a string of length %zd found", s); + return CPY_INT_TAG; +} diff --git a/mypyc/namegen.py b/mypyc/namegen.py index 675dae9001c7..ce84fde143d1 100644 --- a/mypyc/namegen.py +++ b/mypyc/namegen.py @@ -100,10 +100,9 @@ def make_module_translation_map(names: list[str]) -> dict[str, str]: for name in names: for suffix in candidate_suffixes(name): if num_instances[suffix] == 1: - result[name] = suffix break - else: - assert False, names + # Takes the last suffix if none are unique + result[name] = suffix return result diff --git a/mypyc/options.py b/mypyc/options.py index 5f0cf12aeefe..24e68163bb11 100644 --- a/mypyc/options.py +++ b/mypyc/options.py @@ -14,6 +14,7 @@ def __init__( include_runtime_files: bool | None = None, capi_version: tuple[int, int] | None = None, python_version: tuple[int, int] | None = None, + strict_dunder_typing: bool = False, ) -> None: self.strip_asserts = strip_asserts self.multi_file = multi_file @@ -30,3 +31,10 @@ def __init__( # features are used. self.capi_version = capi_version or sys.version_info[:2] self.python_version = python_version + # Make possible to inline dunder methods in the generated code. + # Typically, the convention is the dunder methods can return `NotImplemented` + # even when its return type is just `bool`. + # By enabling this option, this convention is no longer valid and the dunder + # will assume the return type of the method strictly, which can lead to + # more optimization opportunities. + self.strict_dunders_typing = strict_dunder_typing diff --git a/mypyc/primitives/bytes_ops.py b/mypyc/primitives/bytes_ops.py index d7a7f3e2f59b..1afd196cff84 100644 --- a/mypyc/primitives/bytes_ops.py +++ b/mypyc/primitives/bytes_ops.py @@ -99,3 +99,11 @@ error_kind=ERR_MAGIC, var_arg_type=bytes_rprimitive, ) + +function_op( + name="builtins.ord", + arg_types=[bytes_rprimitive], + return_type=int_rprimitive, + c_function_name="CPyBytes_Ord", + error_kind=ERR_MAGIC, +) diff --git a/mypyc/primitives/int_ops.py b/mypyc/primitives/int_ops.py index 2eff233403f4..657578d20046 100644 --- a/mypyc/primitives/int_ops.py +++ b/mypyc/primitives/int_ops.py @@ -31,14 +31,7 @@ str_rprimitive, void_rtype, ) -from mypyc.primitives.registry import ( - CFunctionDescription, - binary_op, - custom_op, - function_op, - load_address_op, - unary_op, -) +from mypyc.primitives.registry import binary_op, custom_op, function_op, load_address_op, unary_op # Constructors for builtins.int and native int types have the same behavior. In # interpreted mode, native int types are just aliases to 'int'. @@ -176,7 +169,7 @@ def int_binary_op( int_binary_op("<<=", "CPyTagged_Lshift", error_kind=ERR_MAGIC) -def int_unary_op(name: str, c_function_name: str) -> CFunctionDescription: +def int_unary_op(name: str, c_function_name: str) -> PrimitiveDescription: return unary_op( name=name, arg_type=int_rprimitive, diff --git a/mypyc/primitives/registry.py b/mypyc/primitives/registry.py index 5190b01adf4a..5e7ecb70f55d 100644 --- a/mypyc/primitives/registry.py +++ b/mypyc/primitives/registry.py @@ -70,17 +70,17 @@ class LoadAddressDescription(NamedTuple): src: str # name of the target to load -# CallC op for method call(such as 'str.join') -method_call_ops: dict[str, list[CFunctionDescription]] = {} +# Primitive ops for method call (such as 'str.join') +method_call_ops: dict[str, list[PrimitiveDescription]] = {} -# CallC op for top level function call(such as 'builtins.list') -function_ops: dict[str, list[CFunctionDescription]] = {} +# Primitive ops for top level function call (such as 'builtins.list') +function_ops: dict[str, list[PrimitiveDescription]] = {} -# CallC op for binary ops +# Primitive ops for binary operations binary_ops: dict[str, list[PrimitiveDescription]] = {} -# CallC op for unary ops -unary_ops: dict[str, list[CFunctionDescription]] = {} +# Primitive ops for unary ops +unary_ops: dict[str, list[PrimitiveDescription]] = {} builtin_names: dict[str, tuple[RType, str]] = {} @@ -99,7 +99,7 @@ def method_op( is_borrowed: bool = False, priority: int = 1, is_pure: bool = False, -) -> CFunctionDescription: +) -> PrimitiveDescription: """Define a c function call op that replaces a method call. This will be automatically generated by matching against the AST. @@ -129,7 +129,7 @@ def method_op( if extra_int_constants is None: extra_int_constants = [] ops = method_call_ops.setdefault(name, []) - desc = CFunctionDescription( + desc = PrimitiveDescription( name, arg_types, return_type, @@ -161,8 +161,8 @@ def function_op( steals: StealsDescription = False, is_borrowed: bool = False, priority: int = 1, -) -> CFunctionDescription: - """Define a c function call op that replaces a function call. +) -> PrimitiveDescription: + """Define a C function call op that replaces a function call. This will be automatically generated by matching against the AST. @@ -175,19 +175,19 @@ def function_op( if extra_int_constants is None: extra_int_constants = [] ops = function_ops.setdefault(name, []) - desc = CFunctionDescription( + desc = PrimitiveDescription( name, arg_types, return_type, - var_arg_type, - truncated_type, - c_function_name, - error_kind, - steals, - is_borrowed, - ordering, - extra_int_constants, - priority, + var_arg_type=var_arg_type, + truncated_type=truncated_type, + c_function_name=c_function_name, + error_kind=error_kind, + steals=steals, + is_borrowed=is_borrowed, + ordering=ordering, + extra_int_constants=extra_int_constants, + priority=priority, is_pure=False, ) ops.append(desc) @@ -327,8 +327,8 @@ def unary_op( is_borrowed: bool = False, priority: int = 1, is_pure: bool = False, -) -> CFunctionDescription: - """Define a c function call op for an unary operation. +) -> PrimitiveDescription: + """Define a primitive op for an unary operation. This will be automatically generated by matching against the AST. @@ -338,19 +338,19 @@ def unary_op( if extra_int_constants is None: extra_int_constants = [] ops = unary_ops.setdefault(name, []) - desc = CFunctionDescription( + desc = PrimitiveDescription( name, [arg_type], return_type, - None, - truncated_type, - c_function_name, - error_kind, - steals, - is_borrowed, - ordering, - extra_int_constants, - priority, + var_arg_type=None, + truncated_type=truncated_type, + c_function_name=c_function_name, + error_kind=error_kind, + steals=steals, + is_borrowed=is_borrowed, + ordering=ordering, + extra_int_constants=extra_int_constants, + priority=priority, is_pure=is_pure, ) ops.append(desc) diff --git a/mypyc/primitives/str_ops.py b/mypyc/primitives/str_ops.py index 2ff1fbdb4b3e..0accffd86a17 100644 --- a/mypyc/primitives/str_ops.py +++ b/mypyc/primitives/str_ops.py @@ -219,6 +219,30 @@ extra_int_constants=[(0, pointer_rprimitive)], ) +# str.encode(encoding) - utf8 strict specialization +str_encode_utf8_strict = custom_op( + arg_types=[str_rprimitive], + return_type=bytes_rprimitive, + c_function_name="PyUnicode_AsUTF8String", + error_kind=ERR_MAGIC, +) + +# str.encode(encoding) - ascii strict specialization +str_encode_ascii_strict = custom_op( + arg_types=[str_rprimitive], + return_type=bytes_rprimitive, + c_function_name="PyUnicode_AsASCIIString", + error_kind=ERR_MAGIC, +) + +# str.encode(encoding) - latin1 strict specialization +str_encode_latin1_strict = custom_op( + arg_types=[str_rprimitive], + return_type=bytes_rprimitive, + c_function_name="PyUnicode_AsLatin1String", + error_kind=ERR_MAGIC, +) + # str.encode(encoding, errors) method_op( name="encode", @@ -227,3 +251,11 @@ c_function_name="CPy_Encode", error_kind=ERR_MAGIC, ) + +function_op( + name="builtins.ord", + arg_types=[str_rprimitive], + return_type=int_rprimitive, + c_function_name="CPyStr_Ord", + error_kind=ERR_MAGIC, +) diff --git a/mypyc/test-data/fixtures/ir.py b/mypyc/test-data/fixtures/ir.py index ac95ffe2c047..be66307286fc 100644 --- a/mypyc/test-data/fixtures/ir.py +++ b/mypyc/test-data/fixtures/ir.py @@ -110,7 +110,7 @@ def upper(self) -> str: ... def startswith(self, x: str, start: int=..., end: int=...) -> bool: ... def endswith(self, x: str, start: int=..., end: int=...) -> bool: ... def replace(self, old: str, new: str, maxcount: int=...) -> str: ... - def encode(self, x: str=..., y: str=...) -> bytes: ... + def encode(self, encoding: str=..., errors: str=...) -> bytes: ... class float: def __init__(self, x: object) -> None: pass diff --git a/mypyc/test-data/fixtures/testutil.py b/mypyc/test-data/fixtures/testutil.py index f210faf71109..36ec41c8f38b 100644 --- a/mypyc/test-data/fixtures/testutil.py +++ b/mypyc/test-data/fixtures/testutil.py @@ -45,7 +45,7 @@ def assertRaises(typ: type, msg: str = '') -> Iterator[None]: try: yield except Exception as e: - assert isinstance(e, typ), f"{e!r} is not a {typ.__name__}" + assert type(e) is typ, f"{e!r} is not a {typ.__name__}" assert msg in str(e), f'Message "{e}" does not match "{msg}"' else: assert False, f"Expected {typ.__name__} but got no exception" diff --git a/mypyc/test-data/irbuild-int.test b/mypyc/test-data/irbuild-int.test index b1a712103e70..9082cc0136d9 100644 --- a/mypyc/test-data/irbuild-int.test +++ b/mypyc/test-data/irbuild-int.test @@ -182,13 +182,31 @@ def int_to_int(n): L0: return n -[case testIntUnaryPlus] +[case testIntUnaryOps] +def unary_minus(n: int) -> int: + x = -n + return x def unary_plus(n: int) -> int: x = +n return x +def unary_invert(n: int) -> int: + x = ~n + return x [out] +def unary_minus(n): + n, r0, x :: int +L0: + r0 = CPyTagged_Negate(n) + x = r0 + return x def unary_plus(n): n, x :: int L0: x = n return x +def unary_invert(n): + n, r0, x :: int +L0: + r0 = CPyTagged_Invert(n) + x = r0 + return x diff --git a/mypyc/test-data/irbuild-statements.test b/mypyc/test-data/irbuild-statements.test index f9d3354b317c..825bc750f7a7 100644 --- a/mypyc/test-data/irbuild-statements.test +++ b/mypyc/test-data/irbuild-statements.test @@ -864,18 +864,16 @@ def g(x: Iterable[int]) -> None: [out] def f(a): a :: list - r0 :: short_int - i :: int - r1 :: short_int + r0, r1 :: short_int r2 :: native_int r3 :: short_int r4 :: bit + i :: int r5 :: object r6, x, r7 :: int r8, r9 :: short_int L0: r0 = 0 - i = 0 r1 = 0 L1: r2 = var_object_size a @@ -883,6 +881,7 @@ L1: r4 = int_lt r1, r3 if r4 goto L2 else goto L4 :: bool L2: + i = r0 r5 = CPyList_GetItemUnsafe(a, r1) r6 = unbox(int, r5) x = r6 @@ -890,7 +889,6 @@ L2: L3: r8 = r0 + 2 r0 = r8 - i = r8 r9 = r1 + 2 r1 = r9 goto L1 @@ -900,25 +898,23 @@ L5: def g(x): x :: object r0 :: short_int - i :: int r1, r2 :: object - r3, n :: int + i, r3, n :: int r4 :: short_int r5 :: bit L0: r0 = 0 - i = 0 r1 = PyObject_GetIter(x) L1: r2 = PyIter_Next(r1) if is_error(r2) goto L4 else goto L2 L2: + i = r0 r3 = unbox(int, r2) n = r3 L3: r4 = r0 + 2 r0 = r4 - i = r4 goto L1 L4: r5 = CPy_NoErrOccured() diff --git a/mypyc/test-data/irbuild-str.test b/mypyc/test-data/irbuild-str.test index 771dcc4c0e68..d17c66bba22f 100644 --- a/mypyc/test-data/irbuild-str.test +++ b/mypyc/test-data/irbuild-str.test @@ -293,20 +293,136 @@ L0: def f(s: str) -> None: s.encode() s.encode('utf-8') + s.encode('utf8', 'strict') + s.encode('latin1', errors='strict') + s.encode(encoding='ascii') + s.encode(errors='strict', encoding='latin-1') + s.encode('utf-8', 'backslashreplace') s.encode('ascii', 'backslashreplace') + encoding = 'utf8' + s.encode(encoding) + errors = 'strict' + s.encode('utf8', errors) + s.encode('utf8', errors=errors) + s.encode(errors=errors) + s.encode(encoding=encoding, errors=errors) + s.encode('latin2') + [out] def f(s): s :: str - r0 :: bytes - r1 :: str - r2 :: bytes - r3, r4 :: str - r5 :: bytes + r0, r1, r2, r3, r4, r5 :: bytes + r6, r7 :: str + r8 :: bytes + r9, r10 :: str + r11 :: bytes + r12, encoding :: str + r13 :: bytes + r14, errors, r15 :: str + r16 :: bytes + r17, r18 :: str + r19 :: object + r20 :: str + r21 :: tuple + r22 :: dict + r23 :: object + r24 :: str + r25 :: object + r26 :: str + r27 :: tuple + r28 :: dict + r29 :: object + r30 :: str + r31 :: object + r32, r33 :: str + r34 :: tuple + r35 :: dict + r36 :: object + r37 :: str + r38 :: bytes L0: - r0 = CPy_Encode(s, 0, 0) - r1 = 'utf-8' - r2 = CPy_Encode(s, r1, 0) - r3 = 'ascii' - r4 = 'backslashreplace' - r5 = CPy_Encode(s, r3, r4) + r0 = PyUnicode_AsUTF8String(s) + r1 = PyUnicode_AsUTF8String(s) + r2 = PyUnicode_AsUTF8String(s) + r3 = PyUnicode_AsLatin1String(s) + r4 = PyUnicode_AsASCIIString(s) + r5 = PyUnicode_AsLatin1String(s) + r6 = 'utf-8' + r7 = 'backslashreplace' + r8 = CPy_Encode(s, r6, r7) + r9 = 'ascii' + r10 = 'backslashreplace' + r11 = CPy_Encode(s, r9, r10) + r12 = 'utf8' + encoding = r12 + r13 = CPy_Encode(s, encoding, 0) + r14 = 'strict' + errors = r14 + r15 = 'utf8' + r16 = CPy_Encode(s, r15, errors) + r17 = 'utf8' + r18 = 'encode' + r19 = CPyObject_GetAttr(s, r18) + r20 = 'errors' + r21 = PyTuple_Pack(1, r17) + r22 = CPyDict_Build(1, r20, errors) + r23 = PyObject_Call(r19, r21, r22) + r24 = 'encode' + r25 = CPyObject_GetAttr(s, r24) + r26 = 'errors' + r27 = PyTuple_Pack(0) + r28 = CPyDict_Build(1, r26, errors) + r29 = PyObject_Call(r25, r27, r28) + r30 = 'encode' + r31 = CPyObject_GetAttr(s, r30) + r32 = 'encoding' + r33 = 'errors' + r34 = PyTuple_Pack(0) + r35 = CPyDict_Build(2, r32, encoding, r33, errors) + r36 = PyObject_Call(r31, r34, r35) + r37 = 'latin2' + r38 = CPy_Encode(s, r37, 0) return 1 + +[case testOrd] +def str_ord(x: str) -> int: + return ord(x) +def str_ord_literal() -> int: + return ord("a") +def bytes_ord(x: bytes) -> int: + return ord(x) +def bytes_ord_literal() -> int: + return ord(b"a") +def any_ord(x) -> int: + return ord(x) +[out] +def str_ord(x): + x :: str + r0 :: int +L0: + r0 = CPyStr_Ord(x) + return r0 +def str_ord_literal(): +L0: + return 194 +def bytes_ord(x): + x :: bytes + r0 :: int +L0: + r0 = CPyBytes_Ord(x) + return r0 +def bytes_ord_literal(): +L0: + return 194 +def any_ord(x): + x, r0 :: object + r1 :: str + r2, r3 :: object + r4 :: int +L0: + r0 = builtins :: module + r1 = 'ord' + r2 = CPyObject_GetAttr(r0, r1) + r3 = PyObject_CallFunctionObjArgs(r2, x, 0) + r4 = unbox(int, r3) + return r4 diff --git a/mypyc/test-data/run-bytes.test b/mypyc/test-data/run-bytes.test index aaf541194ac6..fa63c46a6798 100644 --- a/mypyc/test-data/run-bytes.test +++ b/mypyc/test-data/run-bytes.test @@ -111,6 +111,29 @@ def test_len() -> None: assert len(b) == 3 assert len(bytes()) == 0 +def test_ord() -> None: + assert ord(b'a') == ord('a') + assert ord(b'a' + bytes()) == ord('a') + assert ord(b'\x00') == 0 + assert ord(b'\x00' + bytes()) == 0 + assert ord(b'\xfe') == 254 + assert ord(b'\xfe' + bytes()) == 254 + + with assertRaises(TypeError): + ord(b'aa') + with assertRaises(TypeError): + ord(b'') + +def test_ord_bytesarray() -> None: + assert ord(bytearray(b'a')) == ord('a') + assert ord(bytearray(b'\x00')) == 0 + assert ord(bytearray(b'\xfe')) == 254 + + with assertRaises(TypeError): + ord(bytearray(b'aa')) + with assertRaises(TypeError): + ord(bytearray(b'')) + [case testBytesSlicing] def test_bytes_slicing() -> None: b = b'abcdefg' diff --git a/mypyc/test-data/run-classes.test b/mypyc/test-data/run-classes.test index 59617714f7e7..cf30bddbef64 100644 --- a/mypyc/test-data/run-classes.test +++ b/mypyc/test-data/run-classes.test @@ -3,8 +3,13 @@ class Empty: pass def f(e: Empty) -> Empty: return e + +class EmptyEllipsis: ... + +def g(e: EmptyEllipsis) -> EmptyEllipsis: + return e [file driver.py] -from native import Empty, f +from native import Empty, EmptyEllipsis, f, g print(isinstance(Empty, type)) print(Empty) @@ -12,11 +17,22 @@ print(str(Empty())[:20]) e = Empty() print(f(e) is e) + +print(isinstance(EmptyEllipsis, type)) +print(EmptyEllipsis) +print(str(EmptyEllipsis())[:28]) + +e2 = EmptyEllipsis() +print(g(e2) is e2) [out] True + int: @@ -2503,3 +2532,126 @@ class C: def test_final_attribute() -> None: assert C.A == -1 assert C.a == [-1] + +[case testClassWithFinalDecorator] +from typing import final + +@final +class C: + def a(self) -> int: + return 1 + +def test_class_final_attribute() -> None: + assert C().a() == 1 + + +[case testClassWithFinalDecoratorCtor] +from typing import final + +@final +class C: + def __init__(self) -> None: + self.a = 1 + + def b(self) -> int: + return 2 + + @property + def c(self) -> int: + return 3 + +def test_class_final_attribute() -> None: + assert C().a == 1 + assert C().b() == 2 + assert C().c == 3 + +[case testClassWithFinalDecoratorInheritedWithProperties] +from typing import final + +class B: + def a(self) -> int: + return 2 + + @property + def b(self) -> int: + return self.a() + 2 + + @property + def c(self) -> int: + return 3 + +def test_class_final_attribute_basic() -> None: + assert B().a() == 2 + assert B().b == 4 + assert B().c == 3 + +@final +class C(B): + def a(self) -> int: + return 1 + + @property + def b(self) -> int: + return self.a() + 1 + +def fn(cl: B) -> int: + return cl.a() + +def test_class_final_attribute_inherited() -> None: + assert C().a() == 1 + assert fn(C()) == 1 + assert B().a() == 2 + assert fn(B()) == 2 + + assert B().b == 4 + assert C().b == 2 + assert B().c == 3 + assert C().c == 3 + +[case testClassWithFinalAttributeAccess] +from typing import Final + +class C: + a: Final = {'x': 'y'} + b: Final = C.a + +def test_final_attribute() -> None: + assert C.a['x'] == 'y' + assert C.b['x'] == 'y' + assert C.a is C.b + +[case testClassDerivedFromIntEnum] +from enum import IntEnum, auto + +class Player(IntEnum): + MIN = auto() + +print(f'{Player.MIN = }') +[file driver.py] +from native import Player +[out] +Player.MIN = + +[case testStaticCallsWithUnpackingArgs] +from typing import Tuple + +class Foo: + @staticmethod + def static(a: int, b: int, c: int) -> Tuple[int, int, int]: + return (c+1, a+2, b+3) + + @classmethod + def clsmethod(cls, a: int, b: int, c: int) -> Tuple[int, int, int]: + return (c+1, a+2, b+3) + + +print(Foo.static(*[10, 20, 30])) +print(Foo.static(*(40, 50), *[60])) +assert Foo.static(70, 80, *[90]) == Foo.clsmethod(70, *(80, 90)) + +[file driver.py] +import native + +[out] +(31, 12, 23) +(61, 42, 53) diff --git a/mypyc/test-data/run-dunders-special.test b/mypyc/test-data/run-dunders-special.test new file mode 100644 index 000000000000..cd02cca65eef --- /dev/null +++ b/mypyc/test-data/run-dunders-special.test @@ -0,0 +1,9 @@ +[case testDundersNotImplemented] +# This case is special because it tests the behavior of NotImplemented +# used in a typed function which return type is bool. +# This is a convention that can be overriden by the user. +class UsesNotImplemented: + def __eq__(self, b: object) -> bool: + return NotImplemented + +assert UsesNotImplemented() != object() diff --git a/mypyc/test-data/run-dunders.test b/mypyc/test-data/run-dunders.test index 2845187de2c3..b8fb13c9dcec 100644 --- a/mypyc/test-data/run-dunders.test +++ b/mypyc/test-data/run-dunders.test @@ -32,10 +32,6 @@ class BoxedThing: class Subclass2(BoxedThing): pass -class UsesNotImplemented: - def __eq__(self, b: object) -> bool: - return NotImplemented - def index_into(x : Any, y : Any) -> Any: return x[y] @@ -81,8 +77,6 @@ assert is_truthy(Item('a')) assert not is_truthy(Subclass1('')) assert is_truthy(Subclass1('a')) -assert UsesNotImplemented() != object() - internal_index_into() [out] 7 7 @@ -943,3 +937,31 @@ def test_errors() -> None: pow(ForwardNotImplemented(), Child(), 3) # type: ignore with assertRaises(TypeError, "unsupported operand type(s) for ** or pow(): 'ForwardModRequired' and 'int'"): ForwardModRequired()**3 # type: ignore + +[case testDundersWithFinal] +from typing import final +class A: + def __init__(self, x: int) -> None: + self.x = x + + def __add__(self, y: int) -> int: + return self.x + y + + def __lt__(self, x: 'A') -> bool: + return self.x < x.x + +@final +class B(A): + def __add__(self, y: int) -> int: + return self.x + y + 1 + + def __lt__(self, x: 'A') -> bool: + return self.x < x.x + 1 + +def test_final() -> None: + a = A(5) + b = B(5) + assert a + 3 == 8 + assert b + 3 == 9 + assert (a < A(5)) is False + assert (b < A(5)) is True diff --git a/mypyc/test-data/run-i64.test b/mypyc/test-data/run-i64.test index 1a82ac3e2dd1..36567c949d79 100644 --- a/mypyc/test-data/run-i64.test +++ b/mypyc/test-data/run-i64.test @@ -1307,28 +1307,28 @@ def test_many_locals() -> None: a31: i64 = 31 a32: i64 = 32 a33: i64 = 33 - with assertRaises(NameError): + with assertRaises(UnboundLocalError): print(a0) - with assertRaises(NameError): + with assertRaises(UnboundLocalError): print(a31) - with assertRaises(NameError): + with assertRaises(UnboundLocalError): print(a32) - with assertRaises(NameError): + with assertRaises(UnboundLocalError): print(a33) a0 = 5 assert a0 == 5 - with assertRaises(NameError): + with assertRaises(UnboundLocalError): print(a31) - with assertRaises(NameError): + with assertRaises(UnboundLocalError): print(a32) - with assertRaises(NameError): + with assertRaises(UnboundLocalError): print(a33) a32 = 55 assert a0 == 5 assert a32 == 55 - with assertRaises(NameError): + with assertRaises(UnboundLocalError): print(a31) - with assertRaises(NameError): + with assertRaises(UnboundLocalError): print(a33) a31 = 10 a33 = 20 diff --git a/mypyc/test-data/run-loops.test b/mypyc/test-data/run-loops.test index 95b79af1a411..76fbb06200a3 100644 --- a/mypyc/test-data/run-loops.test +++ b/mypyc/test-data/run-loops.test @@ -228,6 +228,7 @@ def nested_enumerate() -> None: assert i == inner inner += 1 outer += 1 + assert i == 2 assert outer_seen == l1 def nested_range() -> None: @@ -465,6 +466,29 @@ assert g([6, 7], ['a', 'b']) == [(0, 6, 'a'), (1, 7, 'b')] assert f([6, 7], [8]) == [(0, 6, 8)] assert f([6], [8, 9]) == [(0, 6, 8)] +[case testEnumerateEmptyList] +from typing import List + +def get_enumerate_locals(iterable: List[int]) -> int: + for i, j in enumerate(iterable): + pass + try: + return i + except NameError: + return -100 + +[file driver.py] +from native import get_enumerate_locals + +print(get_enumerate_locals([])) +print(get_enumerate_locals([55])) +print(get_enumerate_locals([551, 552])) + +[out] +-100 +0 +1 + [case testIterTypeTrickiness] # Test inferring the type of a for loop body doesn't cause us grief # Extracted from somethings that broke in mypy diff --git a/mypyc/test-data/run-misc.test b/mypyc/test-data/run-misc.test index f07ac51dae6c..2252f3aa104a 100644 --- a/mypyc/test-data/run-misc.test +++ b/mypyc/test-data/run-misc.test @@ -37,9 +37,9 @@ from testutil import assertRaises f(True, True) f(False, False) -with assertRaises(NameError): +with assertRaises(UnboundLocalError): f(False, True) -with assertRaises(NameError): +with assertRaises(UnboundLocalError): g() [out] lol diff --git a/mypyc/test-data/run-primitives.test b/mypyc/test-data/run-primitives.test index b95f742977be..694700d4738c 100644 --- a/mypyc/test-data/run-primitives.test +++ b/mypyc/test-data/run-primitives.test @@ -345,10 +345,10 @@ delAttribute() delAttributeMultiple() with assertRaises(AttributeError): native.global_var -with assertRaises(NameError, 'local variable "dummy" referenced before assignment'): +with assertRaises(UnboundLocalError, 'local variable "dummy" referenced before assignment'): delLocal(True) assert delLocal(False) == 10 -with assertRaises(NameError, 'local variable "dummy" referenced before assignment'): +with assertRaises(UnboundLocalError, 'local variable "dummy" referenced before assignment'): delLocalLoop() [out] (1, 2, 3) diff --git a/mypyc/test-data/run-strings.test b/mypyc/test-data/run-strings.test index be668435d073..1caddce9848d 100644 --- a/mypyc/test-data/run-strings.test +++ b/mypyc/test-data/run-strings.test @@ -565,25 +565,32 @@ def test_chr() -> None: assert try_invalid(1114112) [case testOrd] +from testutil import assertRaises + def test_ord() -> None: + assert ord(' ') == 32 + assert ord(' ' + str()) == 32 + assert ord('\x00') == 0 + assert ord('\x00' + str()) == 0 assert ord('\ue000') == 57344 - s = "a\xac\u1234\u20ac\U00008000" - # ^^^^ two-digit hex escape - # ^^^^^^ four-digit Unicode escape - # ^^^^^^^^^^ eight-digit Unicode escape + assert ord('\ue000' + str()) == 57344 + s = "a\xac\u1234\u20ac\U00010000" + # ^^^^ two-digit hex escape + # ^^^^^^ four-digit Unicode escape + # ^^^^^^^^^^ eight-digit Unicode escape l1 = [ord(c) for c in s] - assert l1 == [97, 172, 4660, 8364, 32768] + assert l1 == [97, 172, 4660, 8364, 65536] u = 'abcdé' assert ord(u[-1]) == 233 assert ord(b'a') == 97 assert ord(b'a' + bytes()) == 97 - u2 = '\U0010ffff' + u2 = '\U0010ffff' + str() assert ord(u2) == 1114111 - try: + assert ord('\U0010ffff') == 1114111 + with assertRaises(TypeError, "ord() expected a character, but a string of length 2 found"): ord('aa') - assert False - except TypeError: - pass + with assertRaises(TypeError): + ord('') [case testDecode] def test_decode() -> None: @@ -639,3 +646,12 @@ def test_encode() -> None: assert u'\u00E1'.encode('latin1') == b'\xe1' with assertRaises(UnicodeEncodeError): u.encode('latin1') + +[case testUnicodeSurrogate] +def f() -> str: + return "\ud800" + +def test_surrogate() -> None: + assert ord(f()) == 0xd800 + assert ord("\udfff") == 0xdfff + assert repr("foobar\x00\xab\ud912\U00012345") == r"'foobar\x00«\ud912𒍅'" diff --git a/mypyc/test/test_cheader.py b/mypyc/test/test_cheader.py index f2af41c22ea9..7ab055c735ad 100644 --- a/mypyc/test/test_cheader.py +++ b/mypyc/test/test_cheader.py @@ -9,7 +9,6 @@ from mypyc.ir.ops import PrimitiveDescription from mypyc.primitives import registry -from mypyc.primitives.registry import CFunctionDescription class TestHeaderInclusion(unittest.TestCase): @@ -26,18 +25,12 @@ def check_name(name: str) -> None: rf"\b{name}\b", header ), f'"{name}" is used in mypyc.primitives but not declared in CPy.h' - for old_values in [ + for values in [ registry.method_call_ops.values(), - registry.function_ops.values(), + registry.binary_ops.values(), registry.unary_ops.values(), + registry.function_ops.values(), ]: - for old_ops in old_values: - if isinstance(old_ops, CFunctionDescription): - old_ops = [old_ops] - for old_op in old_ops: - check_name(old_op.c_function_name) - - for values in [registry.binary_ops.values()]: for ops in values: if isinstance(ops, PrimitiveDescription): ops = [ops] diff --git a/mypyc/test/test_emitfunc.py b/mypyc/test/test_emitfunc.py index 317427afac5a..90df131288f9 100644 --- a/mypyc/test/test_emitfunc.py +++ b/mypyc/test/test_emitfunc.py @@ -134,7 +134,7 @@ def test_integer(self) -> None: def test_tuple_get(self) -> None: self.assert_emit(TupleGet(self.t, 1, 0), "cpy_r_r0 = cpy_r_t.f1;") - def test_load_None(self) -> None: + def test_load_None(self) -> None: # noqa: N802 self.assert_emit( LoadAddress(none_object_op.type, none_object_op.src, 0), "cpy_r_r0 = (PyObject *)&_Py_NoneStruct;", @@ -154,6 +154,7 @@ def test_int_sub(self) -> None: ) def test_int_neg(self) -> None: + assert int_neg_op.c_function_name is not None self.assert_emit( CallC( int_neg_op.c_function_name, @@ -302,7 +303,7 @@ def test_dec_ref_tuple_nested(self) -> None: def test_list_get_item(self) -> None: self.assert_emit( CallC( - list_get_item_op.c_function_name, + str(list_get_item_op.c_function_name), [self.m, self.k], list_get_item_op.return_type, list_get_item_op.steals, @@ -316,7 +317,7 @@ def test_list_get_item(self) -> None: def test_list_set_item(self) -> None: self.assert_emit( CallC( - list_set_item_op.c_function_name, + str(list_set_item_op.c_function_name), [self.l, self.n, self.o], list_set_item_op.return_type, list_set_item_op.steals, @@ -352,7 +353,7 @@ def test_unbox_i64(self) -> None: def test_list_append(self) -> None: self.assert_emit( CallC( - list_append_op.c_function_name, + str(list_append_op.c_function_name), [self.l, self.o], list_append_op.return_type, list_append_op.steals, @@ -492,7 +493,7 @@ def test_set_attr_init_with_bitmap(self) -> None: def test_dict_get_item(self) -> None: self.assert_emit( CallC( - dict_get_item_op.c_function_name, + str(dict_get_item_op.c_function_name), [self.d, self.o2], dict_get_item_op.return_type, dict_get_item_op.steals, @@ -506,7 +507,7 @@ def test_dict_get_item(self) -> None: def test_dict_set_item(self) -> None: self.assert_emit( CallC( - dict_set_item_op.c_function_name, + str(dict_set_item_op.c_function_name), [self.d, self.o, self.o2], dict_set_item_op.return_type, dict_set_item_op.steals, @@ -520,7 +521,7 @@ def test_dict_set_item(self) -> None: def test_dict_update(self) -> None: self.assert_emit( CallC( - dict_update_op.c_function_name, + str(dict_update_op.c_function_name), [self.d, self.o], dict_update_op.return_type, dict_update_op.steals, diff --git a/mypyc/test/test_external.py b/mypyc/test/test_external.py index 22eb8019133c..010c74dee42e 100644 --- a/mypyc/test/test_external.py +++ b/mypyc/test/test_external.py @@ -20,7 +20,9 @@ def test_c_unit_test(self) -> None: cppflags: list[str] = [] env = os.environ.copy() if sys.platform == "darwin": - cppflags += ["-mmacosx-version-min=10.10", "-stdlib=libc++"] + cppflags += ["-O0", "-mmacosx-version-min=10.10", "-stdlib=libc++"] + elif sys.platform == "linux": + cppflags += ["-O0"] env["CPPFLAGS"] = " ".join(cppflags) # Build Python wrapper for C unit tests. diff --git a/mypyc/test/test_namegen.py b/mypyc/test/test_namegen.py index 509018b4c3bd..f88edbd00dce 100644 --- a/mypyc/test/test_namegen.py +++ b/mypyc/test/test_namegen.py @@ -35,6 +35,12 @@ def test_make_module_translation_map(self) -> None: "fu.bar": "fu.bar.", "foo.baz": "baz.", } + assert make_module_translation_map(["foo", "foo.foo", "bar.foo", "bar.foo.bar.foo"]) == { + "foo": "foo.", + "foo.foo": "foo.foo.", + "bar.foo": "bar.foo.", + "bar.foo.bar.foo": "foo.bar.foo.", + } def test_name_generator(self) -> None: g = NameGenerator([["foo", "foo.zar"]]) diff --git a/mypyc/test/test_run.py b/mypyc/test/test_run.py index 668e5b124841..dd3c79da7b9b 100644 --- a/mypyc/test/test_run.py +++ b/mypyc/test/test_run.py @@ -63,6 +63,7 @@ "run-bench.test", "run-mypy-sim.test", "run-dunders.test", + "run-dunders-special.test", "run-singledispatch.test", "run-attrs.test", "run-python37.test", @@ -140,6 +141,7 @@ class TestRun(MypycDataSuite): optional_out = True multi_file = False separate = False # If True, using separate (incremental) compilation + strict_dunder_typing = False def run_case(self, testcase: DataDrivenTestCase) -> None: # setup.py wants to be run from the root directory of the package, which we accommodate @@ -232,7 +234,11 @@ def run_case_step(self, testcase: DataDrivenTestCase, incremental_step: int) -> groups = construct_groups(sources, separate, len(module_names) > 1) try: - compiler_options = CompilerOptions(multi_file=self.multi_file, separate=self.separate) + compiler_options = CompilerOptions( + multi_file=self.multi_file, + separate=self.separate, + strict_dunder_typing=self.strict_dunder_typing, + ) result = emitmodule.parse_and_typecheck( sources=sources, options=options, @@ -401,6 +407,14 @@ class TestRunSeparate(TestRun): files = ["run-multimodule.test", "run-mypy-sim.test"] +class TestRunStrictDunderTyping(TestRun): + """Run the tests with strict dunder typing.""" + + strict_dunder_typing = True + test_name_suffix = "_dunder_typing" + files = ["run-dunders.test", "run-floats.test"] + + def fix_native_line_number(message: str, fnam: str, delta: int) -> str: """Update code locations in test case output to point to the .test file. diff --git a/pyproject.toml b/pyproject.toml index 12a0dc109cd5..1a7adf21c0a6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,8 +3,7 @@ requires = [ # NOTE: this needs to be kept in sync with mypy-requirements.txt # and build-requirements.txt, because those are both needed for # self-typechecking :/ - "setuptools >= 40.6.2", - "wheel >= 0.30.0", + "setuptools >= 75.1.0", # the following is from mypy-requirements.txt/setup.py "typing_extensions>=4.6.0", "mypy_extensions>=1.0.0", @@ -15,6 +14,83 @@ requires = [ ] build-backend = "setuptools.build_meta" +[project] +name = "mypy" +description = "Optional static typing for Python" +readme = {text = """ +Mypy -- Optional Static Typing for Python +========================================= + +Add type annotations to your Python programs, and use mypy to type +check them. Mypy is essentially a Python linter on steroids, and it +can catch many programming errors by analyzing your program, without +actually having to run it. Mypy has a powerful type system with +features such as type inference, gradual typing, generics and union +types. +""", content-type = "text/x-rst"} +authors = [{name = "Jukka Lehtosalo", email = "jukka.lehtosalo@iki.fi"}] +license = {text = "MIT"} +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Topic :: Software Development", + "Typing :: Typed", +] +requires-python = ">=3.8" +dependencies = [ + # When changing this, also update build-system.requires and mypy-requirements.txt + "typing_extensions>=4.6.0", + "mypy_extensions>=1.0.0", + "tomli>=1.1.0; python_version<'3.11'", +] +dynamic = ["version"] + +[project.optional-dependencies] +dmypy = ["psutil>=4.0"] +mypyc = ["setuptools>=50"] +python2 = [] +reports = ["lxml"] +install-types = ["pip"] +faster-cache = ["orjson"] + +[project.urls] +Homepage = "https://www.mypy-lang.org/" +Documentation = "https://mypy.readthedocs.io/en/stable/index.html" +Repository = "https://github.com/python/mypy" +Changelog = "https://github.com/python/mypy/blob/master/CHANGELOG.md" +Issues = "https://github.com/python/mypy/issues" + +[project.scripts] +mypy = "mypy.__main__:console_entry" +stubgen = "mypy.stubgen:main" +stubtest = "mypy.stubtest:main" +dmypy = "mypy.dmypy.client:console_entry" +mypyc = "mypyc.__main__:main" + +[tool.setuptools.packages.find] +include = ["mypy*", "mypyc*", "*__mypyc*"] +namespaces = false + +[tool.setuptools.package-data] +mypy = [ + "py.typed", + "typeshed/**/*.py", + "typeshed/**/*.pyi", + "typeshed/stdlib/VERSIONS", + "xml/*.xsd", + "xml/*.xslt", + "xml/*.css", +] + [tool.black] line-length = 99 target-version = ["py38", "py39", "py310", "py311", "py312"] @@ -50,6 +126,7 @@ select = [ "W", # pycodestyle (warning) "B", # flake8-bugbear "I", # isort + "N", # pep8-naming "RUF100", # Unused noqa comments "PGH004", # blanket noqa comments "UP", # pyupgrade @@ -66,8 +143,12 @@ ignore = [ "E2", # conflicts with black "E402", # module level import not at top of file "E501", # conflicts with black + "E721", # Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks "E731", # Do not assign a `lambda` expression, use a `def` "E741", # Ambiguous variable name + "N818", # Exception should be named with an Error suffix + "N806", # UPPER_CASE used for constant local variables + "UP031", # Use format specifiers instead of percent format "UP032", # 'f-string always preferable to format' is controversial "C416", # There are a few cases where it's nice to have names for the dict items ] @@ -80,6 +161,10 @@ unfixable = [ "UP036", # sometimes it's better to just noqa this ] +[tool.ruff.lint.per-file-ignores] +# Mixed case variable and function names. +"mypy/fastparse.py" = ["N802", "N816"] + [tool.ruff.lint.isort] combine-as-imports = true extra-standard-library = ["typing_extensions"] diff --git a/runtests.py b/runtests.py index 80ef8d814ee1..9863e8491500 100755 --- a/runtests.py +++ b/runtests.py @@ -17,6 +17,8 @@ MYPYC_RUN_MULTI = "TestRunMultiFile" MYPYC_EXTERNAL = "TestExternal" MYPYC_COMMAND_LINE = "TestCommandLine" +MYPYC_SEPARATE = "TestRunSeparate" +MYPYC_MULTIMODULE = "multimodule" # Subset of mypyc run tests that are slow ERROR_STREAM = "ErrorStreamSuite" @@ -31,6 +33,7 @@ MYPYC_RUN_MULTI, MYPYC_EXTERNAL, MYPYC_COMMAND_LINE, + MYPYC_SEPARATE, ERROR_STREAM, ] @@ -40,7 +43,10 @@ # These must be enabled by explicitly including 'mypyc-extra' on the command line. -MYPYC_OPT_IN = [MYPYC_RUN, MYPYC_RUN_MULTI] +MYPYC_OPT_IN = [MYPYC_RUN, MYPYC_RUN_MULTI, MYPYC_SEPARATE] + +# These mypyc test filters cover most slow test cases +MYPYC_SLOW = [MYPYC_RUN_MULTI, MYPYC_COMMAND_LINE, MYPYC_SEPARATE, MYPYC_MULTIMODULE] # We split the pytest run into three parts to improve test @@ -77,6 +83,7 @@ "-k", " or ".join([DAEMON, MYPYC_EXTERNAL, MYPYC_COMMAND_LINE, ERROR_STREAM]), ], + "mypyc-fast": ["pytest", "-q", "mypyc", "-k", f"not ({' or '.join(MYPYC_SLOW)})"], # Test cases that might take minutes to run "pytest-extra": ["pytest", "-q", "-k", " or ".join(PYTEST_OPT_IN)], # Mypyc tests that aren't run by default, since they are slow and rarely @@ -87,7 +94,7 @@ # Stop run immediately if these commands fail FAST_FAIL = ["self", "lint"] -EXTRA_COMMANDS = ("pytest-extra", "mypyc-extra") +EXTRA_COMMANDS = ("pytest-extra", "mypyc-fast", "mypyc-extra") DEFAULT_COMMANDS = [cmd for cmd in cmds if cmd not in EXTRA_COMMANDS] assert all(cmd in cmds for cmd in FAST_FAIL) diff --git a/setup.py b/setup.py index 160e2b054b0e..180faf6d8ded 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ # This requires setuptools when building; setuptools is not needed # when installing from a wheel file (though it is still needed for # alternative forms of installing, as suggested by README.md). -from setuptools import Extension, find_packages, setup +from setuptools import Extension, setup from setuptools.command.build_py import build_py from mypy.version import __version__ as version @@ -26,19 +26,6 @@ if TYPE_CHECKING: from typing_extensions import TypeGuard -description = "Optional static typing for Python" -long_description = """ -Mypy -- Optional Static Typing for Python -========================================= - -Add type annotations to your Python programs, and use mypy to type -check them. Mypy is essentially a Python linter on steroids, and it -can catch many programming errors by analyzing your program, without -actually having to run it. Mypy has a powerful type system with -features such as type inference, gradual typing, generics and union -types. -""".lstrip() - def is_list_of_setuptools_extension(items: list[Any]) -> TypeGuard[list[Extension]]: return all(isinstance(item, Extension) for item in items) @@ -78,13 +65,6 @@ def run(self): cmdclass = {"build_py": CustomPythonBuild} -package_data = ["py.typed"] - -package_data += find_package_data(os.path.join("mypy", "typeshed"), ["*.py", "*.pyi"]) -package_data += [os.path.join("mypy", "typeshed", "stdlib", "VERSIONS")] - -package_data += find_package_data(os.path.join("mypy", "xml"), ["*.xsd", "*.xslt", "*.css"]) - USE_MYPYC = False # To compile with mypyc, a mypyc checkout must be present on the PYTHONPATH if len(sys.argv) > 1 and "--use-mypyc" in sys.argv: @@ -179,65 +159,4 @@ def run(self): ext_modules = [] -classifiers = [ - "Development Status :: 5 - Production/Stable", - "Environment :: Console", - "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Topic :: Software Development", - "Typing :: Typed", -] - -setup( - name="mypy", - version=version, - description=description, - long_description=long_description, - author="Jukka Lehtosalo", - author_email="jukka.lehtosalo@iki.fi", - url="https://www.mypy-lang.org/", - license="MIT", - py_modules=[], - ext_modules=ext_modules, - packages=find_packages(), - package_data={"mypy": package_data}, - entry_points={ - "console_scripts": [ - "mypy=mypy.__main__:console_entry", - "stubgen=mypy.stubgen:main", - "stubtest=mypy.stubtest:main", - "dmypy=mypy.dmypy.client:console_entry", - "mypyc=mypyc.__main__:main", - ] - }, - classifiers=classifiers, - cmdclass=cmdclass, - # When changing this, also update mypy-requirements.txt and pyproject.toml - install_requires=[ - "typing_extensions>=4.6.0", - "mypy_extensions >= 1.0.0", - "tomli>=1.1.0; python_version<'3.11'", - ], - # Same here. - extras_require={ - "dmypy": "psutil >= 4.0", - "mypyc": "setuptools >= 50", - "python2": "", - "reports": "lxml", - "install-types": "pip", - }, - python_requires=">=3.8", - include_package_data=True, - project_urls={ - "Documentation": "https://mypy.readthedocs.io/en/stable/index.html", - "Repository": "https://github.com/python/mypy", - "Changelog": "https://github.com/python/mypy/blob/master/CHANGELOG.md", - "Issues": "https://github.com/python/mypy/issues", - }, -) +setup(version=version, ext_modules=ext_modules, cmdclass=cmdclass) diff --git a/test-data/unit/README.md b/test-data/unit/README.md index 5a9416603541..aaf774d1b62f 100644 --- a/test-data/unit/README.md +++ b/test-data/unit/README.md @@ -100,6 +100,10 @@ First install any additional dependencies needed for testing: python3 -m pip install -U -r test-requirements.txt +Configure `pre-commit` to run the linters automatically when you commit: + + pre-commit install + The unit test suites are driven by the `pytest` framework. To run all mypy tests, run `pytest` in the mypy repository: @@ -157,9 +161,11 @@ To run mypy on itself: python3 -m mypy --config-file mypy_self_check.ini -p mypy -To run the linter: +To run the linter (this commands just wraps `pre-commit`, so you can also +invoke it directly like `pre-commit run -a`, and this will also run when you +`git commit` if enabled): - ruff . + python3 runtests.py lint You can also run all of the above tests using `runtests.py` (this includes type checking mypy and linting): diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index 82208d27df41..5ce80faaee18 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -147,7 +147,6 @@ class Base: class Derived(Base): __hash__ = 1 # E: Incompatible types in assignment (expression has type "int", base class "Base" defined the type as "Callable[[Base], int]") - [case testOverridePartialAttributeWithMethod] # This was crashing: https://github.com/python/mypy/issues/11686. class Base: @@ -710,6 +709,123 @@ class B(A): @dec def f(self) -> Y: pass +[case testOverrideCallableAttributeWithMethod] +from typing import Callable + +class A: + f1: Callable[[str], None] + f2: Callable[[str], None] + f3: Callable[[str], None] + +class B(A): + def f1(self, x: object) -> None: + pass + + @classmethod + def f2(cls, x: object) -> None: + pass + + @staticmethod + def f3(x: object) -> None: + pass +[builtins fixtures/classmethod.pyi] + +[case testOverrideCallableAttributeWithMethodMutableOverride] +# flags: --enable-error-code=mutable-override +from typing import Callable + +class A: + f1: Callable[[str], None] + f2: Callable[[str], None] + f3: Callable[[str], None] + +class B(A): + def f1(self, x: object) -> None: pass # E: Covariant override of a mutable attribute (base class "A" defined the type as "Callable[[str], None]", override has type "Callable[[object], None]") + + @classmethod + def f2(cls, x: object) -> None: pass # E: Covariant override of a mutable attribute (base class "A" defined the type as "Callable[[str], None]", override has type "Callable[[object], None]") + + @staticmethod + def f3(x: object) -> None: pass # E: Covariant override of a mutable attribute (base class "A" defined the type as "Callable[[str], None]", override has type "Callable[[object], None]") +[builtins fixtures/classmethod.pyi] + +[case testOverrideCallableAttributeWithSettableProperty] +from typing import Callable + +class A: + f: Callable[[str], None] + +class B(A): + @property + def f(self) -> Callable[[object], None]: pass + @func.setter + def f(self, x: object) -> None: pass +[builtins fixtures/property.pyi] + +[case testOverrideCallableAttributeWithSettablePropertyMutableOverride] +# flags: --enable-error-code=mutable-override +from typing import Callable + +class A: + f: Callable[[str], None] + +class B(A): + @property # E: Covariant override of a mutable attribute (base class "A" defined the type as "Callable[[str], None]", override has type "Callable[[object], None]") + def f(self) -> Callable[[object], None]: pass + @func.setter + def f(self, x: object) -> None: pass +[builtins fixtures/property.pyi] + +[case testOverrideCallableUnionAttributeWithMethod] +from typing import Callable, Union + +class A: + f1: Union[Callable[[str], str], str] + f2: Union[Callable[[str], str], str] + f3: Union[Callable[[str], str], str] + f4: Union[Callable[[str], str], str] + +class B(A): + def f1(self, x: str) -> str: + pass + + def f2(self, x: object) -> str: + pass + + @classmethod + def f3(cls, x: str) -> str: + pass + + @staticmethod + def f4(x: str) -> str: + pass +[builtins fixtures/classmethod.pyi] + +[case testOverrideCallableUnionAttributeWithMethodMutableOverride] +# flags: --enable-error-code=mutable-override +from typing import Callable, Union + +class A: + f1: Union[Callable[[str], str], str] + f2: Union[Callable[[str], str], str] + f3: Union[Callable[[str], str], str] + f4: Union[Callable[[str], str], str] + +class B(A): + def f1(self, x: str) -> str: # E: Covariant override of a mutable attribute (base class "A" defined the type as "Union[Callable[[str], str], str]", override has type "Callable[[str], str]") + pass + + def f2(self, x: object) -> str: # E: Covariant override of a mutable attribute (base class "A" defined the type as "Union[Callable[[str], str], str]", override has type "Callable[[object], str]") + pass + + @classmethod + def f3(cls, x: str) -> str: # E: Covariant override of a mutable attribute (base class "A" defined the type as "Union[Callable[[str], str], str]", override has type "Callable[[str], str]") + pass + + @staticmethod + def f4(x: str) -> str: # E: Covariant override of a mutable attribute (base class "A" defined the type as "Union[Callable[[str], str], str]", override has type "Callable[[str], str]") + pass +[builtins fixtures/classmethod.pyi] -- Constructors -- ------------ diff --git a/test-data/unit/check-custom-plugin.test b/test-data/unit/check-custom-plugin.test index 2b3b3f4a8695..1e06f300570e 100644 --- a/test-data/unit/check-custom-plugin.test +++ b/test-data/unit/check-custom-plugin.test @@ -232,6 +232,8 @@ reveal_type(magic.non_magic_method()) # N: Revealed type is "builtins.int" reveal_type(magic.non_magic_field) # N: Revealed type is "builtins.int" magic.nonexistent_field # E: Field does not exist reveal_type(magic.fallback_example) # N: Revealed type is "Any" +reveal_type(magic.no_assignment_field) # N: Revealed type is "builtins.float" +magic.no_assignment_field = "bad" # E: Cannot assign to field derived = DerivedMagic() reveal_type(derived.magic_field) # N: Revealed type is "builtins.str" @@ -250,6 +252,7 @@ class Magic: def __getattr__(self, x: Any) -> Any: ... def non_magic_method(self) -> int: ... non_magic_field: int + no_assignment_field: float class DerivedMagic(Magic): ... [file mypy.ini] @@ -964,6 +967,7 @@ class Cls(enum.Enum): attr = 'test' reveal_type(Cls.attr) # N: Revealed type is "builtins.int" +[builtins fixtures/enum.pyi] [file mypy.ini] \[mypy] plugins=/test-data/unit/plugins/class_attr_hook.py diff --git a/test-data/unit/check-dataclasses.test b/test-data/unit/check-dataclasses.test index 0f726242b25b..6de428109c72 100644 --- a/test-data/unit/check-dataclasses.test +++ b/test-data/unit/check-dataclasses.test @@ -2492,12 +2492,14 @@ class Child(Base): [case testDunderReplacePresent] # flags: --python-version 3.13 -from dataclasses import dataclass +from dataclasses import dataclass, field @dataclass class Coords: x: int y: int + # non-init fields are not allowed with replace: + z: int = field(init=False) replaced = Coords(2, 4).__replace__(x=2, y=5) @@ -2523,3 +2525,18 @@ reveal_type(replaced_2) # N: Revealed type is "__main__.Gen[builtins.int]" Gen(2).__replace__(x="not an int") # E: Argument "x" to "__replace__" of "Gen" has incompatible type "str"; expected "int" [builtins fixtures/tuple.pyi] + +[case testDunderReplaceCovariantOverride] +# flags: --python-version 3.13 +from dataclasses import dataclass + +@dataclass +class Base: + a: object + +@dataclass +class Child(Base): # E: Argument 1 of "__replace__" is incompatible with supertype "Base"; supertype defines the argument type as "object" \ + # N: This violates the Liskov substitution principle \ + # N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides + a: int +[builtins fixtures/tuple.pyi] diff --git a/test-data/unit/check-deprecated.test b/test-data/unit/check-deprecated.test new file mode 100644 index 000000000000..362d8725f183 --- /dev/null +++ b/test-data/unit/check-deprecated.test @@ -0,0 +1,636 @@ +-- Type checker test cases for reporting deprecations. + + +[case testDeprecatedDisabled] + +from typing_extensions import deprecated + +@deprecated("use f2 instead") +def f() -> None: ... + +f() + +[builtins fixtures/tuple.pyi] + + +[case testDeprecatedAsNoteWithErrorCode] +# flags: --enable-error-code=deprecated --show-error-codes --report-deprecated-as-note + +from typing_extensions import deprecated + +@deprecated("use f2 instead") +def f() -> None: ... + +f() # type: ignore[deprecated] +f() # N: function __main__.f is deprecated: use f2 instead [deprecated] + +[builtins fixtures/tuple.pyi] + + +[case testDeprecatedAsErrorWithErrorCode] +# flags: --enable-error-code=deprecated --show-error-codes + +from typing_extensions import deprecated + +@deprecated("use f2 instead") +def f() -> None: ... + +f() # type: ignore[deprecated] +f() # E: function __main__.f is deprecated: use f2 instead [deprecated] + +[builtins fixtures/tuple.pyi] + + +[case testDeprecatedFunction] +# flags: --enable-error-code=deprecated + +from typing_extensions import deprecated + +@deprecated("use f2 instead") +def f() -> None: ... + +f # E: function __main__.f is deprecated: use f2 instead # type: ignore[deprecated] +f(1) # E: function __main__.f is deprecated: use f2 instead \ + # E: Too many arguments for "f" +f[1] # E: function __main__.f is deprecated: use f2 instead \ + # E: Value of type "Callable[[], None]" is not indexable +g = f # E: function __main__.f is deprecated: use f2 instead +g() +t = (f, f, g) # E: function __main__.f is deprecated: use f2 instead + +[builtins fixtures/tuple.pyi] + + +[case testDeprecatedFunctionDifferentModule] +# flags: --enable-error-code=deprecated + +import m +import p.s +import m as n +import p.s as ps +from m import f # E: function m.f is deprecated: use f2 instead +from p.s import g # E: function p.s.g is deprecated: use g2 instead +from k import * + +m.f() # E: function m.f is deprecated: use f2 instead +p.s.g() # E: function p.s.g is deprecated: use g2 instead +n.f() # E: function m.f is deprecated: use f2 instead +ps.g() # E: function p.s.g is deprecated: use g2 instead +f() +g() +h() # E: function k.h is deprecated: use h2 instead + +[file m.py] +from typing_extensions import deprecated + +@deprecated("use f2 instead") +def f() -> None: ... + +[file p/s.py] +from typing_extensions import deprecated + +@deprecated("use g2 instead") +def g() -> None: ... + +[file k.py] +from typing_extensions import deprecated + +@deprecated("use h2 instead") +def h() -> None: ... + +[builtins fixtures/tuple.pyi] + + +[case testDeprecatedClass] +# flags: --enable-error-code=deprecated + +from typing import Callable, List, Optional, Tuple, Union +from typing_extensions import deprecated, TypeAlias, TypeVar + +@deprecated("use C2 instead") +class C: ... + +c: C # E: class __main__.C is deprecated: use C2 instead +C() # E: class __main__.C is deprecated: use C2 instead +C.missing() # E: class __main__.C is deprecated: use C2 instead \ + # E: "Type[C]" has no attribute "missing" +C.__init__(c) # E: class __main__.C is deprecated: use C2 instead +C(1) # E: class __main__.C is deprecated: use C2 instead \ + # E: Too many arguments for "C" + +D = C # E: class __main__.C is deprecated: use C2 instead +D() +t = (C, C, D) # E: class __main__.C is deprecated: use C2 instead + +u1: Union[C, int] = 1 # E: class __main__.C is deprecated: use C2 instead +u1 = 1 +u2 = 1 # type: Union[C, int] # E: class __main__.C is deprecated: use C2 instead +u2 = 1 + +c1 = c2 = C() # E: class __main__.C is deprecated: use C2 instead +i, c3 = 1, C() # E: class __main__.C is deprecated: use C2 instead + +class E: ... + +x1: Optional[C] # E: class __main__.C is deprecated: use C2 instead +x2: Union[D, C, E] # E: class __main__.C is deprecated: use C2 instead +x3: Union[D, Optional[C], E] # E: class __main__.C is deprecated: use C2 instead +x4: Tuple[D, C, E] # E: class __main__.C is deprecated: use C2 instead +x5: Tuple[Tuple[D, C], E] # E: class __main__.C is deprecated: use C2 instead +x6: List[C] # E: class __main__.C is deprecated: use C2 instead +x7: List[List[C]] # E: class __main__.C is deprecated: use C2 instead +x8: List[Optional[Tuple[Union[List[C], int]]]] # E: class __main__.C is deprecated: use C2 instead +x9: Callable[[int], C] # E: class __main__.C is deprecated: use C2 instead +x10: Callable[[int, C, int], int] # E: class __main__.C is deprecated: use C2 instead + +T = TypeVar("T") +A1: TypeAlias = Optional[C] # E: class __main__.C is deprecated: use C2 instead +x11: A1 +A2: TypeAlias = List[Union[A2, C]] # E: class __main__.C is deprecated: use C2 instead +x12: A2 +A3: TypeAlias = List[Optional[T]] +x13: A3[C] # E: class __main__.C is deprecated: use C2 instead + +[builtins fixtures/tuple.pyi] + + +[case testDeprecatedBaseClass] +# flags: --enable-error-code=deprecated + +from typing_extensions import deprecated + +@deprecated("use C2 instead") +class C: ... + +class D(C): ... # E: class __main__.C is deprecated: use C2 instead +class E(D): ... +class F(D, C): ... # E: class __main__.C is deprecated: use C2 instead + +[builtins fixtures/tuple.pyi] + + +[case testDeprecatedClassInTypeVar] +# flags: --enable-error-code=deprecated + +from typing import Generic, TypeVar +from typing_extensions import deprecated + +class B: ... +@deprecated("use C2 instead") +class C: ... + +T = TypeVar("T", bound=C) # E: class __main__.C is deprecated: use C2 instead +def f(x: T) -> T: ... +class D(Generic[T]): ... + +V = TypeVar("V", B, C) # E: class __main__.C is deprecated: use C2 instead +def g(x: V) -> V: ... +class E(Generic[V]): ... + +[builtins fixtures/tuple.pyi] + + +[case testDeprecatedClassInCast] +# flags: --enable-error-code=deprecated + +from typing import cast, Generic +from typing_extensions import deprecated + +class B: ... +@deprecated("use C2 instead") +class C: ... + +c = C() # E: class __main__.C is deprecated: use C2 instead +b = cast(B, c) + +[builtins fixtures/tuple.pyi] + + +[case testDeprecatedInstanceInFunctionDefinition] +# flags: --enable-error-code=deprecated + +from typing import Generic, List, Optional, TypeVar +from typing_extensions import deprecated + +@deprecated("use C2 instead") +class C: ... + +def f1(c: C) -> None: # E: class __main__.C is deprecated: use C2 instead + def g1() -> None: ... + +def f2(c: List[Optional[C]]) -> None: # E: class __main__.C is deprecated: use C2 instead + def g2() -> None: ... + +def f3() -> C: # E: class __main__.C is deprecated: use C2 instead + def g3() -> None: ... + return C() # E: class __main__.C is deprecated: use C2 instead + +def f4() -> List[Optional[C]]: # E: class __main__.C is deprecated: use C2 instead + def g4() -> None: ... + return [] + +def f5() -> None: + def g5(c: C) -> None: ... # E: class __main__.C is deprecated: use C2 instead + +def f6() -> None: + def g6() -> C: ... # E: class __main__.C is deprecated: use C2 instead + + +@deprecated("use D2 instead") +class D: + + def f1(self, c: C) -> None: # E: class __main__.C is deprecated: use C2 instead + def g1() -> None: ... + + def f2(self, c: List[Optional[C]]) -> None: # E: class __main__.C is deprecated: use C2 instead + def g2() -> None: ... + + def f3(self) -> None: + def g3(c: C) -> None: ... # E: class __main__.C is deprecated: use C2 instead + + def f4(self) -> None: + def g4() -> C: ... # E: class __main__.C is deprecated: use C2 instead + +T = TypeVar("T") + +@deprecated("use E2 instead") +class E(Generic[T]): + + def f1(self: E[C]) -> None: ... # E: class __main__.C is deprecated: use C2 instead + def f2(self, e: E[C]) -> None: ... # E: class __main__.C is deprecated: use C2 instead + def f3(self) -> E[C]: ... # E: class __main__.C is deprecated: use C2 instead + +[builtins fixtures/tuple.pyi] + + +[case testDeprecatedClassDifferentModule] +# flags: --enable-error-code=deprecated + +import m +import p.s +import m as n +import p.s as ps +from m import B, C # E: class m.B is deprecated: use B2 instead \ + # E: class m.C is deprecated: use C2 instead +from p.s import D # E: class p.s.D is deprecated: use D2 instead +from k import * + +m.C() # E: class m.C is deprecated: use C2 instead +p.s.D() # E: class p.s.D is deprecated: use D2 instead +n.C() # E: class m.C is deprecated: use C2 instead +ps.D() # E: class p.s.D is deprecated: use D2 instead +C() +D() +E() # E: class k.E is deprecated: use E2 instead + +x1: m.A # E: class m.A is deprecated: use A2 instead +x2: m.A = m.A() # E: class m.A is deprecated: use A2 instead +y1: B +y2: B = B() + +[file m.py] +from typing_extensions import deprecated + +@deprecated("use A2 instead") +class A: ... + +@deprecated("use B2 instead") +class B: ... + +@deprecated("use C2 instead") +class C: ... + +[file p/s.py] +from typing_extensions import deprecated + +@deprecated("use D2 instead") +class D: ... + +[file k.py] +from typing_extensions import deprecated + +@deprecated("use E2 instead") +class E: ... + +[builtins fixtures/tuple.pyi] + + +[case testDeprecatedClassInitMethod] +# flags: --enable-error-code=deprecated + +from typing_extensions import deprecated + +@deprecated("use C2 instead") +class C: + def __init__(self) -> None: ... + +c: C # E: class __main__.C is deprecated: use C2 instead +C() # E: class __main__.C is deprecated: use C2 instead +C.__init__(c) # E: class __main__.C is deprecated: use C2 instead + +[builtins fixtures/tuple.pyi] + + +[case testDeprecatedSpecialMethods] +# flags: --enable-error-code=deprecated + +from typing import Iterator +from typing_extensions import deprecated + +class A: + @deprecated("no A + int") + def __add__(self, v: int) -> None: ... + + @deprecated("no int + A") + def __radd__(self, v: int) -> None: ... + + @deprecated("no A = A + int") + def __iadd__(self, v: int) -> A: ... + + @deprecated("no iteration") + def __iter__(self) -> Iterator[int]: ... + + @deprecated("no in") + def __contains__(self, v: int) -> int: ... + + @deprecated("no integer") + def __int__(self) -> int: ... + + @deprecated("no inversion") + def __invert__(self) -> A: ... + +class B: + @deprecated("still no in") + def __contains__(self, v: int) -> int: ... + +a = A() +b = B() +a + 1 # E: function __main__.A.__add__ is deprecated: no A + int +1 + a # E: function __main__.A.__radd__ is deprecated: no int + A +a += 1 # E: function __main__.A.__iadd__ is deprecated: no A = A + int +for i in a: # E: function __main__.A.__iter__ is deprecated: no iteration + reveal_type(i) # N: Revealed type is "builtins.int" +1 in a # E: function __main__.A.__contains__ is deprecated: no in +1 in b # E: function __main__.B.__contains__ is deprecated: still no in +~a # E: function __main__.A.__invert__ is deprecated: no inversion + +[builtins fixtures/tuple.pyi] + + +[case testDeprecatedOverloadedSpecialMethods] +# flags: --enable-error-code=deprecated + +from typing import Iterator, Union +from typing_extensions import deprecated, overload + +class A: + @overload + @deprecated("no A + int") + def __add__(self, v: int) -> None: ... + @overload + def __add__(self, v: str) -> None: ... + def __add__(self, v: Union[int, str]) -> None: ... + + @overload + def __radd__(self, v: int) -> None: ... + @overload + @deprecated("no str + A") + def __radd__(self, v: str) -> None: ... + def __radd__(self, v: Union[int, str]) -> None: ... + + @overload + def __iadd__(self, v: int) -> A: ... + @overload + def __iadd__(self, v: str) -> A: ... + @deprecated("no A += Any") + def __iadd__(self, v: Union[int, str]) -> A: ... + +a = A() +a + 1 # E: overload def (__main__.A, builtins.int) of function __main__.A.__add__ is deprecated: no A + int +a + "x" +1 + a +"x" + a # E: overload def (__main__.A, builtins.str) of function __main__.A.__radd__ is deprecated: no str + A +a += 1 # E: function __main__.A.__iadd__ is deprecated: no A += Any +a += "x" # E: function __main__.A.__iadd__ is deprecated: no A += Any + +[builtins fixtures/tuple.pyi] + + +[case testDeprecatedMethod] +# flags: --enable-error-code=deprecated + +from typing_extensions import deprecated + +class C: + @deprecated("use g instead") + def f(self) -> None: ... + + def g(self) -> None: ... + + @staticmethod + @deprecated("use g instead") + def h() -> None: ... + + @deprecated("use g instead") + @staticmethod + def k() -> None: ... + +C.f # E: function __main__.C.f is deprecated: use g instead +C().f # E: function __main__.C.f is deprecated: use g instead +C().f() # E: function __main__.C.f is deprecated: use g instead +C().f(1) # E: function __main__.C.f is deprecated: use g instead \ + # E: Too many arguments for "f" of "C" +f = C().f # E: function __main__.C.f is deprecated: use g instead +f() +t = (C.f, C.f, C.g) # E: function __main__.C.f is deprecated: use g instead + +C().g() +C().h() # E: function __main__.C.h is deprecated: use g instead +C().k() # E: function __main__.C.k is deprecated: use g instead + +[builtins fixtures/callable.pyi] + + +[case testDeprecatedClassWithDeprecatedMethod] +# flags: --enable-error-code=deprecated + +from typing_extensions import deprecated + +@deprecated("use D instead") +class C: + @deprecated("use g instead") + def f(self) -> None: ... + def g(self) -> None: ... + +C().f() # E: class __main__.C is deprecated: use D instead \ + # E: function __main__.C.f is deprecated: use g instead +C().g() # E: class __main__.C is deprecated: use D instead + +[builtins fixtures/callable.pyi] + + +[case testDeprecatedProperty] +# flags: --enable-error-code=deprecated + +from typing_extensions import deprecated + +class C: + @property + @deprecated("use f2 instead") + def f(self) -> int: ... + + @property + def g(self) -> int: ... + @g.setter + @deprecated("use g2 instead") + def g(self, v: int) -> None: ... + + +C.f # E: function __main__.C.f is deprecated: use f2 instead +C().f # E: function __main__.C.f is deprecated: use f2 instead +C().f() # E: function __main__.C.f is deprecated: use f2 instead \ + # E: "int" not callable +C().f = 1 # E: function __main__.C.f is deprecated: use f2 instead \ + # E: Property "f" defined in "C" is read-only + + +C.g +C().g +C().g = 1 # E: function __main__.C.g is deprecated: use g2 instead +C().g = "x" # E: function __main__.C.g is deprecated: use g2 instead \ + # E: Incompatible types in assignment (expression has type "str", variable has type "int") + +[builtins fixtures/property.pyi] + + +[case testDeprecatedDescriptor] +# flags: --enable-error-code=deprecated + +from typing import Any, Optional, Union +from typing_extensions import deprecated, overload + +@deprecated("use E1 instead") +class D1: + def __get__(self, obj: Optional[C], objtype: Any) -> Union[D1, int]: ... + +class D2: + @deprecated("use E2.__get__ instead") + def __get__(self, obj: Optional[C], objtype: Any) -> Union[D2, int]: ... + + @deprecated("use E2.__set__ instead") + def __set__(self, obj: C, value: int) -> None: ... + +class D3: + @overload + @deprecated("use E3.__get__ instead") + def __get__(self, obj: None, objtype: Any) -> D3: ... + @overload + @deprecated("use E3.__get__ instead") + def __get__(self, obj: C, objtype: Any) -> int: ... + def __get__(self, obj: Optional[C], objtype: Any) -> Union[D3, int]: ... + + @overload + def __set__(self, obj: C, value: int) -> None: ... + @overload + @deprecated("use E3.__set__ instead") + def __set__(self, obj: C, value: str) -> None: ... + def __set__(self, obj: C, value: Union[int, str]) -> None: ... + +class C: + d1 = D1() # E: class __main__.D1 is deprecated: use E1 instead + d2 = D2() + d3 = D3() + +c: C +C.d1 +c.d1 +c.d1 = 1 + +C.d2 # E: function __main__.D2.__get__ is deprecated: use E2.__get__ instead +c.d2 # E: function __main__.D2.__get__ is deprecated: use E2.__get__ instead +c.d2 = 1 # E: function __main__.D2.__set__ is deprecated: use E2.__set__ instead + +C.d3 # E: overload def (self: __main__.D3, obj: None, objtype: Any) -> __main__.D3 of function __main__.D3.__get__ is deprecated: use E3.__get__ instead +c.d3 # E: overload def (self: __main__.D3, obj: __main__.C, objtype: Any) -> builtins.int of function __main__.D3.__get__ is deprecated: use E3.__get__ instead +c.d3 = 1 +c.d3 = "x" # E: overload def (self: __main__.D3, obj: __main__.C, value: builtins.str) of function __main__.D3.__set__ is deprecated: use E3.__set__ instead +[builtins fixtures/property.pyi] + + +[case testDeprecatedOverloadedFunction] +# flags: --enable-error-code=deprecated + +from typing import Union +from typing_extensions import deprecated, overload + +@overload +def f(x: int) -> int: ... +@overload +def f(x: str) -> str: ... +@deprecated("use f2 instead") +def f(x: Union[int, str]) -> Union[int, str]: ... + +f # E: function __main__.f is deprecated: use f2 instead +f(1) # E: function __main__.f is deprecated: use f2 instead +f("x") # E: function __main__.f is deprecated: use f2 instead +f(1.0) # E: function __main__.f is deprecated: use f2 instead \ + # E: No overload variant of "f" matches argument type "float" \ + # N: Possible overload variants: \ + # N: def f(x: int) -> int \ + # N: def f(x: str) -> str + +@overload +@deprecated("work with str instead") +def g(x: int) -> int: ... +@overload +def g(x: str) -> str: ... +def g(x: Union[int, str]) -> Union[int, str]: ... + +g +g(1) # E: overload def (x: builtins.int) -> builtins.int of function __main__.g is deprecated: work with str instead +g("x") +g(1.0) # E: No overload variant of "g" matches argument type "float" \ + # N: Possible overload variants: \ + # N: def g(x: int) -> int \ + # N: def g(x: str) -> str + +@overload +def h(x: int) -> int: ... +@deprecated("work with int instead") +@overload # N: @overload should be placed before @deprecated +def h(x: str) -> str: ... +def h(x: Union[int, str]) -> Union[int, str]: ... + +h +h(1) +h("x") # E: overload def (x: builtins.str) -> builtins.str of function __main__.h is deprecated: work with int instead +h(1.0) # E: No overload variant of "h" matches argument type "float" \ + # N: Possible overload variants: \ + # N: def h(x: int) -> int \ + # N: def h(x: str) -> str + +[builtins fixtures/tuple.pyi] + + +[case testDeprecatedImportedOverloadedFunction] +# flags: --enable-error-code=deprecated + +import m + +m.g +m.g(1) # E: overload def (x: builtins.int) -> builtins.int of function m.g is deprecated: work with str instead +m.g("x") + +[file m.py] + +from typing import Union +from typing_extensions import deprecated, overload + +@overload +@deprecated("work with str instead") +def g(x: int) -> int: ... +@overload +def g(x: str) -> str: ... +def g(x: Union[int, str]) -> Union[int, str]: ... + +[builtins fixtures/tuple.pyi] diff --git a/test-data/unit/check-enum.test b/test-data/unit/check-enum.test index 78a114eda764..e6e42d805052 100644 --- a/test-data/unit/check-enum.test +++ b/test-data/unit/check-enum.test @@ -11,6 +11,8 @@ m = Medal.gold if int(): m = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "Medal") +[builtins fixtures/enum.pyi] + -- Creation from Enum call -- ----------------------- @@ -79,6 +81,7 @@ from typing import Generic, TypeVar T = TypeVar("T") class Medal(Generic[T], metaclass=EnumMeta): # E: Enum class cannot be generic q = None +[builtins fixtures/enum.pyi] [case testEnumNameAndValue] from enum import Enum @@ -175,6 +178,31 @@ def infer_truth(truth: Truth) -> None: reveal_type(truth.value) # N: Revealed type is "builtins.bool" [builtins fixtures/bool.pyi] +[case testEnumTruthyness] +# mypy: warn-unreachable +import enum +class E(enum.Enum): + x = 0 +if not E.x: + "noop" +[builtins fixtures/tuple.pyi] +[out] +main:6: error: Statement is unreachable + +[case testEnumTruthynessCustomDunderBool] +# mypy: warn-unreachable +import enum +from typing_extensions import Literal +class E(enum.Enum): + x = 0 + def __bool__(self) -> Literal[False]: + return False +if E.x: + "noop" +[builtins fixtures/enum.pyi] +[out] +main:9: error: Statement is unreachable + [case testEnumUnique] import enum @enum.unique @@ -183,6 +211,7 @@ class E(enum.Enum): y = 1 # NOTE: This duplicate value is not detected by mypy at the moment x = 1 x = E.x +[builtins fixtures/enum.pyi] [out] main:7: error: Incompatible types in assignment (expression has type "E", variable has type "int") @@ -197,6 +226,7 @@ if int(): s = '' if int(): s = N.y # E: Incompatible types in assignment (expression has type "N", variable has type "str") +[builtins fixtures/enum.pyi] [case testIntEnum_functionTakingIntEnum] from enum import IntEnum @@ -207,6 +237,7 @@ def takes_some_int_enum(n: SomeIntEnum): takes_some_int_enum(SomeIntEnum.x) takes_some_int_enum(1) # Error takes_some_int_enum(SomeIntEnum(1)) # How to deal with the above +[builtins fixtures/enum.pyi] [out] main:7: error: Argument 1 to "takes_some_int_enum" has incompatible type "int"; expected "SomeIntEnum" @@ -218,6 +249,7 @@ def takes_int(i: int): pass takes_int(SomeIntEnum.x) takes_int(2) +[builtins fixtures/enum.pyi] [case testIntEnum_functionReturningIntEnum] from enum import IntEnum @@ -230,6 +262,7 @@ an_int = returns_some_int_enum() an_enum = SomeIntEnum.x an_enum = returns_some_int_enum() +[builtins fixtures/enum.pyi] [out] [case testStrEnumCreation] @@ -244,6 +277,7 @@ reveal_type(MyStrEnum.x) # N: Revealed type is "Literal[__main__.MyStrEnum.x]?" reveal_type(MyStrEnum.x.value) # N: Revealed type is "Literal['x']?" reveal_type(MyStrEnum.y) # N: Revealed type is "Literal[__main__.MyStrEnum.y]?" reveal_type(MyStrEnum.y.value) # N: Revealed type is "Literal['y']?" +[builtins fixtures/enum.pyi] [out] [case testEnumMethods] @@ -278,6 +312,7 @@ takes_int(SomeExtIntEnum.x) def takes_some_ext_int_enum(s: SomeExtIntEnum): pass takes_some_ext_int_enum(SomeExtIntEnum.x) +[builtins fixtures/enum.pyi] [case testNamedTupleEnum] from typing import NamedTuple @@ -299,6 +334,7 @@ class E(IntEnum): a = 1 x: int reveal_type(E(x)) +[builtins fixtures/tuple.pyi] [out] main:5: note: Revealed type is "__main__.E" @@ -308,6 +344,7 @@ class E(IntEnum): a = 1 s: str reveal_type(E[s]) +[builtins fixtures/enum.pyi] [out] main:5: note: Revealed type is "__main__.E" @@ -317,6 +354,7 @@ class E(IntEnum): a = 1 E[1] # E: Enum index should be a string (actual index type "int") x = E[1] # E: Enum index should be a string (actual index type "int") +[builtins fixtures/enum.pyi] [case testEnumIndexIsNotAnAlias] from enum import Enum @@ -334,6 +372,7 @@ def get_member(name: str) -> E: return val reveal_type(get_member('a')) # N: Revealed type is "__main__.E" +[builtins fixtures/enum.pyi] [case testGenericEnum] from enum import Enum @@ -346,6 +385,7 @@ class F(Generic[T], Enum): # E: Enum class cannot be generic y: T reveal_type(F[int].x) # N: Revealed type is "__main__.F[builtins.int]" +[builtins fixtures/enum.pyi] [case testEnumFlag] from enum import Flag @@ -357,6 +397,7 @@ if int(): x = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "C") if int(): x = x | C.b +[builtins fixtures/enum.pyi] [case testEnumIntFlag] from enum import IntFlag @@ -368,6 +409,7 @@ if int(): x = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "C") if int(): x = x | C.b +[builtins fixtures/enum.pyi] [case testAnonymousEnum] from enum import Enum @@ -378,6 +420,7 @@ class A: self.x = E.a a = A() reveal_type(a.x) +[builtins fixtures/enum.pyi] [out] main:8: note: Revealed type is "__main__.E@4" @@ -393,6 +436,7 @@ x = A.E.a y = B.E.a if int(): x = y # E: Incompatible types in assignment (expression has type "__main__.B.E", variable has type "__main__.A.E") +[builtins fixtures/enum.pyi] [case testFunctionalEnumString] from enum import Enum, IntEnum @@ -402,6 +446,7 @@ reveal_type(E.foo) reveal_type(E.bar.value) reveal_type(I.bar) reveal_type(I.baz.value) +[builtins fixtures/enum.pyi] [out] main:4: note: Revealed type is "Literal[__main__.E.foo]?" main:5: note: Revealed type is "Any" @@ -414,6 +459,7 @@ E = Enum('E', ('foo', 'bar')) F = IntEnum('F', ['bar', 'baz']) reveal_type(E.foo) reveal_type(F.baz) +[builtins fixtures/enum.pyi] [out] main:4: note: Revealed type is "Literal[__main__.E.foo]?" main:5: note: Revealed type is "Literal[__main__.F.baz]?" @@ -426,6 +472,7 @@ reveal_type(E.foo) reveal_type(F.baz) reveal_type(E.foo.value) reveal_type(F.bar.name) +[builtins fixtures/enum.pyi] [out] main:4: note: Revealed type is "Literal[__main__.E.foo]?" main:5: note: Revealed type is "Literal[__main__.F.baz]?" @@ -440,6 +487,7 @@ reveal_type(E.foo) reveal_type(F.baz) reveal_type(E.foo.value) reveal_type(F.bar.name) +[builtins fixtures/enum.pyi] [out] main:4: note: Revealed type is "Literal[__main__.E.foo]?" main:5: note: Revealed type is "Literal[__main__.F.baz]?" @@ -455,6 +503,7 @@ fake_enum1 = Enum('fake_enum1', ['a', 'b']) fake_enum2 = Enum('fake_enum2', names=['a', 'b']) fake_enum3 = Enum(value='fake_enum3', names=['a', 'b']) fake_enum4 = Enum(value='fake_enum4', names=['a', 'b'] , module=__name__) +[builtins fixtures/enum.pyi] [case testFunctionalEnumErrors] from enum import Enum, IntEnum @@ -484,6 +533,7 @@ X = Enum('Something', 'a b') # E: String argument 1 "Something" to enum.Enum(.. reveal_type(X.a) # N: Revealed type is "Literal[__main__.Something@23.a]?" X.asdf # E: "Type[Something@23]" has no attribute "asdf" +[builtins fixtures/tuple.pyi] [typing fixtures/typing-medium.pyi] [case testFunctionalEnumFlag] @@ -498,6 +548,7 @@ reveal_type(B.a.name) # N: Revealed type is "Literal['a']?" # TODO: The revealed type should be 'int' here reveal_type(A.x.value) # N: Revealed type is "Any" reveal_type(B.a.value) # N: Revealed type is "Any" +[builtins fixtures/enum.pyi] [case testAnonymousFunctionalEnum] from enum import Enum @@ -507,6 +558,7 @@ class A: self.x = E.a a = A() reveal_type(a.x) +[builtins fixtures/enum.pyi] [out] main:7: note: Revealed type is "__main__.A.E@4" @@ -520,6 +572,7 @@ x = A.E.a y = B.E.a if int(): x = y # E: Incompatible types in assignment (expression has type "__main__.B.E", variable has type "__main__.A.E") +[builtins fixtures/enum.pyi] [case testFunctionalEnumProtocols] from enum import IntEnum @@ -537,6 +590,7 @@ a: E = E.x # type: ignore[used-before-def] class E(Enum): x = 1 y = 2 +[builtins fixtures/enum.pyi] [out] [case testEnumWorkWithForward2] @@ -547,6 +601,7 @@ F = Enum('F', {'x': 1, 'y': 2}) def fn(x: F) -> None: pass fn(b) +[builtins fixtures/enum.pyi] [out] [case testFunctionalEnum] @@ -564,6 +619,7 @@ Gu.a Gb.a Hu.a Hb.a +[builtins fixtures/enum.pyi] [out] [case testEnumIncremental] @@ -576,6 +632,7 @@ class E(Enum): a = 1 b = 2 F = Enum('F', 'a b') +[builtins fixtures/enum.pyi] [rechecked] [stale] [out1] @@ -734,6 +791,7 @@ class SomeEnum(Enum): from enum import Enum class SomeEnum(Enum): a = "foo" +[builtins fixtures/enum.pyi] [out] main:2: note: Revealed type is "Literal[1]?" [out2] @@ -757,7 +815,7 @@ elif x is Foo.C: reveal_type(x) # N: Revealed type is "Literal[__main__.Foo.C]" else: reveal_type(x) # No output here: this branch is unreachable -reveal_type(x) # N: Revealed type is "__main__.Foo" +reveal_type(x) # N: Revealed type is "Union[Literal[__main__.Foo.A], Literal[__main__.Foo.B], Literal[__main__.Foo.C]]" if Foo.A is x: reveal_type(x) # N: Revealed type is "Literal[__main__.Foo.A]" @@ -767,7 +825,7 @@ elif Foo.C is x: reveal_type(x) # N: Revealed type is "Literal[__main__.Foo.C]" else: reveal_type(x) # No output here: this branch is unreachable -reveal_type(x) # N: Revealed type is "__main__.Foo" +reveal_type(x) # N: Revealed type is "Union[Literal[__main__.Foo.A], Literal[__main__.Foo.B], Literal[__main__.Foo.C]]" y: Foo if y is Foo.A: @@ -949,7 +1007,7 @@ x: Optional[Foo] if x: reveal_type(x) # N: Revealed type is "__main__.Foo" else: - reveal_type(x) # N: Revealed type is "Union[__main__.Foo, None]" + reveal_type(x) # N: Revealed type is "None" if x is not None: reveal_type(x) # N: Revealed type is "__main__.Foo" @@ -961,7 +1019,7 @@ if x is Foo.A: else: reveal_type(x) # N: Revealed type is "Union[Literal[__main__.Foo.B], Literal[__main__.Foo.C], None]" reveal_type(x) # N: Revealed type is "Union[__main__.Foo, None]" -[builtins fixtures/bool.pyi] +[builtins fixtures/enum.pyi] [case testEnumReachabilityWithMultipleEnums] from enum import Enum @@ -1104,6 +1162,7 @@ class A: self.b = Enum("b", [("foo", "bar")]) # E: Enum type as attribute is not supported reveal_type(A().b) # N: Revealed type is "Any" +[builtins fixtures/enum.pyi] [case testEnumReachabilityWithChaining] from enum import Enum @@ -1307,6 +1366,7 @@ class Foo(Enum): a = Foo.A reveal_type(a.value) # N: Revealed type is "Union[Literal[1]?, Literal[2]?]" reveal_type(a._value_) # N: Revealed type is "Union[Literal[1]?, Literal[2]?]" +[builtins fixtures/enum.pyi] [case testNewSetsUnexpectedValueType] from enum import Enum @@ -1325,7 +1385,7 @@ class Foo(bytes, Enum): a = Foo.A reveal_type(a.value) # N: Revealed type is "Any" reveal_type(a._value_) # N: Revealed type is "Any" -[builtins fixtures/primitives.pyi] +[builtins fixtures/tuple.pyi] [typing fixtures/typing-medium.pyi] [case testValueTypeWithNewInParentClass] @@ -1398,6 +1458,7 @@ class E(IntEnum): A = N(0) reveal_type(E.A.value) # N: Revealed type is "__main__.N" +[builtins fixtures/enum.pyi] [case testEnumFinalValues] @@ -1410,6 +1471,7 @@ class Medal(Enum): Medal.gold = 0 # E: Cannot assign to final attribute "gold" # Same value: Medal.silver = 2 # E: Cannot assign to final attribute "silver" +[builtins fixtures/enum.pyi] [case testEnumFinalValuesCannotRedefineValueProp] @@ -1417,6 +1479,7 @@ from enum import Enum class Types(Enum): key = 0 value = 1 +[builtins fixtures/enum.pyi] [case testEnumReusedKeys] @@ -1764,7 +1827,8 @@ class B(A): x = 1 # E: Cannot override writable attribute "x" with a final one class A1(Enum): - x: int = 1 + x: int = 1 # E: Enum members must be left unannotated \ + # N: See https://typing.readthedocs.io/en/latest/spec/enums.html#defining-members class B1(A1): # E: Cannot extend enum with existing members: "A1" pass @@ -1779,6 +1843,7 @@ class A3(Enum): x: Final[int] # type: ignore class B3(A3): x = 1 # E: Cannot override final attribute "x" (previously declared in base class "A3") + [builtins fixtures/bool.pyi] [case testEnumNotFinalWithMethodsAndUninitializedValuesStub] @@ -1786,14 +1851,17 @@ import lib [file lib.pyi] from enum import Enum -class A(Enum): +class A(Enum): # E: Detected enum "lib.A" in a type stub with zero members. There is a chance this is due to a recent change in the semantics of enum membership. If so, use `member = value` to mark an enum member, instead of `member: type` \ + # N: See https://typing.readthedocs.io/en/latest/spec/enums.html#defining-members x: int class B(A): # E: Cannot extend enum with existing members: "A" x = 1 # E: Cannot override writable attribute "x" with a final one class C(Enum): x = 1 -class D(C): # E: Cannot extend enum with existing members: "C" +class D(C): # E: Cannot extend enum with existing members: "C" \ + # E: Detected enum "lib.D" in a type stub with zero members. There is a chance this is due to a recent change in the semantics of enum membership. If so, use `member = value` to mark an enum member, instead of `member: type` \ + # N: See https://typing.readthedocs.io/en/latest/spec/enums.html#defining-members x: int # E: Cannot assign to final name "x" [builtins fixtures/bool.pyi] @@ -2030,7 +2098,7 @@ class C(Enum): _ignore_ = 'X' C._ignore_ # E: "Type[C]" has no attribute "_ignore_" -[typing fixtures/typing-medium.pyi] +[builtins fixtures/enum.pyi] [case testCanOverrideDunderAttributes] import typing @@ -2109,6 +2177,7 @@ class AllPartialList(Enum): def check(self) -> None: reveal_type(self.value) # N: Revealed type is "builtins.list[Any]" +[builtins fixtures/tuple.pyi] [case testEnumPrivateAttributeNotMember] from enum import Enum @@ -2120,6 +2189,7 @@ class MyEnum(Enum): # TODO: change the next line to use MyEnum._MyEnum__my_dict when mypy implements name mangling x: MyEnum = MyEnum.__my_dict # E: Incompatible types in assignment (expression has type "Dict[int, str]", variable has type "MyEnum") +[builtins fixtures/enum.pyi] [case testEnumWithPrivateAttributeReachability] # flags: --warn-unreachable @@ -2185,3 +2255,69 @@ reveal_type(A.y.value) # N: Revealed type is "Literal[2]?" def some_a(a: A): reveal_type(a.value) # N: Revealed type is "Union[Literal[1]?, Literal[2]?]" [builtins fixtures/dict.pyi] + + +[case testErrorOnAnnotatedMember] +from enum import Enum + +class Medal(Enum): + gold: int = 1 # E: Enum members must be left unannotated \ + # N: See https://typing.readthedocs.io/en/latest/spec/enums.html#defining-members + silver: str = 2 # E: Enum members must be left unannotated \ + # N: See https://typing.readthedocs.io/en/latest/spec/enums.html#defining-members \ + # E: Incompatible types in assignment (expression has type "int", variable has type "str") + bronze = 3 +[builtins fixtures/enum.pyi] + +[case testEnumMemberWithPlaceholder] +from enum import Enum + +class Pet(Enum): + CAT = ... + DOG: str = ... # E: Enum members must be left unannotated \ + # N: See https://typing.readthedocs.io/en/latest/spec/enums.html#defining-members \ + # E: Incompatible types in assignment (expression has type "ellipsis", variable has type "str") +[builtins fixtures/enum.pyi] + +[case testEnumValueWithPlaceholderNodeType] +# https://github.com/python/mypy/issues/11971 +from enum import Enum +from typing import Any, Callable, Dict +class Foo(Enum): + Bar: Foo = Callable[[str], None] # E: Enum members must be left unannotated \ + # N: See https://typing.readthedocs.io/en/latest/spec/enums.html#defining-members \ + # E: Incompatible types in assignment (expression has type "", variable has type "Foo") + Baz: Any = Callable[[Dict[str, "Missing"]], None] # E: Enum members must be left unannotated \ + # N: See https://typing.readthedocs.io/en/latest/spec/enums.html#defining-members \ + # E: Type application targets a non-generic function or class \ + # E: Name "Missing" is not defined + +reveal_type(Foo.Bar) # N: Revealed type is "Literal[__main__.Foo.Bar]?" +reveal_type(Foo.Bar.value) # N: Revealed type is "__main__.Foo" +reveal_type(Foo.Baz) # N: Revealed type is "Literal[__main__.Foo.Baz]?" +reveal_type(Foo.Baz.value) # N: Revealed type is "Any" +[builtins fixtures/tuple.pyi] +[typing fixtures/typing-full.pyi] + + +[case testEnumWithOnlyImplicitMembersUsingAnnotationOnly] +# flags: --warn-unreachable +import enum + + +class E(enum.IntEnum): + A: int + B: int + + +def do_check(value: E) -> None: + reveal_type(value) # N: Revealed type is "__main__.E" + # this is a nonmember check, not an emum member check, and it should not narrow the value + if value is E.A: + return + + reveal_type(value) # N: Revealed type is "__main__.E" + "should be reachable" + +[builtins fixtures/primitives.pyi] +[typing fixtures/typing-full.pyi] diff --git a/test-data/unit/check-expressions.test b/test-data/unit/check-expressions.test index d5ddc910bcd6..cd26c9bb408a 100644 --- a/test-data/unit/check-expressions.test +++ b/test-data/unit/check-expressions.test @@ -1178,8 +1178,8 @@ class B: pass [case testSlicingWithInvalidBase] a: A -a[1:2] # E: Invalid index type "slice" for "A"; expected type "int" -a[:] # E: Invalid index type "slice" for "A"; expected type "int" +a[1:2] # E: Invalid index type "slice[int, int, None]" for "A"; expected type "int" +a[:] # E: Invalid index type "slice[None, None, None]" for "A"; expected type "int" class A: def __getitem__(self, n: int) -> 'A': pass [builtins fixtures/slice.pyi] diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test index 4f327a2f0edc..c6419923ebc6 100644 --- a/test-data/unit/check-flags.test +++ b/test-data/unit/check-flags.test @@ -79,6 +79,13 @@ async def g(x: int) -> Any: [builtins fixtures/async_await.pyi] [typing fixtures/typing-async.pyi] +[case testDisallowUntypedDefsAndGeneric] +# flags: --disallow-untyped-defs --disallow-any-generics +def get_tasks(self): + return 'whatever' +[out] +main:2: error: Function is missing a return type annotation + [case testDisallowUntypedDefsUntypedDecorator] # flags: --disallow-untyped-decorators def d(p): @@ -540,21 +547,30 @@ tmp/b.py:1: error: Unsupported operand types for + ("int" and "str") [case testFollowImportsNormal] # flags: --follow-imports=normal from mod import x -x + "" +x + 0 +x + "" # E: Unsupported operand types for + ("int" and "str") +import mod +mod.x + 0 +mod.x + "" # E: Unsupported operand types for + ("int" and "str") +mod.y # E: "object" has no attribute "y" +mod + 0 # E: Unsupported left operand type for + ("object") [file mod.py] -1 + "" +1 + "" # E: Unsupported operand types for + ("int" and "str") x = 0 -[out] -tmp/mod.py:1: error: Unsupported operand types for + ("int" and "str") -main:3: error: Unsupported operand types for + ("int" and "str") +x += "" # E: Unsupported operand types for + ("int" and "str") [case testFollowImportsSilent] # flags: --follow-imports=silent from mod import x x + "" # E: Unsupported operand types for + ("int" and "str") +import mod +mod.x + "" # E: Unsupported operand types for + ("int" and "str") +mod.y # E: "object" has no attribute "y" +mod + 0 # E: Unsupported left operand type for + ("object") [file mod.py] 1 + "" x = 0 +x += "" [case testFollowImportsSilentTypeIgnore] # flags: --warn-unused-ignores --follow-imports=silent @@ -565,20 +581,55 @@ x = 3 # type: ignore [case testFollowImportsSkip] # flags: --follow-imports=skip from mod import x +reveal_type(x) # N: Revealed type is "Any" x + "" +import mod +reveal_type(mod.x) # N: Revealed type is "Any" [file mod.py] this deliberate syntax error will not be reported -[out] [case testFollowImportsError] # flags: --follow-imports=error -from mod import x +from mod import x # E: Import of "mod" ignored \ + # N: (Using --follow-imports=error, module not passed on command line) x + "" +reveal_type(x) # N: Revealed type is "Any" +import mod +reveal_type(mod.x) # N: Revealed type is "Any" [file mod.py] deliberate syntax error -[out] -main:2: error: Import of "mod" ignored -main:2: note: (Using --follow-imports=error, module not passed on command line) + +[case testFollowImportsSelective] +# flags: --config-file tmp/mypy.ini +import normal +import silent +import skip +import error # E: Import of "error" ignored \ + # N: (Using --follow-imports=error, module not passed on command line) +reveal_type(normal.x) # N: Revealed type is "builtins.int" +reveal_type(silent.x) # N: Revealed type is "builtins.int" +reveal_type(skip) # N: Revealed type is "Any" +reveal_type(error) # N: Revealed type is "Any" +[file mypy.ini] +\[mypy] +\[mypy-normal] +follow_imports = normal +\[mypy-silent] +follow_imports = silent +\[mypy-skip] +follow_imports = skip +\[mypy-error] +follow_imports = error +[file normal.py] +x = 0 +x += '' # E: Unsupported operand types for + ("int" and "str") +[file silent.py] +x = 0 +x += '' +[file skip.py] +bla bla +[file error.py] +bla bla [case testIgnoreMissingImportsFalse] from mod import x @@ -591,6 +642,15 @@ main:1: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missin from mod import x [out] +[case testNoConfigFile] +# flags: --config-file= +# type: ignore + +[file mypy.ini] +\[mypy] +warn_unused_ignores = True +[out] + [case testPerFileIncompleteDefsBasic] # flags: --config-file tmp/mypy.ini import standard, incomplete @@ -868,6 +928,16 @@ implicit_optional = true module = 'optional' strict_optional = true +[case testSilentMissingImportsOff] +-- ignore_missing_imports is False by default. +import missing # E: Cannot find implementation or library stub for module named "missing" \ + # N: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports +reveal_type(missing.x) # N: Revealed type is "Any" + +[case testSilentMissingImportsOn] +# flags: --ignore-missing-imports +import missing +reveal_type(missing.x) # N: Revealed type is "Any" [case testDisallowImplicitTypesIgnoreMissingTypes] # flags: --ignore-missing-imports --disallow-any-unimported @@ -893,6 +963,12 @@ from missing import Unchecked t: Unchecked = 12 # E: Type of variable becomes "Any" due to an unfollowed import +[case testAllowImplicitAnyVariableDefinition] +# flags: --ignore-missing-imports --allow-any-unimported +from missing import Unchecked + +t: Unchecked = 12 + [case testDisallowImplicitAnyGeneric] # flags: --ignore-missing-imports --disallow-any-unimported from missing import Unchecked @@ -1447,6 +1523,29 @@ class Queue(Generic[_T]): ... [builtins fixtures/async_await.pyi] [typing fixtures/typing-full.pyi] +[case testDisallowAnyGenericsBuiltinTuplePre39] +# flags: --disallow-any-generics --python-version 3.8 +s = tuple([1, 2, 3]) +def f(t: tuple) -> None: pass # E: Implicit generic "Any". Use "typing.Tuple" and specify generic parameters +[builtins fixtures/tuple.pyi] + +[case testDisallowAnyGenericsBuiltinListPre39] +# flags: --disallow-any-generics --python-version 3.8 +l = list([1, 2, 3]) +def f(t: list) -> None: pass # E: Implicit generic "Any". Use "typing.List" and specify generic parameters +[builtins fixtures/list.pyi] + +[case testDisallowAnyGenericsBuiltinSetPre39] +# flags: --disallow-any-generics --python-version 3.8 +l = set({1, 2, 3}) +def f(s: set) -> None: pass # E: Implicit generic "Any". Use "typing.Set" and specify generic parameters +[builtins fixtures/set.pyi] + +[case testDisallowAnyGenericsBuiltinDictPre39] +# flags: --disallow-any-generics --python-version 3.8 +l = dict([('a', 1)]) +def f(d: dict) -> None: pass # E: Implicit generic "Any". Use "typing.Dict" and specify generic parameters +[builtins fixtures/dict.pyi] [case testCheckDefaultAllowAnyGeneric] from typing import TypeVar, Callable @@ -1863,8 +1962,9 @@ x: Tuple = () # E: Missing type parameters for generic type "Tuple" # flags: --disallow-any-generics from typing import Tuple, List -def f(s: List[Tuple]) -> None: pass # E: Missing type parameters for generic type "Tuple" -def g(s: List[Tuple[str, str]]) -> None: pass # no error +def f(s: Tuple) -> None: pass # E: Missing type parameters for generic type "Tuple" +def g(s: List[Tuple]) -> None: pass # E: Missing type parameters for generic type "Tuple" +def h(s: List[Tuple[str, str]]) -> None: pass # no error [builtins fixtures/list.pyi] [case testDisallowAnyGenericsTypeType] @@ -1908,14 +2008,36 @@ x: A = ('a', 'b', 1) # E: Missing type parameters for generic type "A" from typing import List def f(l: List) -> None: pass # E: Missing type parameters for generic type "List" -def g(l: List[str]) -> None: pass # no error +def g(l: List[str]) -> None: pass def h(l: List[List]) -> None: pass # E: Missing type parameters for generic type "List" def i(l: List[List[List[List]]]) -> None: pass # E: Missing type parameters for generic type "List" +def j() -> List: pass # E: Missing type parameters for generic type "List" x = [] # E: Need type annotation for "x" (hint: "x: List[] = ...") y: List = [] # E: Missing type parameters for generic type "List" [builtins fixtures/list.pyi] +[case testDisallowAnyGenericsPlainDict] +# flags: --disallow-any-generics +from typing import List, Dict + +def f(d: Dict) -> None: pass # E: Missing type parameters for generic type "Dict" +def g(d: Dict[str, Dict]) -> None: pass # E: Missing type parameters for generic type "Dict" +def h(d: List[Dict]) -> None: pass # E: Missing type parameters for generic type "Dict" + +d: Dict = {} # E: Missing type parameters for generic type "Dict" +[builtins fixtures/dict.pyi] + +[case testDisallowAnyGenericsPlainSet] +# flags: --disallow-any-generics +from typing import Set + +def f(s: Set) -> None: pass # E: Missing type parameters for generic type "Set" +def g(s: Set[Set]) -> None: pass # E: Missing type parameters for generic type "Set" + +s: Set = set() # E: Missing type parameters for generic type "Set" +[builtins fixtures/set.pyi] + [case testDisallowAnyGenericsCustomGenericClass] # flags: --disallow-any-generics from typing import Generic, TypeVar, Any @@ -2162,6 +2284,38 @@ allow_untyped_defs = True allow_untyped_calls = True disable_error_code = var-annotated +[case testPerFileIgnoreErrors] +# flags: --config-file tmp/mypy.ini +import foo, bar +[file foo.py] +x: str = 5 +[file bar.py] +x: str = 5 # E: Incompatible types in assignment (expression has type "int", variable has type "str") +[file mypy.ini] +\[mypy] +\[mypy-foo] +ignore_errors = True + +[case testPerFileUntypedDefs] +# flags: --config-file tmp/mypy.ini +import x, y, z +[file x.py] +def f(a): ... # E: Function is missing a type annotation +def g(a: int) -> int: return f(a) +[file y.py] +def f(a): pass +def g(a: int) -> int: return f(a) +[file z.py] +def f(a): pass # E: Function is missing a type annotation +def g(a: int) -> int: return f(a) # E: Call to untyped function "f" in typed context +[file mypy.ini] +\[mypy] +disallow_untyped_defs = True +\[mypy-y] +disallow_untyped_defs = False +\[mypy-z] +disallow_untyped_calls = True + [case testPerModuleErrorCodesOverride] # flags: --config-file tmp/mypy.ini import tests.foo @@ -2284,3 +2438,8 @@ class C(Generic[T]): ... A = Union[C, List] # OK [builtins fixtures/list.pyi] + +[case testNotesOnlyResultInExitSuccess] +-- check_untyped_defs is False by default. +def f(): + x: int = "no" # N: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs diff --git a/test-data/unit/check-functions.test b/test-data/unit/check-functions.test index 96f9815019e6..b8a02a1ec7d4 100644 --- a/test-data/unit/check-functions.test +++ b/test-data/unit/check-functions.test @@ -1474,7 +1474,7 @@ def dec(f) -> Callable[[int], None]: pass x = int() if x: - def f(x: int) -> None: pass + def f(x: int, /) -> None: pass else: @dec def f(): pass @@ -1489,9 +1489,12 @@ x = int() if x: def f(x: str) -> None: pass else: - # TODO: Complain about incompatible redefinition @dec - def f(): pass + def f(): pass # E: All conditional function variants must have identical signatures \ + # N: Original: \ + # N: def f(x: str) -> None \ + # N: Redefinition: \ + # N: def f(int, /) -> None [case testConditionalFunctionDefinitionUnreachable] def bar() -> None: @@ -1599,7 +1602,7 @@ else: def f(): yield [file m.py] -def f(): pass +def f() -> None: pass [case testDefineConditionallyAsImportedAndDecoratedWithInference] if int(): diff --git a/test-data/unit/check-functools.test b/test-data/unit/check-functools.test index 9f8fbd42440b..c1868b3e3d72 100644 --- a/test-data/unit/check-functools.test +++ b/test-data/unit/check-functools.test @@ -215,7 +215,7 @@ def bar(*a: bytes, **k: int): p1("a", d="a", **k) p1("a", **k) # E: Argument 2 to "foo" has incompatible type "**Dict[str, int]"; expected "str" p1(**k) # E: Argument 1 to "foo" has incompatible type "**Dict[str, int]"; expected "str" - p1(*a) # E: List or tuple expected as variadic arguments + p1(*a) # E: Expected iterable as variadic argument def baz(a: int, b: int) -> int: ... @@ -223,6 +223,8 @@ def test_baz(xs: List[int]): p3 = functools.partial(baz, *xs) p3() p3(1) # E: Too many arguments for "baz" + + [builtins fixtures/dict.pyi] [case testFunctoolsPartialGeneric] @@ -346,15 +348,32 @@ fn1: Union[Callable[[int], int], Callable[[int], int]] reveal_type(functools.partial(fn1, 2)()) # N: Revealed type is "builtins.int" fn2: Union[Callable[[int], int], Callable[[int], str]] -reveal_type(functools.partial(fn2, 2)()) # N: Revealed type is "builtins.object" +reveal_type(functools.partial(fn2, 2)()) # N: Revealed type is "Union[builtins.int, builtins.str]" fn3: Union[Callable[[int], int], str] reveal_type(functools.partial(fn3, 2)()) # E: "str" not callable \ - # E: "Union[Callable[[int], int], str]" not callable \ # N: Revealed type is "builtins.int" \ # E: Argument 1 to "partial" has incompatible type "Union[Callable[[int], int], str]"; expected "Callable[..., int]" [builtins fixtures/tuple.pyi] +[case testFunctoolsPartialUnionOfTypeAndCallable] +import functools +from typing import Callable, Union, Type +from typing_extensions import TypeAlias + +class FooBar: + def __init__(self, arg1: str) -> None: + pass + +def f1(t: Union[Type[FooBar], Callable[..., 'FooBar']]) -> None: + val = functools.partial(t) + +FooBarFunc: TypeAlias = Callable[..., 'FooBar'] + +def f2(t: Union[Type[FooBar], FooBarFunc]) -> None: + val = functools.partial(t) +[builtins fixtures/tuple.pyi] + [case testFunctoolsPartialExplicitType] from functools import partial from typing import Type, TypeVar, Callable @@ -557,3 +576,66 @@ def bar(f: S) -> S: g = functools.partial(f, "foo") return f [builtins fixtures/primitives.pyi] + +[case testFunctoolsPartialAbstractType] +# flags: --python-version 3.9 +from abc import ABC, abstractmethod +from functools import partial + +class A(ABC): + def __init__(self) -> None: ... + @abstractmethod + def method(self) -> None: ... + +def f1(cls: type[A]) -> None: + cls() + partial_cls = partial(cls) + partial_cls() + +def f2() -> None: + A() # E: Cannot instantiate abstract class "A" with abstract attribute "method" + partial_cls = partial(A) # E: Cannot instantiate abstract class "A" with abstract attribute "method" + partial_cls() # E: Cannot instantiate abstract class "A" with abstract attribute "method" +[builtins fixtures/tuple.pyi] + +[case testFunctoolsPartialSelfType] +from functools import partial +from typing_extensions import Self + +class A: + def __init__(self, ts: float, msg: str) -> None: ... + + @classmethod + def from_msg(cls, msg: str) -> Self: + factory = partial(cls, ts=0) + return factory(msg=msg) +[builtins fixtures/tuple.pyi] + +[case testFunctoolsPartialTypeVarValues] +from functools import partial +from typing import TypeVar + +T = TypeVar("T", int, str) + +def f(x: int, y: T) -> T: + return y + +def g(x: T, y: int) -> T: + return x + +def h(x: T, y: T) -> T: + return x + +fp = partial(f, 1) +reveal_type(fp(1)) # N: Revealed type is "builtins.int" +reveal_type(fp("a")) # N: Revealed type is "builtins.str" +fp(object()) # E: Value of type variable "T" of "f" cannot be "object" + +gp = partial(g, 1) +reveal_type(gp(1)) # N: Revealed type is "builtins.int" +gp("a") # E: Argument 1 to "g" has incompatible type "str"; expected "int" + +hp = partial(h, 1) +reveal_type(hp(1)) # N: Revealed type is "builtins.int" +hp("a") # E: Argument 1 to "h" has incompatible type "str"; expected "int" +[builtins fixtures/tuple.pyi] diff --git a/test-data/unit/check-incremental.test b/test-data/unit/check-incremental.test index 173265e48e6f..888b4c26a7c7 100644 --- a/test-data/unit/check-incremental.test +++ b/test-data/unit/check-incremental.test @@ -6586,6 +6586,7 @@ class TheClass: for x in names }) self.enum_type = pyenum +[builtins fixtures/tuple.pyi] [out] [out2] tmp/a.py:3: note: Revealed type is "def (value: builtins.object) -> lib.TheClass.pyenum@6" diff --git a/test-data/unit/check-inference.test b/test-data/unit/check-inference.test index 0dbefbc774a3..5a99e65c9c90 100644 --- a/test-data/unit/check-inference.test +++ b/test-data/unit/check-inference.test @@ -1238,6 +1238,35 @@ class B: pass [builtins fixtures/for.pyi] [out] +[case testForStatementIndexNarrowing] +from typing_extensions import TypedDict + +class X(TypedDict): + hourly: int + daily: int + +x: X +for a in ("hourly", "daily"): + reveal_type(a) # N: Revealed type is "Union[Literal['hourly']?, Literal['daily']?]" + reveal_type(x[a]) # N: Revealed type is "builtins.int" + reveal_type(a.upper()) # N: Revealed type is "builtins.str" + c = a + reveal_type(c) # N: Revealed type is "builtins.str" + a = "monthly" + reveal_type(a) # N: Revealed type is "builtins.str" + a = "yearly" + reveal_type(a) # N: Revealed type is "builtins.str" + a = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "str") + reveal_type(a) # N: Revealed type is "builtins.str" + d = a + reveal_type(d) # N: Revealed type is "builtins.str" + +b: str +for b in ("hourly", "daily"): + reveal_type(b) # N: Revealed type is "builtins.str" + reveal_type(b.upper()) # N: Revealed type is "builtins.str" +[builtins fixtures/for.pyi] + -- Regression tests -- ---------------- @@ -3648,7 +3677,8 @@ def f(x: Call[T]) -> Tuple[T, T]: ... def g(__x: str) -> None: pass reveal_type(f(g)) # N: Revealed type is "Tuple[Never, Never]" \ - # E: Argument 1 to "f" has incompatible type "Callable[[str], None]"; expected "Call[Never]" + # E: Argument 1 to "f" has incompatible type "Callable[[str], None]"; expected "Call[Never]" \ + # N: "Call[Never].__call__" has type "Callable[[NamedArg(Never, 'x')], None]" [builtins fixtures/list.pyi] [case testCallableInferenceAgainstCallableNamedVsPosOnly] @@ -3664,7 +3694,8 @@ def f(x: Call[T]) -> Tuple[T, T]: ... def g(*, x: str) -> None: pass reveal_type(f(g)) # N: Revealed type is "Tuple[Never, Never]" \ - # E: Argument 1 to "f" has incompatible type "Callable[[NamedArg(str, 'x')], None]"; expected "Call[Never]" + # E: Argument 1 to "f" has incompatible type "Callable[[NamedArg(str, 'x')], None]"; expected "Call[Never]" \ + # N: "Call[Never].__call__" has type "Callable[[Never], None]" [builtins fixtures/list.pyi] [case testCallableInferenceAgainstCallablePosOnlyVsKwargs] @@ -3680,7 +3711,8 @@ def f(x: Call[T]) -> Tuple[T, T]: ... def g(**x: str) -> None: pass reveal_type(f(g)) # N: Revealed type is "Tuple[Never, Never]" \ - # E: Argument 1 to "f" has incompatible type "Callable[[KwArg(str)], None]"; expected "Call[Never]" + # E: Argument 1 to "f" has incompatible type "Callable[[KwArg(str)], None]"; expected "Call[Never]" \ + # N: "Call[Never].__call__" has type "Callable[[Never], None]" [builtins fixtures/list.pyi] [case testCallableInferenceAgainstCallableNamedVsArgs] @@ -3696,7 +3728,8 @@ def f(x: Call[T]) -> Tuple[T, T]: ... def g(*args: str) -> None: pass reveal_type(f(g)) # N: Revealed type is "Tuple[Never, Never]" \ - # E: Argument 1 to "f" has incompatible type "Callable[[VarArg(str)], None]"; expected "Call[Never]" + # E: Argument 1 to "f" has incompatible type "Callable[[VarArg(str)], None]"; expected "Call[Never]" \ + # N: "Call[Never].__call__" has type "Callable[[NamedArg(Never, 'x')], None]" [builtins fixtures/list.pyi] [case testInferenceAgainstTypeVarActualBound] diff --git a/test-data/unit/check-isinstance.test b/test-data/unit/check-isinstance.test index 8fa1bc1ca1ac..99bd62765b11 100644 --- a/test-data/unit/check-isinstance.test +++ b/test-data/unit/check-isinstance.test @@ -2207,23 +2207,24 @@ def foo2(x: Optional[str]) -> None: reveal_type(x) # N: Revealed type is "builtins.str" [builtins fixtures/isinstance.pyi] -[case testNoneCheckDoesNotNarrowWhenUsingTypeVars] - -# Note: this test (and the following one) are testing checker.conditional_type_map: -# if you set the 'prohibit_none_typevar_overlap' keyword argument to False when calling -# 'is_overlapping_types', the binder will incorrectly infer that 'out' has a type of -# Union[T, None] after the if statement. - +[case testNoneCheckDoesNotMakeTypeVarOptional] from typing import TypeVar T = TypeVar('T') -def foo(x: T) -> T: +def foo_if(x: T) -> T: out = None out = x if out is None: pass return out + +def foo_while(x: T) -> T: + out = None + out = x + while out is None: + pass + return out [builtins fixtures/isinstance.pyi] [case testNoneCheckDoesNotNarrowWhenUsingTypeVarsNoStrictOptional] diff --git a/test-data/unit/check-kwargs.test b/test-data/unit/check-kwargs.test index 4beac047e278..3a8c7f5ba454 100644 --- a/test-data/unit/check-kwargs.test +++ b/test-data/unit/check-kwargs.test @@ -358,6 +358,9 @@ f(**d) # E: Keywords must be strings f(**A()) # E: Argument after ** must be a mapping, not "A" kwargs: Optional[Any] f(**kwargs) # E: Argument after ** must be a mapping, not "Optional[Any]" + +def g(a: int) -> None: pass +g(a=1, **4) # E: Argument after ** must be a mapping, not "int" [builtins fixtures/dict.pyi] [case testPassingKeywordVarArgsToNonVarArgsFunction] diff --git a/test-data/unit/check-literal.test b/test-data/unit/check-literal.test index 6d76ce176aaf..2f94b5df0f83 100644 --- a/test-data/unit/check-literal.test +++ b/test-data/unit/check-literal.test @@ -2960,3 +2960,27 @@ class C(B[Literal["word"]]): reveal_type(C().collection) # N: Revealed type is "builtins.list[Literal['word']]" reveal_type(C().word) # N: Revealed type is "Literal['word']" [builtins fixtures/tuple.pyi] + +[case testLiteralTernaryUnionNarrowing] +from typing_extensions import Literal +from typing import Optional + +SEP = Literal["a", "b"] + +class Base: + def feed_data( + self, + sep: SEP, + ) -> int: + return 0 + +class C(Base): + def feed_data( + self, + sep: Optional[SEP] = None, + ) -> int: + if sep is None: + sep = "a" if int() else "b" + reveal_type(sep) # N: Revealed type is "Union[Literal['a'], Literal['b']]" + return super().feed_data(sep) +[builtins fixtures/tuple.pyi] diff --git a/test-data/unit/check-modules.test b/test-data/unit/check-modules.test index 5fd48577e436..68897790e4bf 100644 --- a/test-data/unit/check-modules.test +++ b/test-data/unit/check-modules.test @@ -3136,15 +3136,12 @@ import google.cloud.ndb # E: Library stubs not installed for "google.cloud.ndb" from google.cloud import ndb [case testMissingSubmoduleOfInstalledStubPackage] -import bleach.xyz -from bleach.abc import fgh +import bleach.exists +import bleach.xyz # E: Cannot find implementation or library stub for module named "bleach.xyz" \ + # N: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports +from bleach.abc import fgh # E: Cannot find implementation or library stub for module named "bleach.abc" [file bleach/__init__.pyi] -[out] -main:1: error: Library stubs not installed for "bleach.xyz" -main:1: note: Hint: "python3 -m pip install types-bleach" -main:1: note: (or run "mypy --install-types" to install all missing stub packages) -main:1: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports -main:2: error: Library stubs not installed for "bleach.abc" +[file bleach/exists.pyi] [case testMissingSubmoduleOfInstalledStubPackageIgnored] # flags: --ignore-missing-imports diff --git a/test-data/unit/check-narrowing.test b/test-data/unit/check-narrowing.test index 60fc39dd817b..285d56ff7e50 100644 --- a/test-data/unit/check-narrowing.test +++ b/test-data/unit/check-narrowing.test @@ -1385,9 +1385,9 @@ val: Optional[A] if val == None: reveal_type(val) # N: Revealed type is "Union[__main__.A, None]" else: - reveal_type(val) # N: Revealed type is "Union[__main__.A, None]" + reveal_type(val) # N: Revealed type is "__main__.A" if val != None: - reveal_type(val) # N: Revealed type is "Union[__main__.A, None]" + reveal_type(val) # N: Revealed type is "__main__.A" else: reveal_type(val) # N: Revealed type is "Union[__main__.A, None]" @@ -2291,3 +2291,64 @@ def f4(x: SE) -> None: else: reveal_type(x) # N: Revealed type is "Literal[__main__.SE.B]" [builtins fixtures/primitives.pyi] + +[case testConsistentNarrowingEqAndIn] +# flags: --python-version 3.10 + +# https://github.com/python/mypy/issues/17864 +def f(x: str | int) -> None: + if x == "x": + reveal_type(x) # N: Revealed type is "Union[builtins.str, builtins.int]" + y = x + + if x in ["x"]: + # TODO: we should fix this reveal https://github.com/python/mypy/issues/3229 + reveal_type(x) # N: Revealed type is "Union[builtins.str, builtins.int]" + y = x + z = x + z = y +[builtins fixtures/primitives.pyi] + +[case testConsistentNarrowingInWithCustomEq] +# flags: --python-version 3.10 + +# https://github.com/python/mypy/issues/17864 +class C: + def __init__(self, x: int) -> None: + self.x = x + + def __eq__(self, other: object) -> bool: + raise + # Example implementation: + # if isinstance(other, C) and other.x == self.x: + # return True + # return NotImplemented + +class D(C): + pass + +def f(x: C) -> None: + if x in [D(5)]: + reveal_type(x) # D # N: Revealed type is "__main__.C" + +f(C(5)) +[builtins fixtures/primitives.pyi] + +[case testNarrowingTypeVarNone] +# flags: --warn-unreachable + +# https://github.com/python/mypy/issues/18126 +from typing import TypeVar + +T = TypeVar("T") + +def fn_if(arg: T) -> None: + if arg is None: + return None + return None + +def fn_while(arg: T) -> None: + while arg is None: + return None + return None +[builtins fixtures/primitives.pyi] diff --git a/test-data/unit/check-newsemanal.test b/test-data/unit/check-newsemanal.test index 511c7b003015..784b9db9f66e 100644 --- a/test-data/unit/check-newsemanal.test +++ b/test-data/unit/check-newsemanal.test @@ -1908,9 +1908,9 @@ else: @dec def f(x: int) -> None: 1() # E: "int" not callable -reveal_type(f) # N: Revealed type is "def (x: builtins.str)" +reveal_type(f) # N: Revealed type is "def (builtins.str)" [file m.py] -def f(x: str) -> None: pass +def f(x: str, /) -> None: pass [case testNewAnalyzerConditionallyDefineFuncOverVar] from typing import Callable @@ -2069,6 +2069,7 @@ from enum import Enum A = Enum('A', ['x', 'y']) A = Enum('A', ['z', 't']) # E: Name "A" already defined on line 3 +[builtins fixtures/tuple.pyi] [case testNewAnalyzerNewTypeRedefinition] from typing import NewType diff --git a/test-data/unit/check-overloading.test b/test-data/unit/check-overloading.test index e414c1c9b0b6..9d01ce6bd480 100644 --- a/test-data/unit/check-overloading.test +++ b/test-data/unit/check-overloading.test @@ -6463,7 +6463,7 @@ class D: ... def f1(g: A) -> A: ... if True: @overload # E: Single overload definition, multiple required - def f1(g: B) -> B: ... + def f1(g: B) -> B: ... # E: Incompatible redefinition (redefinition with type "Callable[[B], B]", original type "Callable[[A], A]") if maybe_true: # E: Condition can't be inferred, unable to merge overloads \ # E: Name "maybe_true" is not defined @overload @@ -6480,14 +6480,14 @@ if True: def f2(g: B) -> B: ... elif maybe_true: # E: Name "maybe_true" is not defined @overload # E: Single overload definition, multiple required - def f2(g: C) -> C: ... + def f2(g: C) -> C: ... # E: Incompatible redefinition (redefinition with type "Callable[[C], C]", original type "Callable[[A], A]") def f2(g): ... # E: Name "f2" already defined on line 21 @overload # E: Single overload definition, multiple required def f3(g: A) -> A: ... if True: @overload # E: Single overload definition, multiple required - def f3(g: B) -> B: ... + def f3(g: B) -> B: ... # E: Incompatible redefinition (redefinition with type "Callable[[B], B]", original type "Callable[[A], A]") if True: pass # Some other node @overload # E: Name "f3" already defined on line 32 \ diff --git a/test-data/unit/check-parameter-specification.test b/test-data/unit/check-parameter-specification.test index 38fb62fe78e0..7f038b811741 100644 --- a/test-data/unit/check-parameter-specification.test +++ b/test-data/unit/check-parameter-specification.test @@ -1452,6 +1452,17 @@ y: C[int, str] reveal_type(y) # N: Revealed type is "def (builtins.int, builtins.int, builtins.str) -> builtins.int" [builtins fixtures/paramspec.pyi] +[case testParamSpecInTypeAliasIllegalBare] +from typing import ParamSpec +from typing_extensions import Concatenate, TypeAlias + +P = ParamSpec("P") +Bad1: TypeAlias = P # E: Invalid location for ParamSpec "P" \ + # N: You can use ParamSpec as the first argument to Callable, e.g., "Callable[P, int]" +Bad2: TypeAlias = Concatenate[int, P] # E: Invalid location for Concatenate \ + # N: You can use Concatenate as the first argument to Callable +[builtins fixtures/paramspec.pyi] + [case testParamSpecInTypeAliasRecursive] from typing import ParamSpec, Callable, Union @@ -2303,3 +2314,162 @@ reveal_type(capture(fn)) # N: Revealed type is "Union[builtins.str, builtins.in reveal_type(capture(err)) # N: Revealed type is "builtins.int" [builtins fixtures/paramspec.pyi] + +[case testRunParamSpecOverlappingOverloadsOrder] +from typing import Any, Callable, overload +from typing_extensions import ParamSpec + +P = ParamSpec("P") + +class Base: + pass +class Child(Base): + def __call__(self) -> str: ... +class NotChild: + def __call__(self) -> str: ... + +@overload +def handle(func: Base) -> int: ... +@overload +def handle(func: Callable[P, str], *args: P.args, **kwargs: P.kwargs) -> str: ... +def handle(func: Any, *args: Any, **kwargs: Any) -> Any: + return func(*args, **kwargs) + +@overload +def handle_reversed(func: Callable[P, str], *args: P.args, **kwargs: P.kwargs) -> str: ... +@overload +def handle_reversed(func: Base) -> int: ... +def handle_reversed(func: Any, *args: Any, **kwargs: Any) -> Any: + return func(*args, **kwargs) + +reveal_type(handle(Child())) # N: Revealed type is "builtins.int" +reveal_type(handle(NotChild())) # N: Revealed type is "builtins.str" + +reveal_type(handle_reversed(Child())) # N: Revealed type is "builtins.str" +reveal_type(handle_reversed(NotChild())) # N: Revealed type is "builtins.str" + +[builtins fixtures/paramspec.pyi] + +[case testBindPartial] +from functools import partial +from typing_extensions import ParamSpec +from typing import Callable, TypeVar + +P = ParamSpec("P") +T = TypeVar("T") + +def run(func: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> T: + func2 = partial(func, **kwargs) + return func2(*args) + +def run2(func: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> T: + func2 = partial(func, *args) + return func2(**kwargs) + +def run3(func: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> T: + func2 = partial(func, *args, **kwargs) + return func2() + +def run4(func: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> T: + func2 = partial(func, *args, **kwargs) + return func2(**kwargs) + +def run_bad(func: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> T: + func2 = partial(func, *args, **kwargs) + return func2(*args) # E: Too many arguments + +def run_bad2(func: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> T: + func2 = partial(func, **kwargs) + return func2(**kwargs) # E: Too few arguments + +def run_bad3(func: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> T: + func2 = partial(func, *args) + return func2() # E: Too few arguments + +[builtins fixtures/paramspec.pyi] + +[case testBindPartialConcatenate] +from functools import partial +from typing_extensions import Concatenate, ParamSpec +from typing import Callable, TypeVar + +P = ParamSpec("P") +T = TypeVar("T") + +def run(func: Callable[Concatenate[int, P], T], *args: P.args, **kwargs: P.kwargs) -> T: + func2 = partial(func, 1, **kwargs) + return func2(*args) + +def run2(func: Callable[Concatenate[int, P], T], *args: P.args, **kwargs: P.kwargs) -> T: + func2 = partial(func, **kwargs) + p = [""] + func2(1, *p) # E: Too few arguments \ + # E: Argument 2 has incompatible type "*List[str]"; expected "P.args" + func2(1, 2, *p) # E: Too few arguments \ + # E: Argument 2 has incompatible type "int"; expected "P.args" \ + # E: Argument 3 has incompatible type "*List[str]"; expected "P.args" + func2(1, *args, *p) # E: Argument 3 has incompatible type "*List[str]"; expected "P.args" + func2(1, *p, *args) # E: Argument 2 has incompatible type "*List[str]"; expected "P.args" + return func2(1, *args) + +def run3(func: Callable[Concatenate[int, P], T], *args: P.args, **kwargs: P.kwargs) -> T: + func2 = partial(func, 1, *args) + d = {"":""} + func2(**d) # E: Too few arguments \ + # E: Argument 1 has incompatible type "**Dict[str, str]"; expected "P.kwargs" + return func2(**kwargs) + +def run4(func: Callable[Concatenate[int, P], T], *args: P.args, **kwargs: P.kwargs) -> T: + func2 = partial(func, 1) + return func2(*args, **kwargs) + +def run5(func: Callable[Concatenate[int, P], T], *args: P.args, **kwargs: P.kwargs) -> T: + func2 = partial(func, 1, *args, **kwargs) + func2() + return func2(**kwargs) + +def run_bad(func: Callable[Concatenate[int, P], T], *args: P.args, **kwargs: P.kwargs) -> T: + func2 = partial(func, *args) # E: Argument 1 has incompatible type "*P.args"; expected "int" + return func2(1, **kwargs) # E: Argument 1 has incompatible type "int"; expected "P.args" + +def run_bad2(func: Callable[Concatenate[int, P], T], *args: P.args, **kwargs: P.kwargs) -> T: + func2 = partial(func, 1, *args) + func2() # E: Too few arguments + func2(*args, **kwargs) # E: Too many arguments + return func2(1, **kwargs) # E: Argument 1 has incompatible type "int"; expected "P.args" + +def run_bad3(func: Callable[Concatenate[int, P], T], *args: P.args, **kwargs: P.kwargs) -> T: + func2 = partial(func, 1, **kwargs) + func2() # E: Too few arguments + return func2(1, *args) # E: Argument 1 has incompatible type "int"; expected "P.args" + +def run_bad4(func: Callable[Concatenate[int, P], T], *args: P.args, **kwargs: P.kwargs) -> T: + func2 = partial(func, 1) + func2() # E: Too few arguments + func2(*args) # E: Too few arguments + func2(1, *args) # E: Too few arguments \ + # E: Argument 1 has incompatible type "int"; expected "P.args" + func2(1, **kwargs) # E: Too few arguments \ + # E: Argument 1 has incompatible type "int"; expected "P.args" + return func2(**kwargs) # E: Too few arguments + +[builtins fixtures/paramspec.pyi] + +[case testOtherVarArgs] +from functools import partial +from typing_extensions import Concatenate, ParamSpec +from typing import Callable, TypeVar, Tuple + +P = ParamSpec("P") +T = TypeVar("T") + +def run(func: Callable[Concatenate[int, str, P], T], *args: P.args, **kwargs: P.kwargs) -> T: + func2 = partial(func, **kwargs) + args_prefix: Tuple[int, str] = (1, 'a') + func2(*args_prefix) # E: Too few arguments + func2(*args, *args_prefix) # E: Argument 1 has incompatible type "*P.args"; expected "int" \ + # E: Argument 1 has incompatible type "*P.args"; expected "str" \ + # E: Argument 2 has incompatible type "*Tuple[int, str]"; expected "P.args" + return func2(*args_prefix, *args) + +[builtins fixtures/paramspec.pyi] diff --git a/test-data/unit/check-protocols.test b/test-data/unit/check-protocols.test index 5ed2351e33e6..dd19eb1f21d6 100644 --- a/test-data/unit/check-protocols.test +++ b/test-data/unit/check-protocols.test @@ -2473,7 +2473,8 @@ def func(caller: Caller) -> None: pass func(call) -func(bad) # E: Argument 1 to "func" has incompatible type "Callable[[int, VarArg(str)], None]"; expected "Caller" +func(bad) # E: Argument 1 to "func" has incompatible type "Callable[[int, VarArg(str)], None]"; expected "Caller" \ + # N: "Caller.__call__" has type "Callable[[Arg(str, 'x'), VarArg(int)], None]" [builtins fixtures/tuple.pyi] [out] @@ -2510,7 +2511,8 @@ def func(caller: Caller) -> None: pass func(call) -func(bad) # E: Argument 1 to "func" has incompatible type "Callable[[int], int]"; expected "Caller" +func(bad) # E: Argument 1 to "func" has incompatible type "Callable[[int], int]"; expected "Caller" \ + # N: "Caller.__call__" has type "Callable[[Arg(T, 'x')], T]" [builtins fixtures/tuple.pyi] [out] @@ -2530,7 +2532,8 @@ def func(caller: Caller) -> None: pass func(call) -func(bad) # E: Argument 1 to "func" has incompatible type "Callable[[T], Tuple[T, T]]"; expected "Caller" +func(bad) # E: Argument 1 to "func" has incompatible type "Callable[[T], Tuple[T, T]]"; expected "Caller" \ + # N: "Caller.__call__" has type "Callable[[Arg(int, 'x')], int]" [builtins fixtures/tuple.pyi] [out] @@ -2557,7 +2560,8 @@ def func(caller: Caller) -> None: pass func(call) -func(bad) # E: Argument 1 to "func" has incompatible type "Callable[[Union[int, str]], Union[int, str]]"; expected "Caller" +func(bad) # E: Argument 1 to "func" has incompatible type "Callable[[Union[int, str]], Union[int, str]]"; expected "Caller" \ + # N: "Caller.__call__" has type overloaded function [out] [case testCallableImplementsProtocolExtraNote] @@ -2596,7 +2600,8 @@ def anon(caller: CallerAnon) -> None: func(call) -func(bad) # E: Argument 1 to "func" has incompatible type "Callable[[str], None]"; expected "Caller" +func(bad) # E: Argument 1 to "func" has incompatible type "Callable[[str], None]"; expected "Caller" \ + # N: "Caller.__call__" has type "Callable[[Arg(str, 'x')], None]" anon(bad) [out] @@ -2619,7 +2624,8 @@ a: Other b: Bad func(a) -func(b) # E: Argument 1 to "func" has incompatible type "Bad"; expected "One" +func(b) # E: Argument 1 to "func" has incompatible type "Bad"; expected "One" \ + # N: "One.__call__" has type "Callable[[Arg(str, 'x')], None]" [out] [case testJoinProtocolCallback] @@ -3589,7 +3595,8 @@ test(C) # E: Argument 1 to "test" has incompatible type "Type[C]"; expected "P" # N: Expected: \ # N: def __call__(x: int, y: int) -> Any \ # N: Got: \ - # N: def __init__(x: int, y: str) -> C + # N: def __init__(x: int, y: str) -> C \ + # N: "P.__call__" has type "Callable[[Arg(int, 'x'), Arg(int, 'y')], Any]" [case testProtocolClassObjectPureCallback] from typing import Any, ClassVar, Protocol @@ -3610,7 +3617,8 @@ test(C) # E: Argument 1 to "test" has incompatible type "Type[C]"; expected "P" # N: Expected: \ # N: def __call__(x: int, y: int) -> Any \ # N: Got: \ - # N: def __init__(x: int, y: str) -> C + # N: def __init__(x: int, y: str) -> C \ + # N: "P.__call__" has type "Callable[[Arg(int, 'x'), Arg(int, 'y')], Any]" [builtins fixtures/type.pyi] [case testProtocolClassObjectCallableError] @@ -4215,3 +4223,24 @@ def g4(a: Input[bytes], b: Output[str]) -> None: f(a, b) # E: Cannot infer type argument 1 of "f" [builtins fixtures/tuple.pyi] + +[case testOverloadProtocolSubtyping] +from typing import Protocol, Self, overload + +class NumpyFloat: + __add__: "FloatOP" + +class FloatOP(Protocol): + @overload + def __call__(self, other: float) -> NumpyFloat: ... + @overload + def __call__(self, other: NumpyFloat) -> NumpyFloat: ... + +class SupportsAdd(Protocol): + @overload + def __add__(self, other: float) -> Self: ... + @overload + def __add__(self, other: NumpyFloat) -> Self: ... + +x: SupportsAdd = NumpyFloat() +[builtins fixtures/tuple.pyi] diff --git a/test-data/unit/check-python310.test b/test-data/unit/check-python310.test index e7028a027e25..0231b47cf4a0 100644 --- a/test-data/unit/check-python310.test +++ b/test-data/unit/check-python310.test @@ -648,6 +648,25 @@ match m: reveal_type(m) # N: Revealed type is "builtins.tuple[Any, ...]" [builtins fixtures/primitives.pyi] +[case testMatchClassPatternCaptureSelfSubtype] +class A(str): + pass + +class B(str): + __match_args__ = ("b",) + b: int + +def f1(x: A): + match x: + case A(a): + reveal_type(a) # N: Revealed type is "__main__.A" + +def f2(x: B): + match x: + case B(b): + reveal_type(b) # N: Revealed type is "builtins.int" +[builtins fixtures/tuple.pyi] + [case testMatchInvalidClassPattern] m: object @@ -1524,6 +1543,62 @@ def g(m: Medal) -> int: case Medal.bronze: reveal_type(m) # N: Revealed type is "Literal[__main__.Medal.bronze]" return 2 +[builtins fixtures/enum.pyi] + + +[case testMatchLiteralPatternEnumWithTypedAttribute] +from enum import Enum +from typing import NoReturn +def assert_never(x: NoReturn) -> None: ... + +class int: + def __new__(cls, value: int): pass + +class Medal(int, Enum): + prize: str + + def __new__(cls, value: int, prize: str) -> Medal: + enum = int.__new__(cls, value) + enum._value_ = value + enum.prize = prize + return enum + + gold = (1, 'cash prize') + silver = (2, 'sponsorship') + bronze = (3, 'nothing') + +m: Medal + +match m: + case Medal.gold: + reveal_type(m) # N: Revealed type is "Literal[__main__.Medal.gold]" + case Medal.silver: + reveal_type(m) # N: Revealed type is "Literal[__main__.Medal.silver]" + case Medal.bronze: + reveal_type(m) # N: Revealed type is "Literal[__main__.Medal.bronze]" + case _ as unreachable: + assert_never(unreachable) + +[builtins fixtures/tuple.pyi] + +[case testMatchLiteralPatternFunctionalEnum] +from enum import Enum +from typing import NoReturn +def assert_never(x: NoReturn) -> None: ... + +Medal = Enum('Medal', 'gold silver bronze') +m: Medal + +match m: + case Medal.gold: + reveal_type(m) # N: Revealed type is "Literal[__main__.Medal.gold]" + case Medal.silver: + reveal_type(m) # N: Revealed type is "Literal[__main__.Medal.silver]" + case Medal.bronze: + reveal_type(m) # N: Revealed type is "Literal[__main__.Medal.bronze]" + case _ as unreachable: + assert_never(unreachable) +[builtins fixtures/enum.pyi] [case testMatchLiteralPatternEnumCustomEquals-skip] from enum import Enum @@ -1541,6 +1616,7 @@ match m: reveal_type(m) # N: Revealed type is "Literal[__main__.Medal.gold]" case _: reveal_type(m) # N: Revealed type is "__main__.Medal" +[builtins fixtures/enum.pyi] [case testMatchNarrowUsingPatternGuardSpecialCase] def f(x: int | str) -> int: @@ -1618,6 +1694,7 @@ def union(x: str | bool) -> None: case True: return reveal_type(x) # N: Revealed type is "Union[builtins.str, Literal[False]]" +[builtins fixtures/tuple.pyi] [case testMatchAssertFalseToSilenceFalsePositives] class C: @@ -1648,6 +1725,22 @@ def f(x: int | str) -> int: case str() as s: return 1 +[case testMatchOrPatternExhaustiveness] +from typing import NoReturn, Literal +def assert_never(x: NoReturn) -> None: ... + +Color = Literal["blue", "green", "red"] +c: Color + +match c: + case "blue": + reveal_type(c) # N: Revealed type is "Literal['blue']" + case "green" | "notColor": + reveal_type(c) # N: Revealed type is "Literal['green']" + case _: + assert_never(c) # E: Argument 1 to "assert_never" has incompatible type "Literal['red']"; expected "Never" +[typing fixtures/typing-typeddict.pyi] + [case testMatchAsPatternIntersection-skip] class A: pass class B: pass @@ -2289,3 +2382,60 @@ def test(xs: Tuple[Unpack[Ts]]) -> None: reveal_type(b3) # N: Revealed type is "builtins.list[builtins.object]" reveal_type(c3) # N: Revealed type is "builtins.int" [builtins fixtures/tuple.pyi] + +[case testMatchSequencePatternTypeVarBoundNoCrash] +# This was crashing: https://github.com/python/mypy/issues/18089 +from typing import TypeVar, Sequence, Any + +T = TypeVar("T", bound=Sequence[Any]) + +def f(x: T) -> None: + match x: + case [_]: + pass +[builtins fixtures/tuple.pyi] + +[case testMatchSequencePatternTypeVarBoundNarrows] +from typing import TypeVar, Sequence + +T = TypeVar("T", bound=Sequence[int | str]) + +def accept_seq_int(x: Sequence[int]): ... + +def f(x: T) -> None: + match x: + case [1, 2]: + accept_seq_int(x) + case _: + accept_seq_int(x) # E: Argument 1 to "accept_seq_int" has incompatible type "T"; expected "Sequence[int]" +[builtins fixtures/tuple.pyi] + +[case testNarrowingTypeVarMatch] +# flags: --warn-unreachable + +# https://github.com/python/mypy/issues/18126 +from typing import TypeVar + +T = TypeVar("T") + +def fn_case(arg: T) -> None: + match arg: + case None: + return None + return None +[builtins fixtures/primitives.pyi] + +[case testNoneCheckDoesNotMakeTypeVarOptionalMatch] +from typing import TypeVar + +T = TypeVar('T') + +def foo(x: T) -> T: + out = None + out = x + match out: + case None: + pass + return out + +[builtins fixtures/isinstance.pyi] diff --git a/test-data/unit/check-python311.test b/test-data/unit/check-python311.test index 28951824999f..6f4c540572b0 100644 --- a/test-data/unit/check-python311.test +++ b/test-data/unit/check-python311.test @@ -173,3 +173,89 @@ Alias4 = Callable[[*IntList], int] # E: "List[int]" cannot be unpacked (must be x4: Alias4[int] # E: Bad number of arguments for type alias, expected 0, given 1 reveal_type(x4) # N: Revealed type is "def (*Any) -> builtins.int" [builtins fixtures/tuple.pyi] + +[case testReturnInExceptStarBlock1] +# flags: --python-version 3.11 +def foo() -> None: + try: + pass + except* Exception: + return # E: "return" not allowed in except* block + finally: + return +[builtins fixtures/exception.pyi] + +[case testReturnInExceptStarBlock2] +# flags: --python-version 3.11 +def foo(): + while True: + try: + pass + except* Exception: + while True: + return # E: "return" not allowed in except* block +[builtins fixtures/exception.pyi] + +[case testContinueInExceptBlockNestedInExceptStarBlock] +# flags: --python-version 3.11 +while True: + try: + ... + except* Exception: + try: + ... + except Exception: + continue # E: "continue" not allowed in except* block + continue # E: "continue" not allowed in except* block +[builtins fixtures/exception.pyi] + +[case testReturnInExceptBlockNestedInExceptStarBlock] +# flags: --python-version 3.11 +def foo(): + try: + ... + except* Exception: + try: + ... + except Exception: + return # E: "return" not allowed in except* block + return # E: "return" not allowed in except* block +[builtins fixtures/exception.pyi] + +[case testBreakContinueReturnInExceptStarBlock1] +# flags: --python-version 3.11 +from typing import Iterable +def foo(x: Iterable[int]) -> None: + for _ in x: + try: + pass + except* Exception: + continue # E: "continue" not allowed in except* block + except* Exception: + for _ in x: + continue + break # E: "break" not allowed in except* block + except* Exception: + return # E: "return" not allowed in except* block +[builtins fixtures/exception.pyi] + +[case testBreakContinueReturnInExceptStarBlock2] +# flags: --python-version 3.11 +def foo(): + while True: + try: + pass + except* Exception: + def inner(): + while True: + if 1 < 1: + continue + else: + break + return + if 1 < 2: + break # E: "break" not allowed in except* block + if 1 < 2: + continue # E: "continue" not allowed in except* block + return # E: "return" not allowed in except* block +[builtins fixtures/exception.pyi] diff --git a/test-data/unit/check-python312.test b/test-data/unit/check-python312.test index 085cc052705d..8b4d638ecdaa 100644 --- a/test-data/unit/check-python312.test +++ b/test-data/unit/check-python312.test @@ -1525,6 +1525,29 @@ reveal_type(E[str]().a) # N: Revealed type is "builtins.list[Any]" [builtins fixtures/type.pyi] [typing fixtures/typing-full.pyi] +[case testPEP695TypeAliasInvalidGenericConstraint] +class A[T]: + class a[S: (int, list[T])]: pass # E: Name "T" is not defined + type b[S: (int, list[T])] = S # E: TypeVar constraint type cannot be parametrized by type variables + def c[S: (int, list[T])](self) -> None: ... # E: TypeVar constraint type cannot be parametrized by type variables +[builtins fixtures/tuple.pyi] +[typing fixtures/typing-full.pyi] + +[case testPEP695TypeAliasUnboundTypeVarConstraint] +from typing import TypeVar +T = TypeVar("T") +class a[S: (int, list[T])]: pass # E: Type variable "__main__.T" is unbound \ + # N: (Hint: Use "Generic[T]" or "Protocol[T]" base class to bind "T" inside a class) \ + # N: (Hint: Use "T" in function signature to bind "T" inside a function) +type b[S: (int, list[T])] = S # E: Type variable "__main__.T" is unbound \ + # N: (Hint: Use "Generic[T]" or "Protocol[T]" base class to bind "T" inside a class) \ + # N: (Hint: Use "T" in function signature to bind "T" inside a function) +def c[S: (int, list[T])](self) -> None: ... # E: Type variable "__main__.T" is unbound \ + # N: (Hint: Use "Generic[T]" or "Protocol[T]" base class to bind "T" inside a class) \ + # N: (Hint: Use "T" in function signature to bind "T" inside a function) +[builtins fixtures/tuple.pyi] +[typing fixtures/typing-full.pyi] + [case testPEP695RedefineAsTypeAlias1] class C: pass type C = int # E: Name "C" already defined on line 1 @@ -1873,3 +1896,79 @@ d1: Multi[int, str] = Multi[float, str]() # E: Incompatible types in assignment d2: Multi[float, str] = Multi[int, str]() # E: Incompatible types in assignment (expression has type "Multi[int, str]", variable has type "Multi[float, str]") d3: Multi[str, int] = Multi[str, float]() d4: Multi[str, float] = Multi[str, int]() # E: Incompatible types in assignment (expression has type "Multi[str, int]", variable has type "Multi[str, float]") + +[case testPEP695MultipleNestedGenericClass1] +# flags: --enable-incomplete-feature=NewGenericSyntax +class A: + class B: + class C: + class D[Q]: + def g(self, x: Q): ... + d: D[str] + +x: A.B.C.D[int] +x.g('a') # E: Argument 1 to "g" of "D" has incompatible type "str"; expected "int" +reveal_type(x) # N: Revealed type is "__main__.A.B.C.D[builtins.int]" +reveal_type(A.B.C.d) # N: Revealed type is "__main__.A.B.C.D[builtins.str]" + +[case testPEP695MultipleNestedGenericClass2] +# flags: --enable-incomplete-feature=NewGenericSyntax +class A: + class B: + def m(self) -> None: + class C[T]: + def f(self) -> T: ... + x: C[int] + reveal_type(x.f()) # N: Revealed type is "builtins.int" + self.a = C[str]() + +reveal_type(A().B().a) # N: Revealed type is "__main__.C@5[builtins.str]" + +[case testPEP695MultipleNestedGenericClass3] +# flags: --enable-incomplete-feature=NewGenericSyntax +class A: + class C[T]: + def f(self) -> T: ... + class D[S]: + x: T # E: Name "T" is not defined + def g(self) -> S: ... + +a: A.C[int] +reveal_type(a.f()) # N: Revealed type is "builtins.int" +b: A.C.D[str] +reveal_type(b.g()) # N: Revealed type is "builtins.str" + +class B: + class E[T]: + class F[T]: # E: "T" already defined as a type parameter + x: T + +c: B.E.F[int] + +[case testPEP695MultipleNestedGenericClass4] +# flags: --enable-incomplete-feature=NewGenericSyntax +class Z: + class A: + class B[T]: + def __get__(self, instance: Z.A, owner: type[Z.A]) -> T: + return None # E: Incompatible return value type (got "None", expected "T") + f = B[int]() + +a = Z.A() +v = a.f + +[case testPEP695MultipleNestedGenericClass5] +# flags: --enable-incomplete-feature=NewGenericSyntax +from a.b.c import d +x: d.D.E.F.G[int] +x.g('a') # E: Argument 1 to "g" of "G" has incompatible type "str"; expected "int" +reveal_type(x) # N: Revealed type is "a.b.c.d.D.E.F.G[builtins.int]" +reveal_type(d.D.E.F.d) # N: Revealed type is "a.b.c.d.D.E.F.G[builtins.str]" + +[file a/b/c/d.py] +class D: + class E: + class F: + class G[Q]: + def g(self, x: Q): ... + d: G[str] diff --git a/test-data/unit/check-python313.test b/test-data/unit/check-python313.test index 0ba64ad67c91..2729ad3e21d1 100644 --- a/test-data/unit/check-python313.test +++ b/test-data/unit/check-python313.test @@ -1,11 +1,257 @@ -[case testPEP695TypeParameterDefaultNotSupported] -class C[T = None]: # E: Type parameter default types not supported when using Python 3.12 type parameter syntax - pass +[case testPEP695TypeParameterDefaultSupported] +class C[T = None]: ... +def f[T = list[int]]() -> None: ... +def g[**P = [int, str]]() -> None: ... +type A[T, S = int, U = str] = list[T] -def f[T = list[int]]() -> None: # E: Type parameter default types not supported when using Python 3.12 type parameter syntax - pass +[case testPEP695TypeParameterDefaultBasic] +from typing import Callable -def g[**P = [int, str]]() -> None: # E: Type parameter default types not supported when using Python 3.12 type parameter syntax - pass +def f1[T1 = int](a: T1) -> list[T1]: ... +reveal_type(f1) # N: Revealed type is "def [T1 = builtins.int] (a: T1`-1 = builtins.int) -> builtins.list[T1`-1 = builtins.int]" -type A[T, S = int, U = str] = list[T] # E: Type parameter default types not supported when using Python 3.12 type parameter syntax +def f2[**P1 = [int, str]](a: Callable[P1, None]) -> Callable[P1, None]: ... +reveal_type(f2) # N: Revealed type is "def [P1 = [builtins.int, builtins.str]] (a: def (*P1.args, **P1.kwargs)) -> def (*P1.args, **P1.kwargs)" + +def f3[*Ts1 = *tuple[int, str]](a: tuple[*Ts1]) -> tuple[*Ts1]: ... +reveal_type(f3) # N: Revealed type is "def [Ts1 = Unpack[Tuple[builtins.int, builtins.str]]] (a: Tuple[Unpack[Ts1`-1 = Unpack[Tuple[builtins.int, builtins.str]]]]) -> Tuple[Unpack[Ts1`-1 = Unpack[Tuple[builtins.int, builtins.str]]]]" + + +class ClassA1[T1 = int]: ... +class ClassA2[**P1 = [int, str]]: ... +class ClassA3[*Ts1 = *tuple[int, str]]: ... + +reveal_type(ClassA1) # N: Revealed type is "def [T1 = builtins.int] () -> __main__.ClassA1[T1`1 = builtins.int]" +reveal_type(ClassA2) # N: Revealed type is "def [P1 = [builtins.int, builtins.str]] () -> __main__.ClassA2[P1`1 = [builtins.int, builtins.str]]" +reveal_type(ClassA3) # N: Revealed type is "def [Ts1 = Unpack[Tuple[builtins.int, builtins.str]]] () -> __main__.ClassA3[Unpack[Ts1`1 = Unpack[Tuple[builtins.int, builtins.str]]]]" +[builtins fixtures/tuple.pyi] + +[case testPEP695TypeParameterDefaultValid] +from typing import Any + +class ClassT1[T = int]: ... +class ClassT2[T: float = int]: ... +class ClassT3[T: list[Any] = list[int]]: ... +class ClassT4[T: (int, str) = int]: ... + +class ClassP1[**P = []]: ... +class ClassP2[**P = ...]: ... +class ClassP3[**P = [int, str]]: ... + +class ClassTs1[*Ts = *tuple[int]]: ... +class ClassTs2[*Ts = *tuple[int, ...]]: ... +[builtins fixtures/tuple.pyi] + +[case testPEP695TypeParameterDefaultInvalid] +class ClassT1[T = 2]: ... # E: TypeVar "default" must be a type +class ClassT2[T = [int]]: ... # E: Bracketed expression "[...]" is not valid as a type \ + # N: Did you mean "List[...]"? \ + # E: TypeVar "default" must be a type +class ClassT3[T: str = int]: ... # E: TypeVar default must be a subtype of the bound type +class ClassT4[T: list[str] = list[int]]: ... # E: TypeVar default must be a subtype of the bound type +class ClassT5[T: (int, str) = bytes]: ... # E: TypeVar default must be one of the constraint types +class ClassT6[T: (int, str) = int | str]: ... # E: TypeVar default must be one of the constraint types +class ClassT7[T: (float, str) = int]: ... # E: TypeVar default must be one of the constraint types + +class ClassP1[**P = int]: ... # E: The default argument to ParamSpec must be a list expression, ellipsis, or a ParamSpec +class ClassP2[**P = 2]: ... # E: The default argument to ParamSpec must be a list expression, ellipsis, or a ParamSpec +class ClassP3[**P = (2, int)]: ... # E: The default argument to ParamSpec must be a list expression, ellipsis, or a ParamSpec +class ClassP4[**P = [2, int]]: ... # E: Argument 0 of ParamSpec default must be a type + +class ClassTs1[*Ts = 2]: ... # E: The default argument to TypeVarTuple must be an Unpacked tuple +class ClassTs2[*Ts = int]: ... # E: The default argument to TypeVarTuple must be an Unpacked tuple +class ClassTs3[*Ts = tuple[int]]: ... # E: The default argument to TypeVarTuple must be an Unpacked tuple +[builtins fixtures/tuple.pyi] + +[case testPEP695TypeParameterDefaultInvalid2] +from typing import overload +def f1[T = 2]() -> None: ... # E: TypeVar "default" must be a type +def f2[T = [int]]() -> None: ... # E: Bracketed expression "[...]" is not valid as a type \ + # N: Did you mean "List[...]"? \ + # E: TypeVar "default" must be a type +def f3[T: str = int](x: T) -> T: ... # E: TypeVar default must be a subtype of the bound type +def f4[T: list[str] = list[int]](x: T) -> T: ... # E: TypeVar default must be a subtype of the bound type +def f5[T: (int, str) = bytes](x: T) -> T: ... # E: TypeVar default must be one of the constraint types +def f6[T: (int, str) = int | str](x: T) -> T: ... # E: TypeVar default must be one of the constraint types +def f7[T: (float, str) = int](x: T) -> T: ... # E: TypeVar default must be one of the constraint types +def f8[T: str = int]() -> None: ... # TODO check unused TypeVars +@overload +def f9[T: str = int](x: T) -> T: ... # E: TypeVar default must be a subtype of the bound type +@overload +def f9[T: (int, str) = bytes](x: T) -> T: ... # E: TypeVar default must be one of the constraint types +def f9() -> None: ... # type: ignore[misc] + +def g1[**P = int]() -> None: ... # E: The default argument to ParamSpec must be a list expression, ellipsis, or a ParamSpec +def g2[**P = 2]() -> None: ... # E: The default argument to ParamSpec must be a list expression, ellipsis, or a ParamSpec +def g3[**P = (2, int)]() -> None: ... # E: The default argument to ParamSpec must be a list expression, ellipsis, or a ParamSpec +def g4[**P = [2, int]]() -> None: ... # E: Argument 0 of ParamSpec default must be a type + +def h1[*Ts = 2]() -> None: ... # E: The default argument to TypeVarTuple must be an Unpacked tuple +def h2[*Ts = int]() -> None: ... # E: The default argument to TypeVarTuple must be an Unpacked tuple +def h3[*Ts = tuple[int]]() -> None: ... # E: The default argument to TypeVarTuple must be an Unpacked tuple +[builtins fixtures/tuple.pyi] + +[case testPEP695TypeParameterDefaultInvalid3] +from typing import Callable + +type TA1[T: str = 1] = list[T] # E: TypeVar "default" must be a type +type TA2[T: str = [int]] = list[T] # E: Bracketed expression "[...]" is not valid as a type \ + # N: Did you mean "List[...]"? \ + # E: TypeVar "default" must be a type +type TA3[T: str = int] = list[T] # E: TypeVar default must be a subtype of the bound type +type TA4[T: list[str] = list[int]] = list[T] # E: TypeVar default must be a subtype of the bound type +type TA5[T: (int, str) = bytes] = list[T] # E: TypeVar default must be one of the constraint types +type TA6[T: (int, str) = int | str] = list[T] # E: TypeVar default must be one of the constraint types +type TA7[T: (float, str) = int] = list[T] # E: TypeVar default must be one of the constraint types + +type TB1[**P = int] = Callable[P, None] # E: The default argument to ParamSpec must be a list expression, ellipsis, or a ParamSpec +type TB2[**P = 2] = Callable[P, None] # E: The default argument to ParamSpec must be a list expression, ellipsis, or a ParamSpec +type TB3[**P = (2, int)] = Callable[P, None] # E: The default argument to ParamSpec must be a list expression, ellipsis, or a ParamSpec +type TB4[**P = [2, int]] = Callable[P, None] # E: Argument 0 of ParamSpec default must be a type + +type TC1[*Ts = 2] = tuple[*Ts] # E: The default argument to TypeVarTuple must be an Unpacked tuple +type TC2[*Ts = int] = tuple[*Ts] # E: The default argument to TypeVarTuple must be an Unpacked tuple +type TC3[*Ts = tuple[int]] = tuple[*Ts] # E: The default argument to TypeVarTuple must be an Unpacked tuple +[builtins fixtures/tuple.pyi] +[typing fixtures/typing-full.pyi] + +[case testPEP695TypeParameterDefaultFunctions] +from typing import Callable + +def callback1(x: str) -> None: ... + +def func_a1[T = str](x: int | T) -> T: ... +reveal_type(func_a1(2)) # N: Revealed type is "builtins.str" +reveal_type(func_a1(2.1)) # N: Revealed type is "builtins.float" + +def func_a2[T = str](x: int | T) -> list[T]: ... +reveal_type(func_a2(2)) # N: Revealed type is "builtins.list[builtins.str]" +reveal_type(func_a2(2.1)) # N: Revealed type is "builtins.list[builtins.float]" + + +def func_a3[T: str = str](x: int | T) -> T: ... +reveal_type(func_a3(2)) # N: Revealed type is "builtins.str" + +def func_a4[T: (bytes, str) = str](x: int | T) -> T: ... +reveal_type(func_a4(2)) # N: Revealed type is "builtins.str" + +def func_b1[**P = [int, str]](x: int | Callable[P, None]) -> Callable[P, None]: ... +reveal_type(func_b1(callback1)) # N: Revealed type is "def (x: builtins.str)" +reveal_type(func_b1(2)) # N: Revealed type is "def (builtins.int, builtins.str)" + +def func_c1[*Ts = *tuple[int, str]](x: int | Callable[[*Ts], None]) -> tuple[*Ts]: ... +# reveal_type(func_c1(callback1)) # Revealed type is "Tuple[str]" # TODO +reveal_type(func_c1(2)) # N: Revealed type is "Tuple[builtins.int, builtins.str]" +[builtins fixtures/tuple.pyi] + +[case testPEP695TypeParameterDefaultClass1] +# flags: --disallow-any-generics + +class ClassA1[T2 = int, T3 = str]: ... + +def func_a1( + a: ClassA1, + b: ClassA1[float], + c: ClassA1[float, float], + d: ClassA1[float, float, float], # E: "ClassA1" expects between 0 and 2 type arguments, but 3 given +) -> None: + reveal_type(a) # N: Revealed type is "__main__.ClassA1[builtins.int, builtins.str]" + reveal_type(b) # N: Revealed type is "__main__.ClassA1[builtins.float, builtins.str]" + reveal_type(c) # N: Revealed type is "__main__.ClassA1[builtins.float, builtins.float]" + reveal_type(d) # N: Revealed type is "__main__.ClassA1[builtins.int, builtins.str]" +[builtins fixtures/tuple.pyi] + +[case testPEP695TypeParameterDefaultClass2] +# flags: --disallow-any-generics + +class ClassB1[**P2 = [int, str], **P3 = ...]: ... + +def func_b1( + a: ClassB1, + b: ClassB1[[float]], + c: ClassB1[[float], [float]], + d: ClassB1[[float], [float], [float]], # E: "ClassB1" expects between 0 and 2 type arguments, but 3 given +) -> None: + reveal_type(a) # N: Revealed type is "__main__.ClassB1[[builtins.int, builtins.str], ...]" + reveal_type(b) # N: Revealed type is "__main__.ClassB1[[builtins.float], ...]" + reveal_type(c) # N: Revealed type is "__main__.ClassB1[[builtins.float], [builtins.float]]" + reveal_type(d) # N: Revealed type is "__main__.ClassB1[[builtins.int, builtins.str], ...]" + + k = ClassB1() + reveal_type(k) # N: Revealed type is "__main__.ClassB1[[builtins.int, builtins.str], [*Any, **Any]]" + l = ClassB1[[float]]() + reveal_type(l) # N: Revealed type is "__main__.ClassB1[[builtins.float], [*Any, **Any]]" + m = ClassB1[[float], [float]]() + reveal_type(m) # N: Revealed type is "__main__.ClassB1[[builtins.float], [builtins.float]]" + n = ClassB1[[float], [float], [float]]() # E: Type application has too many types (expected between 0 and 2) + reveal_type(n) # N: Revealed type is "Any" + +[case testPEP695TypeParameterDefaultClass3] +# flags: --disallow-any-generics + +class ClassC1[*Ts = *tuple[int, str]]: ... + +def func_c1( + a: ClassC1, + b: ClassC1[float], +) -> None: + # reveal_type(a) # Revealed type is "__main__.ClassC1[builtins.int, builtins.str]" # TODO + reveal_type(b) # N: Revealed type is "__main__.ClassC1[builtins.float]" + + k = ClassC1() + reveal_type(k) # N: Revealed type is "__main__.ClassC1[builtins.int, builtins.str]" + l = ClassC1[float]() + reveal_type(l) # N: Revealed type is "__main__.ClassC1[builtins.float]" +[builtins fixtures/tuple.pyi] + +[case testPEP695TypeParameterDefaultTypeAlias1] +# flags: --disallow-any-generics + +type TA1[T2 = int, T3 = str] = dict[T2, T3] + +def func_a1( + a: TA1, + b: TA1[float], + c: TA1[float, float], + d: TA1[float, float, float], # E: Bad number of arguments for type alias, expected between 0 and 2, given 3 +) -> None: + reveal_type(a) # N: Revealed type is "builtins.dict[builtins.int, builtins.str]" + reveal_type(b) # N: Revealed type is "builtins.dict[builtins.float, builtins.str]" + reveal_type(c) # N: Revealed type is "builtins.dict[builtins.float, builtins.float]" + reveal_type(d) # N: Revealed type is "builtins.dict[builtins.int, builtins.str]" +[builtins fixtures/tuple.pyi] +[typing fixtures/typing-full.pyi] + +[case testPEP695TypeParameterDefaultTypeAlias2] +# flags: --disallow-any-generics + +class ClassB1[**P2, **P3]: ... +type TB1[**P2 = [int, str], **P3 = ...] = ClassB1[P2, P3] + +def func_b1( + a: TB1, + b: TB1[[float]], + c: TB1[[float], [float]], + d: TB1[[float], [float], [float]], # E: Bad number of arguments for type alias, expected between 0 and 2, given 3 +) -> None: + reveal_type(a) # N: Revealed type is "__main__.ClassB1[[builtins.int, builtins.str], [*Any, **Any]]" + reveal_type(b) # N: Revealed type is "__main__.ClassB1[[builtins.float], [*Any, **Any]]" + reveal_type(c) # N: Revealed type is "__main__.ClassB1[[builtins.float], [builtins.float]]" + reveal_type(d) # N: Revealed type is "__main__.ClassB1[[builtins.int, builtins.str], [*Any, **Any]]" +[builtins fixtures/tuple.pyi] +[typing fixtures/typing-full.pyi] + +[case testPEP695TypeParameterDefaultTypeAlias3] +# flags: --disallow-any-generics + +type TC1[*Ts = *tuple[int, str]] = tuple[*Ts] + +def func_c1( + a: TC1, + b: TC1[float], +) -> None: + # reveal_type(a) # Revealed type is "Tuple[builtins.int, builtins.str]" # TODO + reveal_type(b) # N: Revealed type is "Tuple[builtins.float]" + +[builtins fixtures/tuple.pyi] +[typing fixtures/typing-full.pyi] diff --git a/test-data/unit/check-recursive-types.test b/test-data/unit/check-recursive-types.test index ac1ea0c0035a..4d7af98204fb 100644 --- a/test-data/unit/check-recursive-types.test +++ b/test-data/unit/check-recursive-types.test @@ -1006,3 +1006,11 @@ ta: Tuple[A] p: Proto p = ta [builtins fixtures/tuple.pyi] + +[case testRecursiveAliasesWithAnyUnimported] +# flags: --disallow-any-unimported +from typing import Callable +from bogus import Foo # type: ignore + +A = Callable[[Foo, "B"], Foo] # E: Type alias target becomes "Callable[[Any, B], Any]" due to an unfollowed import +B = Callable[[Foo, A], Foo] # E: Type alias target becomes "Callable[[Any, A], Any]" due to an unfollowed import diff --git a/test-data/unit/check-selftype.test b/test-data/unit/check-selftype.test index 9601852ef823..fa853ac48e5a 100644 --- a/test-data/unit/check-selftype.test +++ b/test-data/unit/check-selftype.test @@ -2160,3 +2160,57 @@ class MyProtocol(Protocol): def test() -> None: ... value: MyProtocol = test + +[case testSelfTypeUnionIter] +from typing import Self, Iterator, Generic, TypeVar, Union + +T = TypeVar("T") + +class range(Generic[T]): + def __iter__(self) -> Self: ... + def __next__(self) -> T: ... + +class count: + def __iter__(self) -> Iterator[int]: ... + +def foo(x: Union[range[int], count]) -> None: + for item in x: + reveal_type(item) # N: Revealed type is "builtins.int" + +[case testGenericDescriptorWithSelfTypeAnnotationsAndOverloads] +from __future__ import annotations +from typing import Any, overload, Callable, TypeVar, Generic, ParamSpec +from typing_extensions import Concatenate + +C = TypeVar("C", bound=Callable[..., Any]) +S = TypeVar("S") +P = ParamSpec("P") +R = TypeVar("R") + +class Descriptor(Generic[C]): + def __init__(self, impl: C) -> None: ... + + @overload + def __get__( + self: Descriptor[C], instance: None, owner: type | None + ) -> Descriptor[C]: ... + + @overload + def __get__( + self: Descriptor[Callable[Concatenate[S, P], R]], instance: S, owner: type | None, + ) -> Callable[P, R]: ... + + def __get__(self, *args, **kwargs): ... + +class Test: + @Descriptor + def method(self, foo: int, bar: str) -> bytes: ... + +reveal_type(Test().method) # N: Revealed type is "def (foo: builtins.int, bar: builtins.str) -> builtins.bytes" + +class Test2: + @Descriptor + def method(self, foo: int, *, bar: str) -> bytes: ... + +reveal_type(Test2().method) # N: Revealed type is "def (foo: builtins.int, *, bar: builtins.str) -> builtins.bytes" +[builtins fixtures/tuple.pyi] diff --git a/test-data/unit/check-statements.test b/test-data/unit/check-statements.test index d1464423e90f..44880cf35204 100644 --- a/test-data/unit/check-statements.test +++ b/test-data/unit/check-statements.test @@ -519,6 +519,13 @@ if object(): raise BaseException from f # E: Exception must be derived from BaseException [builtins fixtures/exception.pyi] +[case testRaiseNotImplementedFails] +if object(): + raise NotImplemented # E: Exception must be derived from BaseException; did you mean "NotImplementedError"? +if object(): + raise NotImplemented() # E: NotImplemented? not callable +[builtins fixtures/notimplemented.pyi] + [case testTryFinallyStatement] import typing try: diff --git a/test-data/unit/check-tuples.test b/test-data/unit/check-tuples.test index 972bccf8c24b..d675a35c4aae 100644 --- a/test-data/unit/check-tuples.test +++ b/test-data/unit/check-tuples.test @@ -1438,6 +1438,12 @@ reveal_type(t[x:]) # N: Revealed type is "builtins.tuple[Union[builtins.int, bu t[y:] # E: Slice index must be an integer, SupportsIndex or None [builtins fixtures/tuple.pyi] +[case testTupleSliceStepZeroNoCrash] +# This was crashing: https://github.com/python/mypy/issues/18062 +# TODO: emit better error when 0 is used for step +()[::0] # E: Ambiguous slice of a variadic tuple +[builtins fixtures/tuple.pyi] + [case testInferTupleTypeFallbackAgainstInstance] from typing import TypeVar, Generic, Tuple T = TypeVar('T') diff --git a/test-data/unit/check-type-promotion.test b/test-data/unit/check-type-promotion.test index e66153726e7d..d98d0c60e164 100644 --- a/test-data/unit/check-type-promotion.test +++ b/test-data/unit/check-type-promotion.test @@ -91,7 +91,7 @@ else: reveal_type(x) # N: Revealed type is "builtins.complex" # Note we make type precise, since type promotions are involved -reveal_type(x) # N: Revealed type is "Union[builtins.complex, builtins.int, builtins.float]" +reveal_type(x) # N: Revealed type is "builtins.complex" [builtins fixtures/primitives.pyi] [case testIntersectionUsingPromotion3] @@ -127,7 +127,7 @@ if isinstance(x, int): reveal_type(x) # N: Revealed type is "builtins.int" else: reveal_type(x) # N: Revealed type is "Union[builtins.float, builtins.complex]" -reveal_type(x) # N: Revealed type is "Union[builtins.int, builtins.float, builtins.complex]" +reveal_type(x) # N: Revealed type is "Union[builtins.float, builtins.complex]" [builtins fixtures/primitives.pyi] [case testIntersectionUsingPromotion6] @@ -139,7 +139,7 @@ if isinstance(x, int): reveal_type(x) # N: Revealed type is "builtins.int" else: reveal_type(x) # N: Revealed type is "Union[builtins.str, builtins.complex]" -reveal_type(x) # N: Revealed type is "Union[builtins.str, builtins.int, builtins.complex]" +reveal_type(x) # N: Revealed type is "Union[builtins.str, builtins.complex]" [builtins fixtures/primitives.pyi] [case testIntersectionUsingPromotion7] diff --git a/test-data/unit/check-typeddict.test b/test-data/unit/check-typeddict.test index e1797421636e..a30fec1b9422 100644 --- a/test-data/unit/check-typeddict.test +++ b/test-data/unit/check-typeddict.test @@ -3894,6 +3894,20 @@ accepts_B(b) [builtins fixtures/dict.pyi] [typing fixtures/typing-typeddict.pyi] +[case testTypedDictRequiredConsistentWithNotRequiredReadOnly] +from typing import NotRequired, ReadOnly, Required, TypedDict + +class A(TypedDict): + x: NotRequired[ReadOnly[str]] + +class B(TypedDict): + x: Required[str] + +def f(b: B): + a: A = b # ok +[builtins fixtures/dict.pyi] +[typing fixtures/typing-typeddict.pyi] + [case testTypedDictReadOnlyCall] from typing import ReadOnly, TypedDict @@ -3988,3 +4002,54 @@ class TP(TypedDict): k: ReadOnly # E: "ReadOnly[]" must have exactly one type argument [builtins fixtures/dict.pyi] [typing fixtures/typing-typeddict.pyi] + +[case testTypedDictAnnotatedWithSpecialForms] +from typing import NotRequired, ReadOnly, Required, TypedDict +from typing_extensions import Annotated + +class A(TypedDict): + a: Annotated[NotRequired[ReadOnly[int]], ""] # ok + b: NotRequired[ReadOnly[Annotated[int, ""]]] # ok +[builtins fixtures/dict.pyi] +[typing fixtures/typing-typeddict.pyi] + +[case testTypedDictReadOnlyCovariant] +from typing import ReadOnly, TypedDict, Union + +class A(TypedDict): + a: ReadOnly[Union[int, str]] + +class A2(TypedDict): + a: ReadOnly[int] + +class B(TypedDict): + a: int + +class B2(TypedDict): + a: Union[int, str] + +class B3(TypedDict): + a: int + +def fa(a: A) -> None: ... +def fa2(a: A2) -> None: ... + +b: B = {"a": 1} +fa(b) +fa2(b) +b2: B2 = {"a": 1} +fa(b2) +fa2(b2) # E: Argument 1 to "fa2" has incompatible type "B2"; expected "A2" + +class C(TypedDict): + a: ReadOnly[Union[int, str]] + b: Union[str, bytes] + +class D(TypedDict): + a: int + b: str + +d: D = {"a": 1, "b": "x"} +c: C = d # E: Incompatible types in assignment (expression has type "D", variable has type "C") +[builtins fixtures/dict.pyi] +[typing fixtures/typing-typeddict.pyi] diff --git a/test-data/unit/check-typeguard.test b/test-data/unit/check-typeguard.test index 27b88553fb43..e7a8eac4f043 100644 --- a/test-data/unit/check-typeguard.test +++ b/test-data/unit/check-typeguard.test @@ -87,6 +87,15 @@ def main(a: Tuple[T, ...]): reveal_type(a) # N: Revealed type is "Tuple[T`-1, T`-1]" [builtins fixtures/tuple.pyi] +[case testTypeGuardPassedAsTypeVarIsBool] +from typing import Callable, TypeVar +from typing_extensions import TypeGuard +T = TypeVar('T') +def is_str(x: object) -> TypeGuard[str]: ... +def main(f: Callable[[object], T]) -> T: ... +reveal_type(main(is_str)) # N: Revealed type is "builtins.bool" +[builtins fixtures/tuple.pyi] + [case testTypeGuardNonOverlapping] from typing import List from typing_extensions import TypeGuard diff --git a/test-data/unit/check-typeis.test b/test-data/unit/check-typeis.test index 6b96845504ab..2372f990fda1 100644 --- a/test-data/unit/check-typeis.test +++ b/test-data/unit/check-typeis.test @@ -104,6 +104,15 @@ def main(x: object, type_check_func: Callable[[object], TypeIs[T]]) -> T: reveal_type(main("a", is_str)) # N: Revealed type is "builtins.str" [builtins fixtures/exception.pyi] +[case testTypeIsPassedAsTypeVarIsBool] +from typing import Callable, TypeVar +from typing_extensions import TypeIs +T = TypeVar('T') +def is_str(x: object) -> TypeIs[str]: pass +def main(f: Callable[[object], T]) -> T: pass +reveal_type(main(is_str)) # N: Revealed type is "builtins.bool" +[builtins fixtures/tuple.pyi] + [case testTypeIsUnionIn] from typing import Union from typing_extensions import TypeIs diff --git a/test-data/unit/check-typevar-defaults.test b/test-data/unit/check-typevar-defaults.test index 9ca67376da26..93d20eb26f6e 100644 --- a/test-data/unit/check-typevar-defaults.test +++ b/test-data/unit/check-typevar-defaults.test @@ -1,5 +1,4 @@ [case testTypeVarDefaultsBasic] -import builtins from typing import Generic, TypeVar, ParamSpec, Callable, Tuple, List from typing_extensions import TypeVarTuple, Unpack @@ -10,7 +9,7 @@ Ts1 = TypeVarTuple("Ts1", default=Unpack[Tuple[int, str]]) def f1(a: T1) -> List[T1]: ... reveal_type(f1) # N: Revealed type is "def [T1 = builtins.int] (a: T1`-1 = builtins.int) -> builtins.list[T1`-1 = builtins.int]" -def f2(a: Callable[P1, None] ) -> Callable[P1, None]: ... +def f2(a: Callable[P1, None]) -> Callable[P1, None]: ... reveal_type(f2) # N: Revealed type is "def [P1 = [builtins.int, builtins.str]] (a: def (*P1.args, **P1.kwargs)) -> def (*P1.args, **P1.kwargs)" def f3(a: Tuple[Unpack[Ts1]]) -> Tuple[Unpack[Ts1]]: ... @@ -68,7 +67,7 @@ P2 = ParamSpec("P2", default=2) # E: The default argument to ParamSpec must be P3 = ParamSpec("P3", default=(2, int)) # E: The default argument to ParamSpec must be a list expression, ellipsis, or a ParamSpec P4 = ParamSpec("P4", default=[2, int]) # E: Argument 0 of ParamSpec default must be a type -Ts1 = TypeVarTuple("Ts1", default=2) # E: The default argument to TypeVarTuple must be an Unpacked tuple +Ts1 = TypeVarTuple("Ts1", default=2) # E: The default argument to TypeVarTuple must be an Unpacked tuple Ts2 = TypeVarTuple("Ts2", default=int) # E: The default argument to TypeVarTuple must be an Unpacked tuple Ts3 = TypeVarTuple("Ts3", default=Tuple[int]) # E: The default argument to TypeVarTuple must be an Unpacked tuple [builtins fixtures/tuple.pyi] @@ -181,8 +180,8 @@ reveal_type(func_b1(callback1)) # N: Revealed type is "def (x: builtins.str)" reveal_type(func_b1(2)) # N: Revealed type is "def (builtins.int, builtins.str)" def func_c1(x: Union[int, Callable[[Unpack[Ts1]], None]]) -> Tuple[Unpack[Ts1]]: ... -# reveal_type(func_c1(callback1)) # Revealed type is "builtins.tuple[str]" # TODO -# reveal_type(func_c1(2)) # Revealed type is "builtins.tuple[builtins.int, builtins.str]" # TODO +# reveal_type(func_c1(callback1)) # Revealed type is "Tuple[str]" # TODO +reveal_type(func_c1(2)) # N: Revealed type is "Tuple[builtins.int, builtins.str]" [builtins fixtures/tuple.pyi] [case testTypeVarDefaultsClass1] @@ -717,3 +716,36 @@ def func_d3( reveal_type(c) # N: Revealed type is "__main__.B[__main__.A[builtins.dict[builtins.int, builtins.float]]]" reveal_type(d) # N: Revealed type is "__main__.B[builtins.int]" [builtins fixtures/dict.pyi] + +[case testTypeVarDefaultsAndTypeObjectTypeInUnion] +from __future__ import annotations +from typing import Generic +from typing_extensions import TypeVar + +_I = TypeVar("_I", default=int) + +class C(Generic[_I]): pass + +t: type[C] | int = C +[builtins fixtures/tuple.pyi] + + + +[case testGenericTypeAliasWithDefaultTypeVarPreservesNoneInDefault] +from typing_extensions import TypeVar +from typing import Generic, Union + +T1 = TypeVar("T1", default=Union[int, None]) +T2 = TypeVar("T2", default=Union[int, None]) + + +class A(Generic[T1, T2]): + def __init__(self, a: T1, b: T2) -> None: + self.a = a + self.b = b + + +MyA = A[T1, int] +a: MyA = A(None, 10) +reveal_type(a.a) # N: Revealed type is "Union[builtins.int, None]" +[builtins fixtures/tuple.pyi] diff --git a/test-data/unit/check-unreachable-code.test b/test-data/unit/check-unreachable-code.test index cbad1bd5449e..e6818ab5c3c7 100644 --- a/test-data/unit/check-unreachable-code.test +++ b/test-data/unit/check-unreachable-code.test @@ -1000,6 +1000,16 @@ class Test4(Generic[T3]): [builtins fixtures/isinstancelist.pyi] +[case testUnreachableBlockStaysUnreachableWithTypeVarConstraints] +# flags: --always-false COMPILE_TIME_FALSE +from typing import TypeVar +COMPILE_TIME_FALSE = False +T = TypeVar("T", int, str) +def foo(x: T) -> T: + if COMPILE_TIME_FALSE: + return "bad" + return x + [case testUnreachableFlagContextManagersNoSuppress] # flags: --warn-unreachable from contextlib import contextmanager diff --git a/test-data/unit/check-varargs.test b/test-data/unit/check-varargs.test index 2495a883aa71..bb0e80acee1e 100644 --- a/test-data/unit/check-varargs.test +++ b/test-data/unit/check-varargs.test @@ -268,17 +268,19 @@ f(a, *(b, cc)) [builtins fixtures/tuple.pyi] [case testInvalidVarArg] -# flags: --no-strict-optional def f(a: 'A') -> None: pass class A: pass -a = None # type: A +a = A() -f(*None) -f(*a) # E: List or tuple expected as variadic arguments +f(*None) # E: Expected iterable as variadic argument +f(*a) # E: Expected iterable as variadic argument f(*(a,)) + +f(*4) # E: Expected iterable as variadic argument +f(a, *4) # E: Expected iterable as variadic argument [builtins fixtures/tuple.pyi] @@ -543,9 +545,9 @@ if int(): if int(): b, b = f(b, b, *aa) # E: Argument 3 to "f" has incompatible type "*List[A]"; expected "B" if int(): - a, b = f(a, *a) # E: List or tuple expected as variadic arguments + a, b = f(a, *a) # E: Expected iterable as variadic argument if int(): - a, b = f(*a) # E: List or tuple expected as variadic arguments + a, b = f(*a) # E: Expected iterable as variadic argument if int(): a, a = f(*aa) @@ -737,7 +739,7 @@ bar(*good1) bar(*good2) bar(*good3) bar(*bad1) # E: Argument 1 to "bar" has incompatible type "*I[str]"; expected "float" -bar(*bad2) # E: List or tuple expected as variadic arguments +bar(*bad2) # E: Expected iterable as variadic argument [builtins fixtures/dict.pyi] -- Keyword arguments unpacking diff --git a/test-data/unit/cmdline.test b/test-data/unit/cmdline.test index 2262b7e7280c..2bab19e0d42f 100644 --- a/test-data/unit/cmdline.test +++ b/test-data/unit/cmdline.test @@ -153,18 +153,6 @@ FLAG = False if not FLAG: x = "unreachable" -[case testErrorContextConfig] -# cmd: mypy main.py -[file mypy.ini] -\[mypy] -show_error_context=True -[file main.py] -def f() -> None: - 0 + "" -[out] -main.py: note: In function "f": -main.py:2: error: Unsupported operand types for + ("int" and "str") - [case testAltConfigFile] # cmd: mypy --config-file config.ini main.py [file config.ini] @@ -176,43 +164,6 @@ FLAG = False if not FLAG: x = "unreachable" -[case testNoConfigFile] -# cmd: mypy main.py --config-file= -[file mypy.ini] -\[mypy] -warn_unused_ignores = True -[file main.py] -# type: ignore - -[case testPerFileConfigSection] -# cmd: mypy x.py y.py z.py -[file mypy.ini] -\[mypy] -disallow_untyped_defs = True -\[mypy-y] -disallow_untyped_defs = False -\[mypy-z] -disallow_untyped_calls = True -[file x.py] -def f(a): - pass -def g(a: int) -> int: - return f(a) -[file y.py] -def f(a): - pass -def g(a: int) -> int: - return f(a) -[file z.py] -def f(a): - pass -def g(a: int) -> int: - return f(a) -[out] -z.py:1: error: Function is missing a type annotation -z.py:4: error: Call to untyped function "f" in typed context -x.py:1: error: Function is missing a type annotation - [case testPerFileConfigSectionMultipleMatchesDisallowed] # cmd: mypy xx.py xy.py yx.py yy.py [file mypy.ini] @@ -326,43 +277,6 @@ file.py:1: error: Cannot find implementation or library stub for module named "n file.py:1: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports file.py:6: error: Argument 1 to "foo" has incompatible type "str"; expected "int" -[case testIgnoreErrorsConfig] -# cmd: mypy x.py y.py -[file mypy.ini] -\[mypy] -\[mypy-x] -ignore_errors = True -[file x.py] -x: str = 5 -[file y.py] -x: str = 5 -[out] -y.py:1: error: Incompatible types in assignment (expression has type "int", variable has type "str") - -[case testConfigFollowImportsNormal] -# cmd: mypy main.py -[file main.py] -from a import x -x + 0 -x + '' # E -import a -a.x + 0 -a.x + '' # E -a.y # E -a + 0 # E -[file mypy.ini] -\[mypy] -follow_imports = normal -[file a.py] -x = 0 -x += '' # Error reported here -[out] -a.py:2: error: Unsupported operand types for + ("int" and "str") -main.py:3: error: Unsupported operand types for + ("int" and "str") -main.py:6: error: Unsupported operand types for + ("int" and "str") -main.py:7: error: Module has no attribute "y" -main.py:8: error: Unsupported operand types for + (Module and "int") - [case testConfigFollowImportsSysPath] # cmd: mypy main.py [file main.py] @@ -389,102 +303,6 @@ main.py:6: error: Unsupported operand types for + ("int" and "str") main.py:7: error: Module has no attribute "y" main.py:8: error: Unsupported operand types for + (Module and "int") -[case testConfigFollowImportsSilent] -# cmd: mypy main.py -[file main.py] -from a import x -x + '' -import a -a.x + '' -a.y -a + 0 -[file mypy.ini] -\[mypy] -follow_imports = silent -[file a.py] -x = 0 -x += '' # No error reported -[out] -main.py:2: error: Unsupported operand types for + ("int" and "str") -main.py:4: error: Unsupported operand types for + ("int" and "str") -main.py:5: error: Module has no attribute "y" -main.py:6: error: Unsupported operand types for + (Module and "int") - -[case testConfigFollowImportsSkip] -# cmd: mypy main.py -[file main.py] -from a import x -reveal_type(x) # Expect Any -import a -reveal_type(a.x) # Expect Any -[file mypy.ini] -\[mypy] -follow_imports = skip -[file a.py] -/ # No error reported -[out] -main.py:2: note: Revealed type is "Any" -main.py:4: note: Revealed type is "Any" -== Return code: 0 - -[case testConfigFollowImportsError] -# cmd: mypy main.py -[file main.py] -from a import x # Error reported here -reveal_type(x) # Expect Any -import a -reveal_type(a.x) # Expect Any -[file mypy.ini] -\[mypy] -follow_imports = error -[file a.py] -/ # No error reported -[out] -main.py:1: error: Import of "a" ignored -main.py:1: note: (Using --follow-imports=error, module not passed on command line) -main.py:2: note: Revealed type is "Any" -main.py:4: note: Revealed type is "Any" - -[case testConfigFollowImportsSelective] -# cmd: mypy main.py -[file mypy.ini] -\[mypy] -\[mypy-normal] -follow_imports = normal -\[mypy-silent] -follow_imports = silent -\[mypy-skip] -follow_imports = skip -\[mypy-error] -follow_imports = error -[file main.py] -import normal -import silent -import skip -import error -reveal_type(normal.x) -reveal_type(silent.x) -reveal_type(skip) -reveal_type(error) -[file normal.py] -x = 0 -x += '' -[file silent.py] -x = 0 -x += '' -[file skip.py] -bla bla -[file error.py] -bla bla -[out] -normal.py:2: error: Unsupported operand types for + ("int" and "str") -main.py:4: error: Import of "error" ignored -main.py:4: note: (Using --follow-imports=error, module not passed on command line) -main.py:5: note: Revealed type is "builtins.int" -main.py:6: note: Revealed type is "builtins.int" -main.py:7: note: Revealed type is "Any" -main.py:8: note: Revealed type is "Any" - [case testConfigFollowImportsInvalid] # cmd: mypy main.py [file mypy.ini] @@ -495,31 +313,6 @@ follow_imports =True mypy.ini: [mypy]: follow_imports: invalid choice 'True' (choose from 'normal', 'silent', 'skip', 'error') == Return code: 0 -[case testConfigSilentMissingImportsOff] -# cmd: mypy main.py -[file main.py] -import missing # Expect error here -reveal_type(missing.x) # Expect Any -[file mypy.ini] -\[mypy] -ignore_missing_imports = False -[out] -main.py:1: error: Cannot find implementation or library stub for module named "missing" -main.py:1: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports -main.py:2: note: Revealed type is "Any" - -[case testConfigSilentMissingImportsOn] -# cmd: mypy main.py -[file main.py] -import missing # No error here -reveal_type(missing.x) # Expect Any -[file mypy.ini] -\[mypy] -ignore_missing_imports = True -[out] -main.py:2: note: Revealed type is "Any" -== Return code: 0 - [case testFailedImportOnWrongCWD] # cmd: mypy main.py # cwd: main/subdir1/subdir2 @@ -683,21 +476,10 @@ int_pow.py:11: note: Revealed type is "Any" python_version = 3.8 \[mypy-m] disallow_any_generics = True - [file m.py] -s = tuple([1, 2, 3]) # no error - -def f(t: tuple) -> None: pass -def g() -> list: pass -def h(s: dict) -> None: pass -def i(s: set) -> None: pass def j(s: frozenset) -> None: pass [out] -m.py:3: error: Implicit generic "Any". Use "typing.Tuple" and specify generic parameters -m.py:4: error: Implicit generic "Any". Use "typing.List" and specify generic parameters -m.py:5: error: Implicit generic "Any". Use "typing.Dict" and specify generic parameters -m.py:6: error: Implicit generic "Any". Use "typing.Set" and specify generic parameters -m.py:7: error: Implicit generic "Any". Use "typing.FrozenSet" and specify generic parameters +m.py:1: error: Implicit generic "Any". Use "typing.FrozenSet" and specify generic parameters [case testDisallowAnyGenericsTypingCollections] # cmd: mypy m.py @@ -705,21 +487,11 @@ m.py:7: error: Implicit generic "Any". Use "typing.FrozenSet" and specify generi \[mypy] \[mypy-m] disallow_any_generics = True - [file m.py] -from typing import Tuple, List, Dict, Set, FrozenSet - -def f(t: Tuple) -> None: pass -def g() -> List: pass -def h(s: Dict) -> None: pass -def i(s: Set) -> None: pass +from typing import FrozenSet def j(s: FrozenSet) -> None: pass [out] -m.py:3: error: Missing type parameters for generic type "Tuple" -m.py:4: error: Missing type parameters for generic type "List" -m.py:5: error: Missing type parameters for generic type "Dict" -m.py:6: error: Missing type parameters for generic type "Set" -m.py:7: error: Missing type parameters for generic type "FrozenSet" +m.py:2: error: Missing type parameters for generic type "FrozenSet" [case testSectionInheritance] # cmd: mypy a @@ -756,18 +528,6 @@ ignore_errors = False a/b/c/d/e/__init__.py:2: error: Missing type parameters for generic type "List" a/b/c/d/e/__init__.py:3: error: Argument 1 to "g" has incompatible type "None"; expected "List[Any]" -[case testDisallowUntypedDefsAndGenerics] -# cmd: mypy a.py -[file mypy.ini] -\[mypy] -disallow_untyped_defs = True -disallow_any_generics = True -[file a.py] -def get_tasks(self): - return 'whatever' -[out] -a.py:1: error: Function is missing a return type annotation - [case testMissingFile] # cmd: mypy nope.py [out] @@ -775,26 +535,6 @@ mypy: can't read file 'nope.py': No such file or directory == Return code: 2 --' -[case testParseError] -# cmd: mypy a.py -[file a.py] -def foo( -[out] -a.py:1: error: unexpected EOF while parsing -== Return code: 2 -[out version>=3.10] -a.py:1: error: '(' was never closed -== Return code: 2 - -[case testParseErrorAnnots] -# cmd: mypy a.py -[file a.py] -def foo(x): - # type: (str, int) -> None - return -[out] -a.py:1: error: Type signature has too many arguments - [case testModulesAndPackages] # cmd: mypy --package p.a --package p.b --module c [file p/__init__.py] @@ -914,6 +654,23 @@ s4.py:2: error: Incompatible return value type (got "int", expected "str") s3.py:2: error: Incompatible return value type (got "List[int]", expected "int") s1.py:2: error: Incompatible return value type (got "int", expected "str") +[case testShadowFileWithPretty] +# cmd: mypy a.py --pretty --shadow-file a.py b.py +[file a.py] +b: bytes +[file b.py] +a: int = "" +b: bytes = 1 +[out] +a.py:1: error: Incompatible types in assignment (expression has type "str", +variable has type "int") + a: int = "" + ^~ +a.py:2: error: Incompatible types in assignment (expression has type "int", +variable has type "bytes") + b: bytes = 1 + ^ + [case testConfigWarnUnusedSection1] # cmd: mypy foo.py quux.py spam/eggs.py [file mypy.ini] @@ -1472,15 +1229,6 @@ pass Warning: --new-type-inference flag is deprecated; new type inference algorithm is already enabled by default == Return code: 0 -[case testNotesOnlyResultInExitSuccess] -# cmd: mypy a.py -[file a.py] -def f(): - x: int = "no" -[out] -a.py:2: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs -== Return code: 0 - [case testCustomTypeshedDirFilePassedExplicitly] # cmd: mypy --custom-typeshed-dir dir m.py dir/stdlib/foo.pyi [file m.py] diff --git a/test-data/unit/daemon.test b/test-data/unit/daemon.test index ca2c969d2f5e..7dfddd8f74df 100644 --- a/test-data/unit/daemon.test +++ b/test-data/unit/daemon.test @@ -263,6 +263,38 @@ mypy-daemon: error: Missing target module, package, files, or command. $ dmypy stop Daemon stopped +[case testDaemonRunTwoFilesFullTypeshed] +$ dmypy run x.py +Daemon started +Success: no issues found in 1 source file +$ dmypy run y.py +Success: no issues found in 1 source file +$ dmypy run x.py +Success: no issues found in 1 source file +[file x.py] +[file y.py] + +[case testDaemonCheckTwoFilesFullTypeshed] +$ dmypy start +Daemon started +$ dmypy check foo.py +foo.py:3: error: Incompatible types in assignment (expression has type "str", variable has type "int") [assignment] +Found 1 error in 1 file (checked 1 source file) +== Return code: 1 +$ dmypy check bar.py +Success: no issues found in 1 source file +$ dmypy check foo.py +foo.py:3: error: Incompatible types in assignment (expression has type "str", variable has type "int") [assignment] +Found 1 error in 1 file (checked 1 source file) +== Return code: 1 +[file foo.py] +from bar import add +x: str = add("a", "b") +x_error: int = add("a", "b") +[file bar.py] +def add(a, b) -> str: + return a + b + [case testDaemonWarningSuccessExitCode-posix] $ dmypy run -- foo.py --follow-imports=error --python-version=3.11 Daemon started diff --git a/test-data/unit/deps-classes.test b/test-data/unit/deps-classes.test index ebe2e9caed02..a8fc5d629491 100644 --- a/test-data/unit/deps-classes.test +++ b/test-data/unit/deps-classes.test @@ -178,6 +178,7 @@ def g() -> None: A.X [file m.py] class B: pass +[builtins fixtures/enum.pyi] [out] -> m.g -> , m.A, m.f, m.g diff --git a/test-data/unit/deps-types.test b/test-data/unit/deps-types.test index def117fe04df..6992a5bdec00 100644 --- a/test-data/unit/deps-types.test +++ b/test-data/unit/deps-types.test @@ -905,6 +905,7 @@ def g() -> None: A.X [file mod.py] class B: pass +[builtins fixtures/tuple.pyi] [out] -> m.g -> , m.f, m.g diff --git a/test-data/unit/diff.test b/test-data/unit/diff.test index 10fb0a80cf38..4acf451e2c34 100644 --- a/test-data/unit/diff.test +++ b/test-data/unit/diff.test @@ -566,6 +566,7 @@ A = Enum('A', 'x') B = Enum('B', 'y') C = IntEnum('C', 'x') D = IntEnum('D', 'x y') +[builtins fixtures/enum.pyi] [out] __main__.B.x __main__.B.y @@ -605,6 +606,7 @@ class D(Enum): Y = 'b' class F(Enum): X = 0 +[builtins fixtures/enum.pyi] [out] __main__.B.Y __main__.B.Z diff --git a/test-data/unit/fine-grained-python312.test b/test-data/unit/fine-grained-python312.test index 0e438ca06574..2cb2148a66fe 100644 --- a/test-data/unit/fine-grained-python312.test +++ b/test-data/unit/fine-grained-python312.test @@ -95,3 +95,23 @@ def f(x: int) -> None: pass [out] == main:7: error: Missing positional argument "x" in call to "f" + +[case testPEP695MultipleNestedGenericClassMethodUpdated] +from a import f + +class A: + class C: + class D[T]: + x: T + def m(self) -> T: + f() + return self.x + +[file a.py] +def f() -> None: pass + +[file a.py.2] +def f(x: int) -> None: pass +[out] +== +main:8: error: Missing positional argument "x" in call to "f" diff --git a/test-data/unit/fine-grained.test b/test-data/unit/fine-grained.test index faedd890922d..9ff8a37ae9ae 100644 --- a/test-data/unit/fine-grained.test +++ b/test-data/unit/fine-grained.test @@ -5355,6 +5355,7 @@ c: C c = C.X if int(): c = 1 +[builtins fixtures/enum.pyi] [out] == == @@ -5386,6 +5387,7 @@ if int(): n = C.X if int(): n = c +[builtins fixtures/enum.pyi] [out] == == @@ -5410,6 +5412,7 @@ from enum import Enum class C(Enum): X = 0 +[builtins fixtures/tuple.pyi] [typing fixtures/typing-medium.pyi] [out] == @@ -5432,6 +5435,7 @@ from enum import Enum class C(Enum): X = 0 Y = 1 +[builtins fixtures/enum.pyi] [out] == a.py:4: error: Argument 1 to "f" has incompatible type "C"; expected "int" @@ -5456,6 +5460,7 @@ c: C c = C.X if int(): c = 1 +[builtins fixtures/tuple.pyi] [out] == == @@ -5485,6 +5490,7 @@ if int(): n: int n = C.X n = c +[builtins fixtures/enum.pyi] [out] == == @@ -5506,6 +5512,7 @@ C = Enum('C', 'X Y') from enum import Enum C = Enum('C', 'X') +[builtins fixtures/tuple.pyi] [typing fixtures/typing-medium.pyi] [out] == @@ -5526,6 +5533,7 @@ class C: [file b.py.2] from enum import Enum C = Enum('C', [('X', 0), ('Y', 1)]) +[builtins fixtures/tuple.pyi] [out] == a.py:4: error: Argument 1 to "f" has incompatible type "C"; expected "int" @@ -10573,3 +10581,583 @@ m.py:9: error: Argument 1 to "foo" has incompatible type "int"; expected "str" m.py:9: error: Argument 2 to "foo" has incompatible type "str"; expected "int" m.py:10: error: Unexpected keyword argument "a" for "foo" partial.py:4: note: "foo" defined here + +[case testReplaceFunctionWithDecoratedFunctionIndirect] +from b import f +x: int = f() +import b +y: int = b.f() + +[file b.py] +from a import f + +[file a.py] +def f() -> int: ... + +[file a.py.2] +from typing import Callable +def d(t: Callable[[], str]) -> Callable[[], str]: ... + +@d +def f() -> str: ... + +[builtins fixtures/tuple.pyi] +[out] +== +main:2: error: Incompatible types in assignment (expression has type "str", variable has type "int") +main:4: error: Incompatible types in assignment (expression has type "str", variable has type "int") + +[case testReplaceFunctionWithDecoratedFunctionIndirect2] +from c import f +x: int = f() +import c +y: int = c.f() + +[file c.py] +from b import f + +[file b.py] +from a import f + +[file a.py] +def f() -> int: ... + +[file a.py.2] +from typing import Callable +def d(t: Callable[[], str]) -> Callable[[], str]: ... + +@d +def f() -> str: ... + +[builtins fixtures/tuple.pyi] +[out] +== +main:2: error: Incompatible types in assignment (expression has type "str", variable has type "int") +main:4: error: Incompatible types in assignment (expression has type "str", variable has type "int") + +[case testReplaceFunctionWithClassIndirect] +from b import f +x: int = f() +import b +y: int = b.f() + +[file b.py] +from a import f + +[file a.py] +def f() -> int: ... + +[file a.py.2] +class f: ... + +[builtins fixtures/tuple.pyi] +[out] +== +main:2: error: Incompatible types in assignment (expression has type "f", variable has type "int") +main:4: error: Incompatible types in assignment (expression has type "f", variable has type "int") + +[case testReplaceFunctionWithClassIndirect2] +from c import f +x: int = f() +import c +y: int = c.f() + +[file c.py] +from b import f + +[file b.py] +from a import f + +[file a.py] +def f() -> int: ... + +[file a.py.2] +class f: ... + +[builtins fixtures/tuple.pyi] +[out] +== +main:2: error: Incompatible types in assignment (expression has type "f", variable has type "int") +main:4: error: Incompatible types in assignment (expression has type "f", variable has type "int") + + +[case testDeprecatedAddKeepChangeAndRemoveFunctionDeprecation] +# flags: --enable-error-code=deprecated + +from a import f +f() +import a +a.f() + +[file a.py] +def f() -> None: ... + +[file a.py.2] +from typing_extensions import deprecated +@deprecated("use f2 instead") +def f() -> None: ... + +[file a.py.3] +from typing_extensions import deprecated +@deprecated("use f2 instead") +def f() -> None: ... + +[file a.py.4] +from typing_extensions import deprecated +@deprecated("use f3 instead") +def f() -> None: ... + +[file a.py.5] +def f() -> None: ... + +[builtins fixtures/tuple.pyi] +[out] +== +main:3: error: function a.f is deprecated: use f2 instead +main:6: error: function a.f is deprecated: use f2 instead +== +main:3: error: function a.f is deprecated: use f2 instead +main:6: error: function a.f is deprecated: use f2 instead +== +main:3: error: function a.f is deprecated: use f3 instead +main:6: error: function a.f is deprecated: use f3 instead +== + + +[case testDeprecatedRemoveFunctionDeprecation] +# flags: --enable-error-code=deprecated +from a import f +f() +import a +a.f() + +[file a.py] +from typing_extensions import deprecated +@deprecated("use f2 instead") +def f() -> None: ... + +[file a.py.2] +def f() -> None: ... + +[builtins fixtures/tuple.pyi] +[out] +main:2: error: function a.f is deprecated: use f2 instead +main:5: error: function a.f is deprecated: use f2 instead +== + +[case testDeprecatedKeepFunctionDeprecation] +# flags: --enable-error-code=deprecated +from a import f +f() +import a +a.f() + +[file a.py] +from typing_extensions import deprecated +@deprecated("use f2 instead") +def f() -> None: ... + +[file a.py.2] +from typing_extensions import deprecated +@deprecated("use f2 instead") +def f() -> None: ... + +[builtins fixtures/tuple.pyi] +[out] +main:2: error: function a.f is deprecated: use f2 instead +main:5: error: function a.f is deprecated: use f2 instead +== +main:2: error: function a.f is deprecated: use f2 instead +main:5: error: function a.f is deprecated: use f2 instead + + +[case testDeprecatedAddFunctionDeprecationIndirectImport] +# flags: --enable-error-code=deprecated +from b import f +f() +import b +b.f() + +[file b.py] +from a import f + +[file a.py] +def f() -> int: ... + +[file a.py.2] +from typing_extensions import deprecated +@deprecated("use f2 instead") +def f() -> int: ... + +[builtins fixtures/tuple.pyi] +[out] +== +b.py:1: error: function a.f is deprecated: use f2 instead +main:2: error: function a.f is deprecated: use f2 instead +main:5: error: function a.f is deprecated: use f2 instead + + +[case testDeprecatedChangeFunctionDeprecationIndirectImport] +# flags: --enable-error-code=deprecated +from b import f +f() +import b +b.f() + +[file b.py] +from a import f + +[file a.py] +from typing_extensions import deprecated +@deprecated("use f1 instead") +def f() -> int: ... + +[file a.py.2] +from typing_extensions import deprecated +@deprecated("use f2 instead") +def f() -> int: ... + +[builtins fixtures/tuple.pyi] +[out] +b.py:1: error: function a.f is deprecated: use f1 instead +main:2: error: function a.f is deprecated: use f1 instead +main:5: error: function a.f is deprecated: use f1 instead +== +b.py:1: error: function a.f is deprecated: use f2 instead +main:2: error: function a.f is deprecated: use f2 instead +main:5: error: function a.f is deprecated: use f2 instead + +[case testDeprecatedRemoveFunctionDeprecationIndirectImport] +# flags: --enable-error-code=deprecated +from b import f +f() +import b +b.f() + +[file b.py] +from a import f + +[file a.py] +from typing_extensions import deprecated +@deprecated("use f1 instead") +def f() -> int: ... + +[file a.py.2] +def f() -> int: ... + +[builtins fixtures/tuple.pyi] +[out] +b.py:1: error: function a.f is deprecated: use f1 instead +main:2: error: function a.f is deprecated: use f1 instead +main:5: error: function a.f is deprecated: use f1 instead +== + + +[case testDeprecatedFunctionAlreadyDecorated1-only_when_cache] +# flags: --enable-error-code=deprecated +from b import f +x: str = f() +import b +y: str = b.f() + +[file b.py] +from a import f + +[file a.py] +from typing import Callable + +def d(t: Callable[[], str]) -> Callable[[], str]: ... + +@d +def f() -> str: ... + +[file a.py.2] +from typing import Callable +from typing_extensions import deprecated + +def d(t: Callable[[], str]) -> Callable[[], str]: ... + +@deprecated("deprecated decorated function") +@d +def f() -> str: ... + +[builtins fixtures/tuple.pyi] +[out] +== +b.py:1: error: function a.f is deprecated: deprecated decorated function +main:2: error: function a.f is deprecated: deprecated decorated function +main:5: error: function a.f is deprecated: deprecated decorated function + + +[case testDeprecatedFunctionAlreadyDecorated2-only_when_nocache] +# flags: --enable-error-code=deprecated +from b import f +x: str = f() +import b +y: str = b.f() + +[file b.py] +from a import f + +[file a.py] +from typing import Callable + +def d(t: Callable[[], str]) -> Callable[[], str]: ... + +@d +def f() -> str: ... + +[file a.py.2] +from typing import Callable +from typing_extensions import deprecated + +def d(t: Callable[[], str]) -> Callable[[], str]: ... + +@deprecated("deprecated decorated function") +@d +def f() -> str: ... + +[builtins fixtures/tuple.pyi] +[out] +== +main:2: error: function a.f is deprecated: deprecated decorated function +main:5: error: function a.f is deprecated: deprecated decorated function +b.py:1: error: function a.f is deprecated: deprecated decorated function + + +[case testDeprecatedAddClassDeprecationIndirectImport1-only_when_cache] +# flags: --enable-error-code=deprecated +from b import C +x: C +C() +import b +y: b.D +b.D() + +[file b.py] +from a import C +from a import D + +[file a.py] +class C: ... +class D: ... + +[file a.py.2] +from typing_extensions import deprecated + +@deprecated("use C2 instead") +class C: ... + +@deprecated("use D2 instead") +class D: ... + +[builtins fixtures/tuple.pyi] +[out] +== +b.py:1: error: class a.C is deprecated: use C2 instead +b.py:2: error: class a.D is deprecated: use D2 instead +main:2: error: class a.C is deprecated: use C2 instead +main:6: error: class a.D is deprecated: use D2 instead +main:7: error: class a.D is deprecated: use D2 instead + + +[case testDeprecatedAddClassDeprecationIndirectImport2-only_when_nocache] +# flags: --enable-error-code=deprecated +from b import C +x: C +C() +import b +y: b.D +b.D() + +[file b.py] +from a import C +from a import D + +[file a.py] +class C: ... +class D: ... + +[file a.py.2] +from typing_extensions import deprecated + +@deprecated("use C2 instead") +class C: ... + +@deprecated("use D2 instead") +class D: ... + +[builtins fixtures/tuple.pyi] +[out] +== +main:2: error: class a.C is deprecated: use C2 instead +main:6: error: class a.D is deprecated: use D2 instead +main:7: error: class a.D is deprecated: use D2 instead +b.py:1: error: class a.C is deprecated: use C2 instead +b.py:2: error: class a.D is deprecated: use D2 instead + + +[case testDeprecatedChangeClassDeprecationIndirectImport] +# flags: --enable-error-code=deprecated +from b import C +x: C +C() +import b +y: b.D +b.D() + +[file b.py] +from a import C +from a import D + +[file a.py] +from typing_extensions import deprecated + +@deprecated("use C1 instead") +class C: ... +@deprecated("use D1 instead") +class D: ... + +[file a.py.2] +from typing_extensions import deprecated + +@deprecated("use C2 instead") +class C: ... + +@deprecated("use D2 instead") +class D: ... + +[builtins fixtures/tuple.pyi] +[out] +b.py:1: error: class a.C is deprecated: use C1 instead +b.py:2: error: class a.D is deprecated: use D1 instead +main:2: error: class a.C is deprecated: use C1 instead +main:6: error: class a.D is deprecated: use D1 instead +main:7: error: class a.D is deprecated: use D1 instead +== +b.py:1: error: class a.C is deprecated: use C2 instead +b.py:2: error: class a.D is deprecated: use D2 instead +main:2: error: class a.C is deprecated: use C2 instead +main:6: error: class a.D is deprecated: use D2 instead +main:7: error: class a.D is deprecated: use D2 instead + + +[case testDeprecatedRemoveClassDeprecationIndirectImport] +# flags: --enable-error-code=deprecated +from b import C +x: C +C() +import b +y: b.D +b.D() + +[file b.py] +from a import C +from a import D + +[file a.py] +from typing_extensions import deprecated + +@deprecated("use C1 instead") +class C: ... +@deprecated("use D1 instead") +class D: ... + +[file a.py.2] +class C: ... +class D: ... + +[builtins fixtures/tuple.pyi] +[out] +b.py:1: error: class a.C is deprecated: use C1 instead +b.py:2: error: class a.D is deprecated: use D1 instead +main:2: error: class a.C is deprecated: use C1 instead +main:6: error: class a.D is deprecated: use D1 instead +main:7: error: class a.D is deprecated: use D1 instead +== + + +[case testDeprecatedAddClassDeprecationIndirectImportAlreadyDecorated1-only_when_cache] +# flags: --enable-error-code=deprecated +from b import C +x: C +C() +import b +y: b.D +b.D() + +[file b.py] +from a import C +from a import D + +[file a.py] +from typing import TypeVar + +T = TypeVar("T") +def dec(x: T) -> T: ... + +@dec +class C: ... +@dec +class D: ... + +[file a.py.2] +from typing_extensions import deprecated + +@deprecated("use C2 instead") +class C: ... + +@deprecated("use D2 instead") +class D: ... + +[builtins fixtures/tuple.pyi] +[out] +== +b.py:1: error: class a.C is deprecated: use C2 instead +b.py:2: error: class a.D is deprecated: use D2 instead +main:2: error: class a.C is deprecated: use C2 instead +main:6: error: class a.D is deprecated: use D2 instead +main:7: error: class a.D is deprecated: use D2 instead + + +[case testDeprecatedAddClassDeprecationIndirectImportAlreadyDecorated2-only_when_nocache] +# flags: --enable-error-code=deprecated +from b import C +x: C +C() +import b +y: b.D +b.D() + +[file b.py] +from a import C +from a import D + +[file a.py] +from typing import TypeVar + +T = TypeVar("T") +def dec(x: T) -> T: ... + +@dec +class C: ... +@dec +class D: ... + +[file a.py.2] +from typing_extensions import deprecated + +@deprecated("use C2 instead") +class C: ... + +@deprecated("use D2 instead") +class D: ... + +[builtins fixtures/tuple.pyi] +[out] +== +main:2: error: class a.C is deprecated: use C2 instead +main:6: error: class a.D is deprecated: use D2 instead +main:7: error: class a.D is deprecated: use D2 instead +b.py:1: error: class a.C is deprecated: use C2 instead +b.py:2: error: class a.D is deprecated: use D2 instead diff --git a/test-data/unit/fixtures/enum.pyi b/test-data/unit/fixtures/enum.pyi new file mode 100644 index 000000000000..debffacf8f32 --- /dev/null +++ b/test-data/unit/fixtures/enum.pyi @@ -0,0 +1,16 @@ +# Minimal set of builtins required to work with Enums +from typing import TypeVar, Generic + +T = TypeVar('T') + +class object: + def __init__(self): pass + +class type: pass +class tuple(Generic[T]): + def __getitem__(self, x: int) -> T: pass + +class int: pass +class str: pass +class dict: pass +class ellipsis: pass diff --git a/test-data/unit/fixtures/for.pyi b/test-data/unit/fixtures/for.pyi index 694f83e940b2..10f45e68cd7d 100644 --- a/test-data/unit/fixtures/for.pyi +++ b/test-data/unit/fixtures/for.pyi @@ -12,9 +12,11 @@ class type: pass class tuple(Generic[t]): def __iter__(self) -> Iterator[t]: pass class function: pass +class ellipsis: pass class bool: pass class int: pass # for convenience -class str: pass # for convenience +class str: # for convenience + def upper(self) -> str: ... class list(Iterable[t], Generic[t]): def __iter__(self) -> Iterator[t]: pass diff --git a/test-data/unit/fixtures/notimplemented.pyi b/test-data/unit/fixtures/notimplemented.pyi index 2ca376ea0760..92edf84a7fd1 100644 --- a/test-data/unit/fixtures/notimplemented.pyi +++ b/test-data/unit/fixtures/notimplemented.pyi @@ -1,6 +1,5 @@ # builtins stub used in NotImplemented related cases. -from typing import Any, cast - +from typing import Any class object: def __init__(self) -> None: pass @@ -10,5 +9,10 @@ class function: pass class bool: pass class int: pass class str: pass -NotImplemented = cast(Any, None) class dict: pass + +class _NotImplementedType(Any): + __call__: NotImplemented # type: ignore +NotImplemented: _NotImplementedType + +class BaseException: pass diff --git a/test-data/unit/fixtures/staticmethod.pyi b/test-data/unit/fixtures/staticmethod.pyi index 8a87121b2a71..a0ca831c7527 100644 --- a/test-data/unit/fixtures/staticmethod.pyi +++ b/test-data/unit/fixtures/staticmethod.pyi @@ -19,3 +19,4 @@ class str: pass class bytes: pass class ellipsis: pass class dict: pass +class tuple: pass diff --git a/test-data/unit/lib-stub/enum.pyi b/test-data/unit/lib-stub/enum.pyi index 0e0b8e025d9f..ccb3818b9d25 100644 --- a/test-data/unit/lib-stub/enum.pyi +++ b/test-data/unit/lib-stub/enum.pyi @@ -1,4 +1,5 @@ from typing import Any, TypeVar, Union, Type, Sized, Iterator +from typing_extensions import Literal _T = TypeVar('_T') @@ -7,6 +8,7 @@ class EnumMeta(type, Sized): def __iter__(self: Type[_T]) -> Iterator[_T]: pass def __reversed__(self: Type[_T]) -> Iterator[_T]: pass def __getitem__(self: Type[_T], name: str) -> _T: pass + def __bool__(self) -> Literal[True]: pass class Enum(metaclass=EnumMeta): def __new__(cls: Type[_T], value: object) -> _T: pass diff --git a/test-data/unit/lib-stub/typing_extensions.pyi b/test-data/unit/lib-stub/typing_extensions.pyi index d9d7067efe0f..cb054b0e6b4f 100644 --- a/test-data/unit/lib-stub/typing_extensions.pyi +++ b/test-data/unit/lib-stub/typing_extensions.pyi @@ -43,6 +43,8 @@ Required: _SpecialForm NotRequired: _SpecialForm ReadOnly: _SpecialForm +Self: _SpecialForm + @final class TypeAliasType: def __init__( diff --git a/test-data/unit/merge.test b/test-data/unit/merge.test index 19b1839f86c0..a6a64c75b2a3 100644 --- a/test-data/unit/merge.test +++ b/test-data/unit/merge.test @@ -1490,6 +1490,7 @@ from enum import Enum class A(Enum): X = 0 Y = 1 +[builtins fixtures/enum.pyi] [out] TypeInfo<0>( Name(target.A) diff --git a/test-data/unit/parse-errors.test b/test-data/unit/parse-errors.test index c6b1c00a6169..7b1078d3fa2f 100644 --- a/test-data/unit/parse-errors.test +++ b/test-data/unit/parse-errors.test @@ -151,6 +151,13 @@ x = 0 # type: A B #comment #7 [out] file:2: error: Syntax error in type comment "A B" +[case testMissingBracket] +def foo( +[out] +file:1: error: unexpected EOF while parsing +[out version>=3.10] +file:1: error: '(' was never closed + [case testInvalidSignatureInComment1] def f(): # type: x pass diff --git a/test-data/unit/parse-python313.test b/test-data/unit/parse-python313.test new file mode 100644 index 000000000000..efbafb0766f5 --- /dev/null +++ b/test-data/unit/parse-python313.test @@ -0,0 +1,80 @@ +[case testPEP696TypeAlias] +type A[T = int] = C[T] +[out] +MypyFile:1( + TypeAliasStmt:1( + NameExpr(A) + TypeParam( + T + Default( + int?)) + LambdaExpr:1( + Block:-1( + ReturnStmt:1( + IndexExpr:1( + NameExpr(C) + NameExpr(T))))))) + +[case testPEP696GenericFunction] +def f[T = int](): pass +class C[T = int]: pass +[out] +MypyFile:1( + FuncDef:1( + f + TypeParam( + T + Default( + int?)) + Block:1( + PassStmt:1())) + ClassDef:2( + C + TypeParam( + T + Default( + int?)) + PassStmt:2())) + +[case testPEP696ParamSpec] +def f[**P = [int, str]](): pass +class C[**P = [int, str]]: pass +[out] +[out] +MypyFile:1( + FuncDef:1( + f + TypeParam( + **P + Default( + )) + Block:1( + PassStmt:1())) + ClassDef:2( + C + TypeParam( + **P + Default( + )) + PassStmt:2())) + +[case testPEP696TypeVarTuple] +def f[*Ts = *tuple[str, int]](): pass +class C[*Ts = *tuple[str, int]]: pass +[out] +MypyFile:1( + FuncDef:1( + f + TypeParam( + *Ts + Default( + Unpack[tuple?[str?, int?]])) + Block:1( + PassStmt:1())) + ClassDef:2( + C + TypeParam( + *Ts + Default( + Unpack[tuple?[str?, int?]])) + PassStmt:2())) diff --git a/test-data/unit/pep561.test b/test-data/unit/pep561.test index 9969c2894c36..fb303a8fb5ec 100644 --- a/test-data/unit/pep561.test +++ b/test-data/unit/pep561.test @@ -187,6 +187,13 @@ b.bf(1) testNamespacePkgWStubsWithNamespacePackagesFlag.py:7: error: Argument 1 to "bf" has incompatible type "int"; expected "bool" testNamespacePkgWStubsWithNamespacePackagesFlag.py:8: error: Argument 1 to "bf" has incompatible type "int"; expected "bool" +[case testMissingPytypedFlag] +# pkgs: typedpkg_ns_b +# flags: --namespace-packages --follow-untyped-imports +import typedpkg_ns.b.bbb as b +b.bf("foo", "bar") +[out] +testMissingPytypedFlag.py:4: error: Too many arguments for "bf" [case testTypedPkgNamespaceRegFromImportTwiceMissing] # pkgs: typedpkg_ns_a diff --git a/test-data/unit/plugins/attrhook2.py b/test-data/unit/plugins/attrhook2.py index 2d41a0fdf52f..1ce318d2057b 100644 --- a/test-data/unit/plugins/attrhook2.py +++ b/test-data/unit/plugins/attrhook2.py @@ -12,6 +12,8 @@ def get_attribute_hook(self, fullname: str) -> Callable[[AttributeContext], Type return magic_field_callback if fullname == "m.Magic.nonexistent_field": return nonexistent_field_callback + if fullname == "m.Magic.no_assignment_field": + return no_assignment_field_callback return None @@ -24,5 +26,12 @@ def nonexistent_field_callback(ctx: AttributeContext) -> Type: return AnyType(TypeOfAny.from_error) +def no_assignment_field_callback(ctx: AttributeContext) -> Type: + if ctx.is_lvalue: + ctx.api.fail(f"Cannot assign to field", ctx.context) + return AnyType(TypeOfAny.from_error) + return ctx.default_attr_type + + def plugin(version: str) -> type[AttrPlugin]: return AttrPlugin diff --git a/test-data/unit/pythoneval.test b/test-data/unit/pythoneval.test index 89f01bff963e..70003545754c 100644 --- a/test-data/unit/pythoneval.test +++ b/test-data/unit/pythoneval.test @@ -11,138 +11,97 @@ print('hello, world') [out] hello, world -[case testReversed] +[case testMiscStdlibFeatures] +# Various legacy tests merged together to speed up test runtimes. + +def f(x: object) -> None: pass + +# testReversed from typing import Reversible -class A(Reversible): +class R(Reversible): def __iter__(self): return iter('oof') def __reversed__(self): return iter('foo') -print(list(reversed(range(5)))) -print(list(reversed([1,2,3]))) -print(list(reversed('abc'))) -print(list(reversed(A()))) -[out] --- Escape bracket at line beginning -\[4, 3, 2, 1, 0] -\[3, 2, 1] -\['c', 'b', 'a'] -\['f', 'o', 'o'] - -[case testIntAndFloatConversion] +f(list(reversed(range(5)))) +f(list(reversed([1,2,3]))) +f(list(reversed('abc'))) +f(list(reversed(R()))) + +# testIntAndFloatConversion from typing import SupportsInt, SupportsFloat class A(SupportsInt): def __int__(self): return 5 class B(SupportsFloat): def __float__(self): return 1.2 -print(int(1)) -print(int(6.2)) -print(int('3')) -print(int(b'4')) -print(int(A())) -print(float(-9)) -print(float(B())) -[out] -1 -6 -3 -4 -5 --9.0 -1.2 - -[case testAbs] +f(int(1)) +f(int(6.2)) +f(int('3')) +f(int(b'4')) +f(int(A())) +f(float(-9)) +f(float(B())) + +# testAbs from typing import SupportsAbs -class A(SupportsAbs[float]): +class Ab(SupportsAbs[float]): def __abs__(self) -> float: return 5.5 -print(abs(-1)) -print(abs(-1.2)) -print(abs(A())) -[out] -1 -1.2 -5.5 +f(abs(-1)) +f(abs(-1.2)) +f(abs(Ab())) -[case testAbs2] -n: int -f: float -n = abs(1) -abs(1) + 'x' # Error -f = abs(1.1) -abs(1.1) + 'x' # Error -[out] -_program.py:4: error: Unsupported operand types for + ("int" and "str") -_program.py:6: error: Unsupported operand types for + ("float" and "str") - -[case testRound] +# testRound from typing import SupportsRound -class A(SupportsRound): +class Ro(SupportsRound): def __round__(self, ndigits=0): return 'x%d' % ndigits -print(round(1.6)) -print(round(A())) -print(round(A(), 2)) -[out] -2 -x0 -x2 +f(round(1.6)) +f(round(Ro())) +f(round(Ro(), 2)) -[case testCallMethodViaTypeObject] -import typing -print(list.__add__([1, 2], [3, 4])) -[out] -\[1, 2, 3, 4] +# testCallMethodViaTypeObject +list.__add__([1, 2], [3, 4]) -[case testInheritedClassAttribute] +# testInheritedClassAttribute import typing -class A: +class AA: x = 1 - def f(self: typing.Optional["A"]) -> None: print('f') -class B(A): + def f(self: typing.Optional["AA"]) -> None: pass +class BB(AA): pass -B.f(None) -print(B.x) -[out] -f -1 +BB.f(None) +f(BB.x) -[case testModuleAttributes] -import math -import typing -print(type(__spec__)) -print(math.__name__) -print(math.__spec__.name) -print(type(math.__dict__)) -print(type(math.__doc__ or '')) -print(type(math.__spec__).__name__) -print(math.__class__) -[out] - -math -math - - -ModuleSpec - - -[case testSpecialAttributes] -import typing -class A: +# testSpecialAttributes +class Doc: """A docstring!""" -print(A().__doc__) -print(A().__class__) -[out] -A docstring! - +f(Doc().__doc__) +f(Doc().__class__) -[case testFunctionAttributes] -import typing -ord.__class__ -print(type(ord.__doc__ or '' + '')) -print(ord.__name__) -print(ord.__module__) +# testFunctionAttributes +f(ord.__class__) +f(type(ord.__doc__ or '' + '')) +f(ord.__name__) +f(ord.__module__) + +# testModuleAttributes +import math +f(type(__spec__)) +f(math.__name__) +f(math.__spec__.name) +f(type(math.__dict__)) +f(type(math.__doc__ or '')) +f(type(math.__spec__).__name__) +f(math.__class__) + +[case testAbs2] +n: int +f: float +n = abs(1) +abs(1) + 'x' # Error +f = abs(1.1) +abs(1.1) + 'x' # Error [out] - -ord -builtins +_program.py:4: error: Unsupported operand types for + ("int" and "str") +_program.py:6: error: Unsupported operand types for + ("float" and "str") [case testTypeAttributes] import typing @@ -283,7 +242,7 @@ f.write('x') f.write(b'x') f.foobar() [out] -_program.py:3: error: Argument 1 to "write" of "TextIOBase" has incompatible type "bytes"; expected "str" +_program.py:3: error: Argument 1 to "write" of "_TextIOBase" has incompatible type "bytes"; expected "str" _program.py:4: error: "TextIOWrapper[_WrappedBuffer]" has no attribute "foobar" [case testOpenReturnTypeInference] @@ -293,9 +252,9 @@ reveal_type(open('x', 'rb')) mode = 'rb' reveal_type(open('x', mode)) [out] -_program.py:1: note: Revealed type is "io.TextIOWrapper[io._WrappedBuffer]" -_program.py:2: note: Revealed type is "io.TextIOWrapper[io._WrappedBuffer]" -_program.py:3: note: Revealed type is "io.BufferedReader" +_program.py:1: note: Revealed type is "_io.TextIOWrapper[_io._WrappedBuffer]" +_program.py:2: note: Revealed type is "_io.TextIOWrapper[_io._WrappedBuffer]" +_program.py:3: note: Revealed type is "_io.BufferedReader" _program.py:5: note: Revealed type is "typing.IO[Any]" [case testOpenReturnTypeInferenceSpecialCases] @@ -304,8 +263,8 @@ reveal_type(open(file='x', mode='rb')) mode = 'rb' reveal_type(open(mode=mode, file='r')) [out] -_testOpenReturnTypeInferenceSpecialCases.py:1: note: Revealed type is "io.BufferedReader" -_testOpenReturnTypeInferenceSpecialCases.py:2: note: Revealed type is "io.BufferedReader" +_testOpenReturnTypeInferenceSpecialCases.py:1: note: Revealed type is "_io.BufferedReader" +_testOpenReturnTypeInferenceSpecialCases.py:2: note: Revealed type is "_io.BufferedReader" _testOpenReturnTypeInferenceSpecialCases.py:4: note: Revealed type is "typing.IO[Any]" [case testPathOpenReturnTypeInference] @@ -317,9 +276,9 @@ reveal_type(p.open('rb')) mode = 'rb' reveal_type(p.open(mode)) [out] -_program.py:3: note: Revealed type is "io.TextIOWrapper[io._WrappedBuffer]" -_program.py:4: note: Revealed type is "io.TextIOWrapper[io._WrappedBuffer]" -_program.py:5: note: Revealed type is "io.BufferedReader" +_program.py:3: note: Revealed type is "_io.TextIOWrapper[_io._WrappedBuffer]" +_program.py:4: note: Revealed type is "_io.TextIOWrapper[_io._WrappedBuffer]" +_program.py:5: note: Revealed type is "_io.BufferedReader" _program.py:7: note: Revealed type is "typing.IO[Any]" [case testPathOpenReturnTypeInferenceSpecialCases] @@ -330,8 +289,8 @@ reveal_type(p.open(errors='replace', mode='r')) mode = 'r' reveal_type(p.open(mode=mode, errors='replace')) [out] -_program.py:3: note: Revealed type is "io.TextIOWrapper[io._WrappedBuffer]" -_program.py:4: note: Revealed type is "io.TextIOWrapper[io._WrappedBuffer]" +_program.py:3: note: Revealed type is "_io.TextIOWrapper[_io._WrappedBuffer]" +_program.py:4: note: Revealed type is "_io.TextIOWrapper[_io._WrappedBuffer]" _program.py:6: note: Revealed type is "typing.IO[Any]" [case testGenericPatterns] @@ -954,7 +913,7 @@ a = [] # type: List[Dict[str, str]] sorted(a, key=lambda y: y['']) [case testAbstractProperty] -from abc import abstractproperty, ABCMeta +from abc import abstractproperty, ABCMeta # type: ignore[deprecated] class A(metaclass=ABCMeta): @abstractproperty def x(self) -> int: pass @@ -1596,18 +1555,6 @@ if isinstance(obj, Awaitable): _testSpecialTypingProtocols.py:6: note: Revealed type is "Tuple[builtins.int]" _testSpecialTypingProtocols.py:8: error: Statement is unreachable -[case testEnumValueWithPlaceholderNodeType] -# https://github.com/python/mypy/issues/11971 -from enum import Enum -from typing import Callable, Dict -class Foo(Enum): - Bar: Foo = Callable[[str], None] - Baz: Foo = Callable[[Dict[str, "Missing"]], None] -[out] -_testEnumValueWithPlaceholderNodeType.py:5: error: Incompatible types in assignment (expression has type "", variable has type "Foo") -_testEnumValueWithPlaceholderNodeType.py:6: error: Incompatible types in assignment (expression has type "", variable has type "Foo") -_testEnumValueWithPlaceholderNodeType.py:6: error: Name "Missing" is not defined - [case testTypeshedRecursiveTypesExample] from typing import List, Union @@ -2216,3 +2163,21 @@ class C3[T1, T2](tuple[T1, ...]): def func3(p: C3[int, object]): x: C3[int, int] = p + + +[case testDynamicClassAttribute] +# Some things that can break if DynamicClassAttribute isn't handled properly +from types import DynamicClassAttribute +from enum import Enum + +class TestClass: + @DynamicClassAttribute + def name(self) -> str: ... + +class TestClass2(TestClass, Enum): ... + +class Status(Enum): + ABORTED = -1 + +def imperfect(status: Status) -> str: + return status.name.lower() diff --git a/test-data/unit/semanal-errors.test b/test-data/unit/semanal-errors.test index 33c8f9b80aa0..2f0a4c140915 100644 --- a/test-data/unit/semanal-errors.test +++ b/test-data/unit/semanal-errors.test @@ -1060,6 +1060,22 @@ S = TypeVar('S', covariant=True, contravariant=True) \ # E: TypeVar cannot be both covariant and contravariant [builtins fixtures/bool.pyi] +[case testInvalidTypevarArgumentsGenericConstraint] +from typing import Generic, List, TypeVar +from typing_extensions import Self + +T = TypeVar("T") + +def f(x: T) -> None: + Bad = TypeVar("Bad", int, List[T]) # E: TypeVar constraint type cannot be parametrized by type variables +class C(Generic[T]): + Bad = TypeVar("Bad", int, List[T]) # E: TypeVar constraint type cannot be parametrized by type variables +class D: + Bad = TypeVar("Bad", int, List[Self]) # E: TypeVar constraint type cannot be parametrized by type variables +S = TypeVar("S", int, List[T]) # E: Type variable "__main__.T" is unbound \ + # N: (Hint: Use "Generic[T]" or "Protocol[T]" base class to bind "T" inside a class) \ + # N: (Hint: Use "T" in function signature to bind "T" inside a function) + [case testInvalidTypevarValues] from typing import TypeVar b = TypeVar('b', *[int]) # E: Unexpected argument to "TypeVar()" diff --git a/test-data/unit/stubgen.test b/test-data/unit/stubgen.test index 69781e9d2143..0801d9a27011 100644 --- a/test-data/unit/stubgen.test +++ b/test-data/unit/stubgen.test @@ -4415,3 +4415,114 @@ class Test(Whatever, a=1, b='b', c=True, d=1.5, e=None, f=1j, g=b'123'): ... class Test(Whatever, keyword=SomeName * 2, attr=SomeName.attr): ... [out] class Test(Whatever, keyword=SomeName * 2, attr=SomeName.attr): ... + +[case testPEP695GenericClass] +# flags: --python-version=3.12 + +class C[T]: ... +class C1[T1](int): ... +class C2[T2: int]: ... +class C3[T3: str | bytes]: ... +class C4[T4: (str, bytes)]: ... + +class Outer: + class Inner[T]: ... + +[out] +class C[T]: ... +class C1[T1](int): ... +class C2[T2: int]: ... +class C3[T3: str | bytes]: ... +class C4[T4: (str, bytes)]: ... + +class Outer: + class Inner[T]: ... + +[case testPEP695GenericFunction] +# flags: --python-version=3.12 + +def f1[T1](): ... +def f2[T2: int](): ... +def f3[T3: str | bytes](): ... +def f4[T4: (str, bytes)](): ... + +class C: + def m[T](self, x: T) -> T: ... + +[out] +def f1[T1]() -> None: ... +def f2[T2: int]() -> None: ... +def f3[T3: str | bytes]() -> None: ... +def f4[T4: (str, bytes)]() -> None: ... + +class C: + def m[T](self, x: T) -> T: ... + +[case testPEP695TypeAlias] +# flags: --python-version=3.12 + +type Alias = int | str +type Alias1[T1] = list[T1] | set[T1] +type Alias2[T2: int] = list[T2] | set[T2] +type Alias3[T3: str | bytes] = list[T3] | set[T3] +type Alias4[T4: (str, bytes)] = list[T4] | set[T4] + +class C: + type IndentedAlias[T] = list[T] + +[out] +type Alias = int | str +type Alias1[T1] = list[T1] | set[T1] +type Alias2[T2: int] = list[T2] | set[T2] +type Alias3[T3: str | bytes] = list[T3] | set[T3] +type Alias4[T4: (str, bytes)] = list[T4] | set[T4] +class C: + type IndentedAlias[T] = list[T] + +[case testPEP695Syntax_semanal] +# flags: --python-version=3.12 + +class C[T]: ... +def f[S](): ... +type A[R] = list[R] + +[out] +class C[T]: ... + +def f[S]() -> None: ... +type A[R] = list[R] + +[case testPEP696Syntax] +# flags: --python-version=3.13 + +type Alias1[T1 = int] = list[T1] | set[T1] +type Alias2[T2: int | float = int] = list[T2] | set[T2] +class C3[T3 = int]: ... +class C4[T4: int | float = int](list[T4]): ... +def f5[T5 = int](): ... + +[out] +type Alias1[T1 = int] = list[T1] | set[T1] +type Alias2[T2: int | float = int] = list[T2] | set[T2] +class C3[T3 = int]: ... +class C4[T4: int | float = int](list[T4]): ... + +def f5[T5 = int]() -> None: ... + +[case testIgnoreMypyGeneratedMethods_semanal] +# flags: --include-private --python-version=3.13 +from typing_extensions import dataclass_transform + +# TODO: preserve dataclass_transform decorator +@dataclass_transform() +class DCMeta(type): ... +class DC(metaclass=DCMeta): + x: str + +[out] +class DCMeta(type): ... + +class DC(metaclass=DCMeta): + x: str + def __init__(self, x) -> None: ... + def __replace__(self, *, x) -> None: ... diff --git a/test-requirements.in b/test-requirements.in index 5a888811bfcd..4e53c63cc36b 100644 --- a/test-requirements.in +++ b/test-requirements.in @@ -4,7 +4,6 @@ -r mypy-requirements.txt -r build-requirements.txt attrs>=18.0 -black==24.3.0 # must match version in .pre-commit-config.yaml filelock>=3.3.0 # lxml 4.9.3 switched to manylinux_2_28, the wheel builder still uses manylinux2014 lxml>=4.9.1,<4.9.3; (python_version<'3.11' or sys_platform!='win32') and python_version<'3.12' @@ -12,6 +11,6 @@ psutil>=4.0 pytest>=8.1.0 pytest-xdist>=1.34.0 pytest-cov>=2.10.0 -ruff==0.2.0 # must match version in .pre-commit-config.yaml -setuptools>=65.5.1 +setuptools>=75.1.0 tomli>=1.1.0 # needed even on py311+ so the self check passes with --python-version 3.8 +pre_commit>=3.5.0 diff --git a/test-requirements.txt b/test-requirements.txt index f4fb4a20cce7..6eb6f6a95ac8 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -4,58 +4,62 @@ # # pip-compile --allow-unsafe --output-file=test-requirements.txt --strip-extras test-requirements.in # -attrs==23.1.0 +attrs==24.2.0 # via -r test-requirements.in -black==24.3.0 - # via -r test-requirements.in -click==8.1.7 - # via black -coverage==7.3.2 +cfgv==3.4.0 + # via pre-commit +coverage==7.6.1 # via pytest-cov -execnet==2.0.2 +distlib==0.3.9 + # via virtualenv +execnet==2.1.1 # via pytest-xdist -filelock==3.12.4 - # via -r test-requirements.in +filelock==3.16.1 + # via + # -r test-requirements.in + # virtualenv +identify==2.6.1 + # via pre-commit iniconfig==2.0.0 # via pytest lxml==4.9.2 ; (python_version < "3.11" or sys_platform != "win32") and python_version < "3.12" # via -r test-requirements.in mypy-extensions==1.0.0 - # via - # -r mypy-requirements.txt - # black -packaging==23.2 - # via - # black - # pytest -pathspec==0.11.2 - # via black -platformdirs==3.11.0 - # via black -pluggy==1.4.0 + # via -r mypy-requirements.txt +nodeenv==1.9.1 + # via pre-commit +packaging==24.1 + # via pytest +platformdirs==4.3.6 + # via virtualenv +pluggy==1.5.0 # via pytest -psutil==5.9.6 +pre-commit==3.5.0 # via -r test-requirements.in -pytest==8.1.1 +psutil==6.0.0 + # via -r test-requirements.in +pytest==8.3.3 # via # -r test-requirements.in # pytest-cov # pytest-xdist -pytest-cov==4.1.0 - # via -r test-requirements.in -pytest-xdist==3.3.1 +pytest-cov==5.0.0 # via -r test-requirements.in -ruff==0.2.0 +pytest-xdist==3.6.1 # via -r test-requirements.in -tomli==2.0.1 +pyyaml==6.0.2 + # via pre-commit +tomli==2.0.2 # via -r test-requirements.in -types-psutil==5.9.5.17 +types-psutil==6.0.0.20241011 # via -r build-requirements.txt -types-setuptools==68.2.0.0 +types-setuptools==75.1.0.20241014 # via -r build-requirements.txt typing-extensions==4.12.2 # via -r mypy-requirements.txt +virtualenv==20.26.6 + # via pre-commit # The following packages are considered to be unsafe in a requirements file: -setuptools==70.0.0 +setuptools==75.1.0 # via -r test-requirements.in diff --git a/tox.ini b/tox.ini index c2abd05d7b6c..a505950521fa 100644 --- a/tox.ini +++ b/tox.ini @@ -7,6 +7,7 @@ envlist = py310, py311, py312, + py313, docs, lint, type, @@ -19,15 +20,18 @@ passenv = PROGRAMDATA PROGRAMFILES(X86) PYTEST_ADDOPTS -deps = -rtest-requirements.txt +deps = + -r test-requirements.txt + # This is a bit of a hack, but ensures the faster-cache path is tested in CI + orjson;python_version=='3.12' commands = python -m pytest {posargs} [testenv:dev] description = generate a DEV environment, that has all project libraries usedevelop = True deps = - -rtest-requirements.txt - -rdocs/requirements-docs.txt + -r test-requirements.txt + -r docs/requirements-docs.txt commands = python -m pip list --format=columns python -c 'import sys; print(sys.executable)' @@ -37,7 +41,7 @@ commands = description = invoke sphinx-build to build the HTML docs passenv = VERIFY_MYPY_ERROR_CODES -deps = -rdocs/requirements-docs.txt +deps = -r docs/requirements-docs.txt commands = sphinx-build -n -d "{toxworkdir}/docs_doctree" docs/source "{toxworkdir}/docs_out" --color -W -bhtml {posargs} python -c 'import pathlib; print("documentation available under file://\{0\}".format(pathlib.Path(r"{toxworkdir}") / "docs_out" / "index.html"))'